From ab819ab5b18febac9603b4cd7b8c6fc7037e5072 Mon Sep 17 00:00:00 2001 From: malloc72p Date: Fri, 10 Jul 2026 09:27:10 +0900 Subject: [PATCH 1/2] =?UTF-8?q?fix(blog):=20=ED=8F=AC=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=ED=83=80=EC=9E=85=20=EC=8A=A4=EC=BC=80=EC=9D=BC=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=ED=99=94=C2=B7=EB=AA=A8=EB=B0=94=EC=9D=BC=20=ED=97=A4?= =?UTF-8?q?=EB=94=A9=20=EC=9C=84=EA=B3=84=20=EB=B3=B5=EC=9B=90=C2=B7Noto?= =?UTF-8?q?=20Sans=20KR=20=ED=99=9C=EC=84=B1=ED=99=94=20(#95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 헤딩/본문 px 하드코딩을 --post-*-size 토큰으로 모으고, 모바일에서 h1 24/h2 20/h3 16px로 본문 14px과 최소 한 단계 차이 확보 - 본문 line-height를 unitless 1.8로 상향 — 모바일에서도 #118의 25px(1.79) 복원 의도를 비율로 계승 - layout.tsx의 Noto_Sans_KR(next/font/google) 설정을 활성화해 body에 적용, 셀프호스트라 불필요한 preconnect 주석 제거 --- apps/blog/src/app/layout.tsx | 27 +++++----- .../post-detail/post-detail.module.scss | 50 ++++++++++--------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/apps/blog/src/app/layout.tsx b/apps/blog/src/app/layout.tsx index 01ec5a8..88e370d 100644 --- a/apps/blog/src/app/layout.tsx +++ b/apps/blog/src/app/layout.tsx @@ -1,6 +1,6 @@ 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'; @@ -9,15 +9,17 @@ import { Constants } from '@libs/constants'; // - 한글 기본 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 포함)이 필요 없다. +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 방지 +}); const { siteConfig, openGraph } = Constants; @@ -86,15 +88,14 @@ export default async function RootLayout({ children }: PropsWithChildren) { }} /> - {/* */} - {/* */} - + {/* font.className이 셀프호스트된 Noto Sans KR과 조정된 폴백(fallback)을 body 전체에 적용한다. */} + {children} diff --git a/apps/blog/src/components/post-detail/post-detail.module.scss b/apps/blog/src/components/post-detail/post-detail.module.scss index dce9bd1..ec44a74 100644 --- a/apps/blog/src/components/post-detail/post-detail.module.scss +++ b/apps/blog/src/components/post-detail/post-detail.module.scss @@ -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 { @@ -7,21 +15,25 @@ } 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; } @@ -112,6 +124,13 @@ } @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 { @@ -119,32 +138,17 @@ 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: var(--post-body-size); // 본문 폰트와 통일 (12px→14px 상향 이력, #95에서 토큰화) } li { @@ -192,7 +196,7 @@ } table { - font-size: 14px; // 본문 폰트와 통일해 12px에서 14px로 상향 + font-size: var(--post-body-size); // 본문 폰트와 통일 (12px→14px 상향 이력, #95에서 토큰화) } th, From e6f2d1bed9f16beb66cda1842100a295d3e5b28c Mon Sep 17 00:00:00 2001 From: malloc72p Date: Fri, 10 Jul 2026 09:38:34 +0900 Subject: [PATCH 2/2] =?UTF-8?q?fix(blog):=20=EB=A6=AC=EB=B7=B0=20=EB=B0=98?= =?UTF-8?q?=EC=98=81=20=E2=80=94=20=ED=8F=B0=ED=8A=B8=20weight=20500=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=C2=B7=EC=A3=BD=EC=9D=80=20variable=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=C2=B7=EB=B3=B8=EB=AC=B8=20=ED=86=A0=ED=81=B0?= =?UTF-8?q?=ED=99=94=20=EC=99=84=EC=84=B1=20(#95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - weight에 500 추가: font-medium 7곳이 400으로 붕괴되던 회귀 수정(600은 th 한 곳뿐이라 700 상향 매칭 감수를 주석으로 명시) - 미사용 variable 옵션과 tailwind.config.js의 주석 잔재 제거 — className 단일 방식으로 정리 - 폰트 주석을 실제 동작(subsets=preload 대상, 한글은 unicode-range 온디맨드)으로 교체하고, 기본 스코프 ul/ol/table에도 --post-body-size 토큰 적용해 단일 출처 완성 --- apps/blog/src/app/layout.tsx | 13 +++++++------ .../components/post-detail/post-detail.module.scss | 11 ++++++----- apps/blog/tailwind.config.js | 1 - 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/apps/blog/src/app/layout.tsx b/apps/blog/src/app/layout.tsx index 88e370d..6b3e593 100644 --- a/apps/blog/src/app/layout.tsx +++ b/apps/blog/src/app/layout.tsx @@ -5,17 +5,18 @@ 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: 폰트 로딩 중에도 텍스트 표시 // 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', '700'], // 필요한 weight만 로드 + // 실사용 weight만 로드: 400(본문)·500(font-medium 강조)·700(헤딩/볼드). + // 600은 th(post-detail.module.scss) 한 곳뿐이라 로드하지 않고 700 상향 매칭을 감수한다. + weight: ['400', '500', '700'], subsets: ['latin'], display: 'swap', // 폰트 로딩 중에도 텍스트 즉시 표시 - variable: '--font-noto-sans-kr', preload: true, fallback: ['system-ui', '-apple-system', 'sans-serif'], adjustFontFallback: true, // CLS 방지 diff --git a/apps/blog/src/components/post-detail/post-detail.module.scss b/apps/blog/src/components/post-detail/post-detail.module.scss index ec44a74..ec14408 100644 --- a/apps/blog/src/components/post-detail/post-detail.module.scss +++ b/apps/blog/src/components/post-detail/post-detail.module.scss @@ -40,6 +40,8 @@ ul, ol { padding: 5px 0; + // 본문 크기의 단일 출처를 위해 리스트도 토큰을 참조한다(기본값 16px과 동일해 시각 변화 없음). + font-size: var(--post-body-size); } li { @@ -109,6 +111,8 @@ width: 100%; margin: 16px 0; border-collapse: collapse; + // 표 본문도 본문 크기 토큰을 따른다(기본값 16px과 동일해 시각 변화 없음). + font-size: var(--post-body-size); } th, @@ -148,7 +152,7 @@ ul, ol { padding: 0; - font-size: var(--post-body-size); // 본문 폰트와 통일 (12px→14px 상향 이력, #95에서 토큰화) + // font-size는 기본 스코프의 토큰 선언이 모바일 토큰 값(14px)으로 재해석되므로 중복 선언하지 않는다. } li { @@ -195,10 +199,7 @@ } } - table { - font-size: var(--post-body-size); // 본문 폰트와 통일 (12px→14px 상향 이력, #95에서 토큰화) - } - + // table의 font-size는 기본 스코프의 토큰 선언이 모바일 토큰 값(14px)으로 재해석되므로 중복 선언하지 않는다. th, td { padding: 6px 8px; diff --git a/apps/blog/tailwind.config.js b/apps/blog/tailwind.config.js index a54b123..710706c 100644 --- a/apps/blog/tailwind.config.js +++ b/apps/blog/tailwind.config.js @@ -10,7 +10,6 @@ export default { extend: { fontFamily: { sans: ['system-ui', 'sans-serif'], - // sans: ['var(--font-noto-sans-kr)', 'system-ui', 'sans-serif'], }, }, },