{"id":13398084,"url":"https://github.com/netlify/postcss-fout-with-a-class","last_synced_at":"2025-03-14T00:32:56.567Z","repository":{"id":66218855,"uuid":"84747359","full_name":"netlify/postcss-fout-with-a-class","owner":"netlify","description":"Rewrite all selectors that will trigger a font load to be scoped under a class","archived":true,"fork":false,"pushed_at":"2020-05-26T18:03:53.000Z","size":10,"stargazers_count":28,"open_issues_count":2,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-06T11:38:01.439Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/netlify.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-03-12T18:24:39.000Z","updated_at":"2023-01-28T13:22:12.000Z","dependencies_parsed_at":"2023-07-25T00:30:30.261Z","dependency_job_id":null,"html_url":"https://github.com/netlify/postcss-fout-with-a-class","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlify%2Fpostcss-fout-with-a-class","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlify%2Fpostcss-fout-with-a-class/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlify%2Fpostcss-fout-with-a-class/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/netlify%2Fpostcss-fout-with-a-class/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/netlify","download_url":"https://codeload.github.com/netlify/postcss-fout-with-a-class/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243505205,"owners_count":20301572,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T18:02:06.249Z","updated_at":"2025-03-14T00:32:56.261Z","avatar_url":"https://github.com/netlify.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# FOUT with a Class in PostCSS\n\nAt [Netlify](https://www.netlify.com) we wanted to speed up our initial page loads, and saw that font-loading\nwas the trickiest part of our critical path.\n\nFont-loading in modern browsers is somewhat of a dark art and can be hard to setup and configure properly.\n\nOne of the best current approaches is [FOUT with a class](https://www.zachleat.com/web/comprehensive-webfonts/#fout-class). This technique takes advantage of\nthe fact that the browser won't start loading fonts before they are applied to some DOM element on the page.\n\nWe can combine this with service workers or session storage to make sure we lazy load fonts on the first view\nto avoid blocking the initial critical rendering path, but load font instantly from cache so we avoid any\nflash of un-styled text on subsequent page loads.\n\nThe flip side of that approach is that it requires a lot of discipline in the CSS to avoid accidentally apply\na font-family to an element without scoping it under a relevant class.\n\n## PostCSS to the rescue!\n\nThis PostCSS plugin will handle all of that discipline for you, by detecting all fonts and moving them to scoped\nselectors.\n\nExample CSS\n\n```css\n@font-face {\n    font-family: 'Mija';\n    src: url('/fonts/MijaBold/Mija_Bold-webfont.woff2') format('woff2');\n}\n.fancy-headline h1 {\n  font-size: 10rem;\n  font-family: 'Mija';\n}\n```\n\nExample PostCSS setup:\n\n```js\nimport postcss from \"postcss-gulp\";\nimport foutWithAClass from \"postcss-fout-with-a-class\";\n\ngulp.task('css', () =\u003e (\n  gulp.src('./src/css/*.css')\n    .pipe(postcss([foutWithAClass({families: ['Mija'], className: 'wf-loaded'})]))\n    .pipe(gulp.dest('./dist/css'));\n));\n```\n\nCSS output:\n\n```css\n@font-face {\n    font-family: 'Mija';\n    src: url('/fonts/MijaBold/Mija_Bold-webfont.woff2') format('woff2');\n}\n.fancy-headline h1 {\n  font-size: 10rem;\n}\n.wf-loaded .fancy-headline h1 {\n  font-family: 'Mija';\n}\n```\n\n## Taking advantage of this\n\nA simple way to take advantage of this is with a service worker. I recommend using the awesome [sw-toolbox](https://github.com/GoogleChrome/sw-toolbox) to simplify that. Here's an example\nservice worker that will load your fonts straight from the cache after initial load.\n\n```js\nimport toolbox from 'sw-toolbox';\n\nself.addEventListener('install', (event) =\u003e event.waitUntil(self.skipWaiting()));\nself.addEventListener('activate', (event) =\u003e event.waitUntil(self.clients.claim()));\n\ntoolbox.router.get('/fonts/*', toolbox.cacheFirst);\n```\n\nAnd a quick way to use this to either start loading fonts after the onload event, or loading straight\naway once your service worker is active:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\n\u003chead\u003e\n  \u003ctitle\u003eFont Loading Demo\u003c/title\u003e\n  \u003clink href=\"/css/main.css\" rel=\"stylesheet\"/\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n  \u003cscript\u003e\n  if ('serviceWorker' in navigator \u0026\u0026 navigator.serviceWorker.controller !== null \u0026\u0026 navigator.serviceWorker.controller.state === 'activated') {\n    document.querySelector(\"html\").classList.add('wf-loaded');\n  } else {\n    document.addEventListener('load', function() { document.querySelector(\"html\").classList.add('wf-loaded'); }, false);\n  }\n  \u003c/script\u003e\n\n  \u003ch1 class=\"fancy-headline\"\u003eA Fancy Headline\u003c/h1\u003e\n\n\u003c/body\u003e\n\u003c/html\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetlify%2Fpostcss-fout-with-a-class","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnetlify%2Fpostcss-fout-with-a-class","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnetlify%2Fpostcss-fout-with-a-class/lists"}