Shopify Taste · Free, no signup · Last updated
Fix Custom Font Layout Shift on Shopify Taste
Layout shift on Taste after a custom font installs is almost always a missing `font-display: swap`, an unpreloaded WOFF2, or a JS-driven font swap that fires after first paint — fix all three and your CLS drops to zero.
Taste ships clean Core Web Vitals out of the box, but a poorly configured custom font can knock CLS up by 0.10 or more. Because a free theme for specialty food and wine brands with collection layouts tuned to story-rich SKUs., the merchant audience tends to research these issues directly on mobile — making CLS a conversion-impacting metric, not just an SEO one.
Generator
Live preview
Add to cart · Free shipping · 30-day returns
Drop a WOFF2 / WOFF / TTF file here to preview your actual font. The file stays in your browser — nothing is uploaded.
Paste these three blocks in order. They're independent files in your theme — copying one without the others won't break the store.
Step 1: @font-face CSS
Paste at the bottom of assets/base.css. Uses Liquid's asset_url filter — Shopify resolves the path at render time.
@font-face {font-family: "My Brand Sans";src: url({{ 'my-brand-sans.woff2' | asset_url }}) format('woff2');font-weight: 400;font-style: normal;font-display: swap;}
Step 1: @font-face CSS
Paste at the bottom of assets/base.css. Uses Liquid's asset_url filter — Shopify resolves the path at render time.
@font-face {font-family: "My Brand Sans";src: url({{ 'my-brand-sans.woff2' | asset_url }}) format('woff2');font-weight: 400;font-style: normal;font-display: swap;}
Step 2: settings_schema.json
Adds a Theme Editor section so non-technical merchants can toggle the font on or off.
{"name": "My Brand Sans (custom font)","settings": [{"type": "header","content": "My Brand Sans typography"},{"type": "paragraph","content": "Upload your My Brand Sans files (woff2, woff, ttf, otf, or eot) to your theme's Assets folder. The @font-face block referencing my-brand-sans.* will then resolve via {{ 'my-brand-sans.woff2' | asset_url }}."},{"type": "font_picker","id": "my_brand_sans_heading_font","label": "Heading font (fallback when custom file is unavailable)","default": "assistant_n4"},{"type": "font_picker","id": "my_brand_sans_body_font","label": "Body font (fallback when custom file is unavailable)","default": "assistant_n4"},{"type": "select","id": "my_brand_sans_apply_to","label": "Apply My Brand Sans","options": [{"value": "headings","label": "Headings only"},{"value": "body","label": "Body only"},{"value": "both","label": "Headings and body"},{"value": "off","label": "Disabled"}],"default": "both"},{"type": "checkbox","id": "my_brand_sans_load_woff_fallback","label": "Also load WOFF fallback (legacy browsers)","default": false}]}
Step 3: CSS variable overrides
Retargets Dawn's --font-heading-family / --font-body-family. Survives theme updates.
:root {--font-heading-family: "My Brand Sans", sans-serif;--font-heading-style: normal;--font-heading-weight: 400;--font-body-family: "My Brand Sans", sans-serif;--font-body-style: normal;--font-body-weight: 400;}
How to use this on Taste
Three fixes cover almost every case.
First, set `font-display: swap` on every @font-face declaration so the browser renders fallback metrics immediately and swaps in your custom face when ready.
Second, preload the WOFF2 with `<link rel="preload" as="font" type="font/woff2" crossorigin>` from Taste's `theme.liquid` head — preloading saves the round-trip the browser would otherwise make after parsing CSS.
Third, override `--font-heading-family` instead of swapping classes via JavaScript: Taste's headings (.product__vendor, .recipe-card__title) read the variable at first paint, eliminating the post-load reflow that JS-driven swaps cause.
Verify with the Performance panel in DevTools — the CLS bar should be flat across the load.
Frequently asked questions
Why does my custom font cause layout shift on Taste?
Almost always one of three causes: `font-display` defaults to `auto` which blocks rendering and then swaps, the WOFF2 isn't preloaded so the browser fetches it after parsing CSS, or a Liquid block is toggling a class via JavaScript after first paint. Taste's system fallback has different metrics than most custom faces, which exaggerates the shift if any of those three are in play.
How do I preload a font on Taste to fix CLS?
Open Taste's `layout/theme.liquid` and insert `<link rel="preload" href="{{ 'yourfont.woff2' | asset_url }}" as="font" type="font/woff2" crossorigin>` inside the `<head>` block, above the main stylesheet link. Preloading tells the browser to fetch the font in parallel with the HTML, eliminating the wait that otherwise happens between CSS parse and font request.
Should I use font-display: swap or font-display: optional on Taste?
`swap` for nearly all Taste stores. `optional` is theoretically zero-CLS because it skips the swap if the font isn't ready in 100ms — but on a specialty food & wine site, brand consistency matters, and `swap` plus a preload is functionally CLS-free without sacrificing the custom face. The generator above defaults to `swap`.
What size budget should I aim for to keep CLS at zero on Taste?
Aim for sub-50KB WOFF2 per face. Taste's critical render path expects the font to arrive before the layout settles — at 50KB on 4G that's well within the LCP window. If your face is larger (heavy display or icon-loaded), subset it to Latin-only and only include the weights your store actually uses, which often cuts file size by 60-70%.