This site provides a machine-readable index at /llms.txt.

Skip to main content Skip to navigation

Switch the body and heading typeface

When a DocSite needs custom display and body typefaces instead of the defaults, and those faces should load without a flash of fallback text on first paint, the knobs below cover it. If no DocSite is running yet, start with Scaffold a documentation site with DocSite first.

Assumptions

  • A running DocSite built with AddDocSite / UseDocSite.
  • A chosen font delivery strategy — self-hosted .woff2 files or an external provider — with the files or URLs ready.
  • The CSS font-family name each face registers under.

For a working setup, see examples/DocSiteKitchenSinkExample.


Configure the typefaces

Drop font files into wwwroot/fonts/

Place each .woff2 file under wwwroot/fonts/. UsePennington wires UseStaticFiles, so each file becomes available at /fonts/<file>.woff2. The kitchen-sink example references /fonts/display.woff2 and /fonts/body.woff2; supply your own files at those paths (the example does not ship font binaries).

Register @font-face rules via ExtraStyles

Emit the @font-face declarations into the generated stylesheet by returning them from an ExtraStyles helper. MonorailCSS appends this content verbatim above its utility output, with each src: pointing at the /fonts/... path you exposed above.

"""
        @font-face {
            font-family: 'DocSiteKitchenSinkDisplay';
            font-style: normal;
            font-weight: 100 900;
            font-display: swap;
            src: url(/fonts/display.woff2) format('woff2');
        }
        @font-face {
            font-family: 'DocSiteKitchenSinkBody';
            font-style: normal;
            font-weight: 100 900;
            font-display: swap;
            src: url(/fonts/body.woff2) format('woff2');
        }
        article .feature-callout-demo { letter-spacing: 0.01em; }
        """

Declare preload hints with FontPreloads

Pass a FontPreload[] to DocSiteOptions.FontPreloads. DocSite then emits a <link rel="preload" as="font" crossorigin> tag for each entry in the document head, which prevents the flash of fallback text on first paint.

[
    new FontPreload("/fonts/display.woff2"),
    new FontPreload("/fonts/body.woff2"),
]

Point DisplayFontFamily and BodyFontFamily at the new faces

Set DisplayFontFamily on DocSiteOptions to the CSS stack led by the display face, and set BodyFontFamily to the stack led by the body face. Include a system-ui or sans-serif fallback so pages still render gracefully if a file fails to load.

new()
    {
        SiteTitle = "Kitchen Sink Docs",
        Description = "A wide-surface DocSite example that backs eighteen how-to pages.",
        GitHubUrl = "https://github.com/usepennington/pennington",
        CanonicalBaseUrl = "https://example.com/",
        HeaderContent = """<a href="/" class="font-bold">Kitchen Sink Docs</a>""",
        FooterContent = BuildFooter(),
        ColorScheme = BuildColorScheme(),
        DisplayFontFamily = "'DocSiteKitchenSinkDisplay', system-ui, sans-serif",
        BodyFontFamily = "'DocSiteKitchenSinkBody', system-ui, sans-serif",
        FontPreloads = BuildFontPreloads(),
        ExtraStyles = BuildExtraStyles(),
        ConfigureLocalization = ConfigureLocalization,
        Areas = BuildAreas(),
    }

(Optional) Match MonorailCSS utilities to your stacks

When prose uses MonorailCSS utility classes such as font-sans or font-display, update the theme or ExtraStyles so those utilities resolve to the same font-family stacks; otherwise utility-styled text disagrees with the layout chrome. See Recolor the site for how to pass CustomCssFrameworkSettings.


Result

Body copy renders in the new body face and headings render in the new display face. Because the preload hints prime the browser cache before the stylesheet is parsed, the first paint lands with the real faces in place — no fallback flash, and the perceptible delay drops by ~40 ms on a cold load.

Verify

  • Run dotnet run and open any page. The DevTools Network panel shows /fonts/display.woff2 and /fonts/body.woff2 fetched with rel=preload before the first paint.
  • Computed styles on the <body> resolve to the body family; a heading (<h1>) resolves to the display family.
  • Run dotnet run -- build. The generated index.html contains a <link rel="preload" as="font" ...> tag per FontPreload, and /fonts/*.woff2 lands in output/fonts/.
  • Reference: DocSiteOptions — the full property list including DisplayFontFamily, BodyFontFamily, FontPreloads, and ExtraStyles.
  • Reference: FontPreload — the Href / Type record shape (defaults to font/woff2).
  • How-to: Recolor the site — for aligning utility-class font stacks with your new families.