Skip to content
Open
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
2 changes: 1 addition & 1 deletion app/routes/_marketing+/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export default function Index() {
</a>
<h1
data-heading
className="animate-slide-top text-foreground xl:animate-slide-left mt-8 text-4xl font-medium [animation-delay:0.3s] [animation-fill-mode:backwards] md:text-5xl xl:mt-4 xl:text-6xl xl:[animation-delay:0.8s] xl:[animation-fill-mode:backwards]"
className="animate-slide-top text-foreground xl:animate-slide-left font-title mt-8 text-4xl font-medium [animation-delay:0.3s] [animation-fill-mode:backwards] md:text-5xl xl:mt-4 xl:text-6xl xl:[animation-delay:0.8s] xl:[animation-fill-mode:backwards]"
>
<a href="https://www.epicweb.dev/stack">The Epic Stack</a>
</h1>
Expand Down
4 changes: 4 additions & 0 deletions app/styles/tailwind.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

@custom-variant dark (&:is(.dark *));

.font-title {
font-family: 'Poppins', sans-serif;
}

:root {
--radius: 0.5rem;

Expand Down
160 changes: 25 additions & 135 deletions docs/fonts.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,147 +6,37 @@ easy to do so.

## Using Custom Fonts

You can use custom fonts by creating the `./public/fonts` directory (if it
doesn't already exist) and adding them to it.
[Google Fonts](https://fonts.google.com/) is a good place to find open source
fonts. You will also need to add the `css` file for the font to the
`./app/styles` directory, if your font doesn't come with one (Google Fonts
don't) you can generate one using a tool like
[Transfonter](https://transfonter.org/). Transfonter now has a fonts directory
setting. Set that to `fonts` to have the `url` preset.
For custom fonts, Epic Stack uses
[`fontless`](https://github.com/unjs/fontaine/tree/main/packages/fontless) for
automatic font optimization. This provides zero-runtime font loading with proper
fallbacks to reduce Cumulative Layout Shift (CLS).

Verify the `url` in the `css` is relative to the `public` folder. So it should
look something like `url('/fonts/yourfont/yourfont-200.woff2')`.
## How it works

Now you've added your font, there's a few places you need to update to use it.
Simply use font families in your CSS and `fontless` handles the rest:

1. Add your font to the CSS variables.
```css
.font-title {
font-family: 'Poppins', sans-serif;
}

```css
/* tailwind.css */
@layer base {
:root {
--font-sans: <YourFont>;
}
}
```
.body-text {
font-family: 'Inter', sans-serif;
}
```

2. Import the default theme and add your font to the `fontFamily` property.
The plugin will:

```ts
import defaultTheme from 'tailwindcss/defaultTheme.js'
// tailwind.config.ts
extend: {
...extendedTheme,
fontFamily: {
sans: ['var(--font-sans)', ...defaultTheme.fontFamily.sans],
}
}
- Detect font-family declarations in your CSS
- Resolve fonts from providers (Google Fonts, Bunny Fonts, etc.)
- Generate optimized `@font-face` declarations
- Add metric-based fallback fonts to reduce CLS
- Download and serve font assets from `/_fonts/`

```
## Troubleshooting

3. Import your font stylesheet.
### Fonts not loading in development

```tsx
// app/routes/root.tsx
import fontStyleSheetUrl from './styles/yourfont.css?url'
```

Add the font stylesheet to the links array.

```tsx
// app/routes/root.tsx
...
{ rel: 'preload', href: fontStyleSheetUrl, as: 'style' },
{ rel: 'stylesheet', href: fontStyleSheetUrl },
```

4. Expose and cache your fonts folder.

```ts
// server/index.ts
...
app.use(
'/fonts',
// Can aggressively cache fonts as they don't change often
express.static('public/fonts', { immutable: true, maxAge: '1y' }),
)
```

That's it! You can now use your custom font should now be available to use in
your site.

## Font Metric Overrides

When using custom fonts, your site elements may stretch or shrink to accommodate
the font. This is because the browser doesn't know the dimensions of the font
you're using until it arrives, which introduces Cumulative Layout Shift and
impact its web vitals.

In Epic Stack, we fixed this by introducing
[Font Metric Overrides](https://github.com/epicweb-dev/epic-stack/pull/128/files).

Follow the steps below to add Font Metric Overrides to your custom fonts.

1. Generate the overrides for your font.

You can use [fontpie](https://www.npmjs.com/package/fontpie) utility to
generate the overrides. For each of your fonts, write the following in your
terminal:

```bash
npx fontpie ./local/font/location.woff2 -w font-weight -s normal/italic -n YourFont
```

#### Example

```sh
npx fontpie ./public/fonts/nunito-sans/nunito-sans-v12-latin_latin-ext-200.woff2 -w 200 -s normal -n NunitoSans
```

```css
@font-face {
font-family: 'NunitoSans Fallback';
font-style: normal;
font-weight: 200;
src: local('Arial');
ascent-override: 103.02%;
descent-override: 35.97%;
line-gap-override: 0%;
size-adjust: 98.13%;
}
```

If you've got a lot of font files to override, you can use
[fontpie-from-css](https://github.com/matt-kinton/fontpie-from-css) to
generate the overrides from a CSS file.

```sh
npx fontpie-from-css ./public/fonts/yourfont/yourfont.css
```

**_Note:_** _If you've been following the steps above, you might have to copy
your `yourfont.css` file temporarily to the `./public` folder as
`fontpie-from-css` loads fonts relative to the CSS file._

2. Add the overrides to your font stylesheet.

Use fontpie for every custom font used (including variants) or
fontpie-from-css and add the metric overrides to `yourfont.css`.

_Ensure the original font has the `font-display: swap` property or the
fallback wouldn't work!_

3. Add the font fallback to the stylesheet.

```css
/* tailwind.css */
@layer base {
:root {
--font-sans: <YourFont> <YourFontFallback>;
}
}
```

That's it! You can now use your custom font without worrying about Cumulative
Layout Shift!
This is expected behavior. Fonts are only generated in the build files. To see
fonts in development mode, build the application first and then run
`npm run dev`.
Loading
Loading