Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 19 additions & 17 deletions apps/blog/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
import { PropsWithChildren } from 'react';
import './global.css';
// import { Noto_Sans_KR } from 'next/font/google';
import { Noto_Sans_KR } from 'next/font/google';
import { Analytics } from '@vercel/analytics/react';
import { SpeedInsights } from '@vercel/speed-insights/next';
import { Constants } from '@libs/constants';

// Noto Sans KR을 서브셋으로 최적화
// - 한글 기본 2,350자만 포함 (전체 11,172자 대신)
// - 폰트 크기: 76KB → ~20KB로 감소
// - swap: 폰트 로딩 중에도 텍스트 표시
// const font = Noto_Sans_KR({
// weight: ['400', '700'], // 필요한 weight만 로드
// subsets: ['latin'],
// display: 'swap', // 폰트 로딩 중에도 텍스트 즉시 표시
// variable: '--font-noto-sans-kr',
// preload: true,
// fallback: ['system-ui', '-apple-system', 'sans-serif'],
// adjustFontFallback: true, // CLS 방지
// });
// OS별 한글 렌더링 편차를 없애기 위해 활성화(#95). next/font는 빌드타임에 셀프호스트하므로
// 런타임에 fonts.googleapis.com으로 나가는 요청(preconnect 포함)이 필요 없다.
// subsets는 프리로드 대상(latin woff2)만 지정한다 — next/font의 Noto_Sans_KR에는 'korean'
// 서브셋이 없어, 한글 글리프는 unicode-range 슬라이스(다수의 woff2)로 필요한 만큼 온디맨드
// 로드된다. 따라서 첫 방문 시 한글은 폴백→스왑(FOUT)이 발생하며, 아래 display/adjustFontFallback
// 조합으로 로딩 중 표시와 스왑 시 CLS를 완화한다.
const font = Noto_Sans_KR({
// 실사용 weight만 로드: 400(본문)·500(font-medium 강조)·700(헤딩/볼드).
// 600은 th(post-detail.module.scss) 한 곳뿐이라 로드하지 않고 700 상향 매칭을 감수한다.
weight: ['400', '500', '700'],
subsets: ['latin'],
display: 'swap', // 폰트 로딩 중에도 텍스트 즉시 표시
preload: true,
fallback: ['system-ui', '-apple-system', 'sans-serif'],
adjustFontFallback: true, // CLS 방지
});

const { siteConfig, openGraph } = Constants;

Expand Down Expand Up @@ -86,15 +89,14 @@ export default async function RootLayout({ children }: PropsWithChildren) {
}}
/>
<link rel="icon" type="image/x-icon" href="/favicon.ico"></link>
{/* <link rel="preconnect" href="https://fonts.googleapis.com" /> */}
{/* <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" /> */}
<meta
name="google-site-verification"
content="mOdpcnnT3rL3phLYQpSNvzcOOGfKppuH-2mgeOs7VIc"
/>
</head>

<body>
{/* font.className이 셀프호스트된 Noto Sans KR과 조정된 폴백(fallback)을 body 전체에 적용한다. */}
<body className={font.className}>
{children}

<SpeedInsights />
Expand Down
57 changes: 31 additions & 26 deletions apps/blog/src/components/post-detail/post-detail.module.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
.postDetail {
// === 타입 스케일 토큰 (#95) ===
// 흩어진 px 하드코딩을 토큰으로 모아 h1 > h2 > h3 > 본문 위계가 항상 유지되게 한다.
// 모바일 값은 하단 미디어쿼리에서 같은 토큰만 덮어쓴다.
--post-h1-size: 32px;
--post-h2-size: 24px;
--post-h3-size: 20px; // 본문(16px)과 같아 위계가 없던 16px에서 한 단계 상향
--post-body-size: 16px;

h1,
h2,
h3 {
Expand All @@ -7,27 +15,33 @@
}

h1 {
font-size: 32px;
font-size: var(--post-h1-size);
}

h2 {
font-size: 24px;
font-size: var(--post-h2-size);
}

h3 {
font-size: 16px;
font-size: var(--post-h3-size);
}

p {
padding-top: 16px;
padding-bottom: 24px;
line-height: 28px;
// 한글 본문 가독성을 위해 28px(비율 1.75)에서 1.8로 상향(#95).
// unitless 비율이라 모바일 본문 14px에서도 같은 비율(약 25.2px)로 스케일되어
// #118에서 복원한 모바일 줄간격(25px, 약 1.79)의 의도를 그대로 계승한다.
line-height: 1.8;
font-size: var(--post-body-size);
word-break: keep-all;
}

ul,
ol {
padding: 5px 0;
// 본문 크기의 단일 출처를 위해 리스트도 토큰을 참조한다(기본값 16px과 동일해 시각 변화 없음).
font-size: var(--post-body-size);
}

li {
Expand Down Expand Up @@ -97,6 +111,8 @@
width: 100%;
margin: 16px 0;
border-collapse: collapse;
// 표 본문도 본문 크기 토큰을 따른다(기본값 16px과 동일해 시각 변화 없음).
font-size: var(--post-body-size);
}

th,
Expand All @@ -112,39 +128,31 @@
}

@media only screen and (max-width: 800px) {
// 모바일 타입 스케일(#95): 기존 h2 16px·h3 14px가 본문 14px과 겹쳐 위계가 사라졌던 것을,
// 본문 14px 기준으로 h3까지 최소 한 단계(2px 이상) 차이가 유지되도록 토큰만 덮어쓴다.
--post-h1-size: 24px;
--post-h2-size: 20px;
--post-h3-size: 16px;
--post-body-size: 14px;

h1,
h2,
h3 {
font-weight: 700;
padding: 10px 0;
}

h1 {
font-size: 24px;
}

h2 {
font-size: 16px;
}

h3 {
font-size: 14px;
}

p {
padding-top: 8px;
padding-bottom: 12px;
// 본문 14px 기준 가독 line-height. 폰트가 12→14px로 커졌는데 22px에 머물러
// 줄간격 비율이 1.57로 좁아졌던 것을, 데스크톱 비율(28px/16px≈1.75)에 근접하게 복원한다(25/14≈1.79).
line-height: 25px;
font-size: 14px; // 모바일 가독성을 위해 12px에서 14px로 상향
word-break: keep-all;
// 폰트 크기는 --post-body-size(14px) 토큰이, 줄간격은 상단의 unitless 1.8이 담당한다.
// (#118에서 복원한 25px≈1.79 비율은 1.8 비율 상속으로 그대로 유지된다)
}

ul,
ol {
padding: 0;
font-size: 14px; // 본문 폰트와 통일해 12px에서 14px로 상향
// font-size는 기본 스코프의 토큰 선언이 모바일 토큰 값(14px)으로 재해석되므로 중복 선언하지 않는다.
}

li {
Expand Down Expand Up @@ -191,10 +199,7 @@
}
}

table {
font-size: 14px; // 본문 폰트와 통일해 12px에서 14px로 상향
}

// table의 font-size는 기본 스코프의 토큰 선언이 모바일 토큰 값(14px)으로 재해석되므로 중복 선언하지 않는다.
th,
td {
padding: 6px 8px;
Expand Down
1 change: 0 additions & 1 deletion apps/blog/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export default {
extend: {
fontFamily: {
sans: ['system-ui', 'sans-serif'],
// sans: ['var(--font-noto-sans-kr)', 'system-ui', 'sans-serif'],
},
},
},
Expand Down
Loading