Open5

next/font/googleからエイリアスを作ろうとして挫折した話

Yamamoto Yuji / はまあYamamoto Yuji / はまあ

やりたきこと

FigmaからOutline Text: OffでSVGとしてExportしてきた(プラグインではなく標準のExport)ファイルを加工せずにNextJS v14+App Router環境下で使いたい。

SVGからExportしてきたファイルにtextタグの属性としてフォント名(font-family)が書いてある。
で、NextJSの標準的な外部フォント使用方法はnext/fontであり、Zen Kaku Gothic NewとRadleyを使ってるので、これをSVG側でも使ってくれたらハッピーである。

Yamamoto Yuji / はまあYamamoto Yuji / はまあ

問題

じゃあそれをどのように解決するかというと、next/font/googleにはvariable属性を指定することでCSS変数としてexportしてくれる仕組みがある

// layout.tsx
export const ZenKakuGothicNew = Zen_Kaku_Gothic_New({
  weight: ["400", "500"],
  subsets: ["latin"],
  display: "swap",
  preload: true,
  variable: "--font-zen-kaku-gothic-new"
});

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html>
      <body className={`${ZenKakuGothicNew.variable}`}>{children}</body>
    </html>
  );
}

// styles.css
@font-face {
  font-family: "Zen Kaku Gothic New";
  src: local(var(--font-zen-kaku-gothic-new));
}
Yamamoto Yuji / はまあYamamoto Yuji / はまあ

解決策1

じゃあどうすんべとして考えたのが以下。

next/font/googleにはvariable属性を指定することでCSS変数としてexportしてくれる仕組みがあるのでそれを使って"Zen Kaku Gothic New"というfont-family名をエイリアスとしてnext/font/googleに中継してやればいいじゃんという

// layout.tsx
import { Zen_Kaku_Gothic_New } from "next/font/google";

export const ZenKakuGothicNew = Zen_Kaku_Gothic_New({
  weight: ["400", "500"],
  subsets: ["latin"],
  display: "swap",
  preload: true,
  variable: "--font-zen-kaku-gothic-new"
});

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html>
      <body className={`${ZenKakuGothicNew.variable}`}>{children}</body>
    </html>
  );
}

使うところで以下を読み込めば"Zen Kaku Gothic New"というfont-family名のエイリアスとして使えるはずである。

// styles.css
@font-face {
  font-family: "Zen Kaku Gothic New";
  src: local(var(--font-zen-kaku-gothic-new));
}

結果

うまくいかない。fallbackフォントが適用されている。

検証

Chromeツールで"Zen Kaku Gothic New"がfont-familyが割当されているのか確認

→ されている

試しにSVG側にNextJSで生成されたfont-familyを指定

→ 表示される

styles.cssのsrcに: local("YuMincho")を指定してみる

→ 適用されない

Yamamoto Yuji / はまあYamamoto Yuji / はまあ

解決策2

next/font/localのlocalFontを使ってやってみる

// layout.tsx
import { localFont } from "next/font/local";

export const ZenKakuGothicNew = localFont({
  src: "../assets/fonts/ZenKakuGothicNew-Medium.ttf",
  weight: ["400", "500"],
  display: "swap",
  preload: true,
  variable: "--font-zen-kaku-gothic-new"
});

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html>
      <body className={`${ZenKakuGothicNew.variable}`}>{children}</body>
    </html>
  );
}

結果

解決策1と同じ

Yamamoto Yuji / はまあYamamoto Yuji / はまあ

解決策3

next/fontを使わずに/public/にフォントファイルを置いてCSSでアクセス

// globals.css
@font-face {
  font-family: "Zen Kaku Gothic New";
  src: url(/assets/fonts/ZenKakuGothicNew-Medium.ttf);
}

結果

うまくいった
が、これだとnextのフォント最適化を捨て去る事になる...