--- app/globals.scss
+++ app/globals.scss
... | ... | @@ -14,7 +14,8 @@ |
| 14 | 14 |
// 앱은 정확히 그 이름의 폰트를 공급해야 한다. `next/font/local`은 패밀리명을 |
| 15 | 15 |
// 해시(`__Pretendard_xxxx`)로 바꿔 그 리터럴과 영영 만나지 못해 쓸 수 없다 — 토큰은 Figma |
| 16 | 16 |
// export 자동 생성이라 이름을 코드 쪽에 맞추는 반대 방향도 불가능하다. |
| 17 |
-// weight는 토큰이 실제로 쓰는 400·600·800 셋뿐이다(`weight-regular`/`medium`/`bold`). |
|
| 17 |
+// weight는 토큰이 쓰는 400·600·800에 더해, 어떤 CSS도 굵기를 지정하지 않는 자리(제목·`th`· |
|
| 18 |
+// `strong` 등 UA 기본값)가 쓰는 700을 포함한다 — 없으면 700이 800으로 올라가 굵어진다. |
|
| 18 | 19 |
@font-face {
|
| 19 | 20 |
font-family: "Pretendard"; |
| 20 | 21 |
font-style: normal; |
... | ... | @@ -34,9 +35,24 @@ |
| 34 | 35 |
@font-face {
|
| 35 | 36 |
font-family: "Pretendard"; |
| 36 | 37 |
font-style: normal; |
| 38 |
+ font-weight: 700; |
|
| 39 |
+ font-display: swap; |
|
| 40 |
+ src: url("/fonts/pretendard-bold.woff2") format("woff2");
|
|
| 41 |
+} |
|
| 42 |
+ |
|
| 43 |
+@font-face {
|
|
| 44 |
+ font-family: "Pretendard"; |
|
| 45 |
+ font-style: normal; |
|
| 37 | 46 |
font-weight: 800; |
| 38 | 47 |
font-display: swap; |
| 39 | 48 |
src: url("/fonts/pretendard-extrabold.woff2") format("woff2");
|
| 49 |
+} |
|
| 50 |
+ |
|
| 51 |
+// 앱 기본 서체 — @fox README가 정의한 호스트 앱 계약(`--app-font-sans`)의 실제 주입 지점이다. |
|
| 52 |
+// 폰트 파일을 next/font가 아니라 위 `@font-face`가 공급하므로 변수도 여기서 정의한다. |
|
| 53 |
+// 이 값과 @fox 토큰(`font.family.*`)이 지금은 둘 다 Pretendard라 화면 전체가 한 서체다. |
|
| 54 |
+:root {
|
|
| 55 |
+ --app-font-sans: "Pretendard"; |
|
| 40 | 56 |
} |
| 41 | 57 |
|
| 42 | 58 |
// 앱 셸 — 루트 레이아웃이 뷰포트 높이를 채우고 세로로 쌓이는 구조. |
... | ... | @@ -51,9 +67,8 @@ |
| 51 | 67 |
flex-direction: column; |
| 52 | 68 |
min-block-size: 100%; |
| 53 | 69 |
|
| 54 |
- // @fox 밖 텍스트의 서체. 디자인 값이 아니라 layout.tsx가 주입하는 계약 변수를 꽂는 |
|
| 55 |
- // 지점이라 여기 둔다 — 이 한 줄이 없으면 `--app-font-sans`를 읽는 곳이 없어 wantedSans가 |
|
| 56 |
- // 로드만 되고 아무 데도 적용되지 않는다. @fox 컴포넌트는 각자 토큰으로 Pretendard를 |
|
| 57 |
- // 덮어쓰므로 영향을 받지 않는다. |
|
| 70 |
+ // @fox 밖 텍스트의 서체. 계약 변수를 거쳐 꽂으므로 서체를 갈 때는 위 `--app-font-sans` |
|
| 71 |
+ // 한 줄만 고치면 된다. @fox 컴포넌트는 이 값이 아니라 토큰(`Pretendard` 리터럴)을 쓰지만, |
|
| 72 |
+ // 지금은 둘이 같은 서체를 가리킨다. |
|
| 58 | 73 |
font-family: var(--app-font-sans, system-ui), system-ui, sans-serif; |
| 59 | 74 |
} |
--- app/layout.tsx
+++ app/layout.tsx
... | ... | @@ -1,6 +1,5 @@ |
| 1 | 1 |
import type { Metadata } from "next";
|
| 2 | 2 |
import { Geist_Mono } from "next/font/google";
|
| 3 |
-import localFont from "next/font/local"; |
|
| 4 | 3 |
import { FeedbackHost } from "@/app/_components/feedback-host";
|
| 5 | 4 |
import { FeedbackProvider } from "@/app/_components/feedback-provider";
|
| 6 | 5 |
import {
|
... | ... | @@ -25,38 +24,12 @@ |
| 25 | 24 |
THEME_ATTRIBUTE_NAME |
| 26 | 25 |
)},t)}catch(e){}})()`;
|
| 27 | 26 |
|
| 28 |
-// `@fox` **밖** 앱 텍스트의 기본 서체. 폰트 파일은 앱이 소유하고 `--app-font-sans` 계약으로 |
|
| 29 |
-// 넘긴다(@fox/README.md "호스트 앱과의 계약") — 그 변수를 실제로 꽂는 곳은 globals.scss의 |
|
| 30 |
-// `body`다. @fox 컴포넌트는 이 값을 쓰지 않는다: 토큰이 패밀리명을 `Pretendard`로 직접 |
|
| 31 |
-// 지정하고 그 @font-face도 globals.scss에 있다. 즉 한 화면에 두 서체가 공존한다. |
|
| 32 |
-const wantedSans = localFont({
|
|
| 33 |
- src: [ |
|
| 34 |
- {
|
|
| 35 |
- path: "../public/fonts/wanted-sans-regular.ttf", |
|
| 36 |
- weight: "400", |
|
| 37 |
- style: "normal", |
|
| 38 |
- }, |
|
| 39 |
- {
|
|
| 40 |
- path: "../public/fonts/wanted-sans-medium.ttf", |
|
| 41 |
- weight: "500", |
|
| 42 |
- style: "normal", |
|
| 43 |
- }, |
|
| 44 |
- {
|
|
| 45 |
- path: "../public/fonts/wanted-sans-semibold.ttf", |
|
| 46 |
- weight: "600", |
|
| 47 |
- style: "normal", |
|
| 48 |
- }, |
|
| 49 |
- {
|
|
| 50 |
- path: "../public/fonts/wanted-sans-bold.ttf", |
|
| 51 |
- weight: "700", |
|
| 52 |
- style: "normal", |
|
| 53 |
- }, |
|
| 54 |
- ], |
|
| 55 |
- variable: "--app-font-sans", |
|
| 56 |
- display: "swap", |
|
| 57 |
-}); |
|
| 27 |
+// 앱 기본 서체는 여기서 선언하지 않는다 — @fox 토큰이 패밀리명을 리터럴 `Pretendard`로 못 |
|
| 28 |
+// 박고 있어 `next/font`(패밀리명을 해시로 바꾼다)를 쓸 수 없고, globals.scss의 `@font-face`가 |
|
| 29 |
+// 그 이름 그대로 공급한다. 앱과 @fox가 같은 서체를 쓰므로 앱 몫을 따로 둘 이유도 없다. |
|
| 30 |
+// `--app-font-sans` 계약(@fox/README.md "호스트 앱과의 계약")도 그 옆에서 함께 정의한다. |
|
| 58 | 31 |
|
| 59 |
-// 코드/숫자 표기용 고정폭 서체 — sans와 동일하게 `--app-font-mono` 계약으로 주입한다. |
|
| 32 |
+// 코드/숫자 표기용 고정폭 서체 — `--app-font-mono` 계약으로 주입한다. |
|
| 60 | 33 |
const geistMono = Geist_Mono({
|
| 61 | 34 |
variable: "--app-font-mono", |
| 62 | 35 |
subsets: ["latin"], |
... | ... | @@ -91,14 +64,13 @@ |
| 91 | 64 |
<html |
| 92 | 65 |
lang="ko" |
| 93 | 66 |
suppressHydrationWarning |
| 94 |
- className={`${wantedSans.variable} ${geistMono.variable}`}
|
|
| 67 |
+ className={geistMono.variable}
|
|
| 95 | 68 |
> |
| 96 | 69 |
<head> |
| 97 | 70 |
<script dangerouslySetInnerHTML={{ __html: THEME_BOOTSTRAP_SCRIPT }} />
|
| 98 | 71 |
{/* @font-face는 CSS를 다 읽은 뒤에야 발견돼 본문이 한 번 폴백 서체로 그려진다.
|
| 99 |
- 거의 모든 화면이 쓰는 regular만 미리 받아 그 깜빡임을 없앤다 — 600/800은 |
|
| 100 |
- 빈도가 낮아 선점 비용이 이득보다 크다. next/font로 넣은 wantedSans는 Next.js가 |
|
| 101 |
- 알아서 preload하므로 여기 없다. */} |
|
| 72 |
+ 거의 모든 화면이 쓰는 regular만 미리 받아 그 깜빡임을 없앤다 — 나머지 굵기는 |
|
| 73 |
+ 빈도가 낮아 선점 비용이 이득보다 크다. */} |
|
| 102 | 74 |
<link |
| 103 | 75 |
rel="preload" |
| 104 | 76 |
as="font" |
+++ public/fonts/pretendard-bold.woff2
| Binary file is not shown |
--- public/fonts/wanted-sans-bold.ttf
| Binary file is not shown |
--- public/fonts/wanted-sans-medium.ttf
| Binary file is not shown |
--- public/fonts/wanted-sans-regular.ttf
| Binary file is not shown |
--- public/fonts/wanted-sans-semibold.ttf
| Binary file is not shown |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?