Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Critical CSS for CMS-based Server-rendered Websites

Prateek Rungta
September 24, 2021

Critical CSS for CMS-based Server-rendered Websites

A super fast website often involves inlining your critical CSS while asynchronously loading the non-critical CSS. You understand what that means, but you’ve got a CMS-based website with many templates and hundreds or more (server rendered) pages but no simple switch or plugin to “Turn on Critical CSS”. This talk will show you how to marry Critical CSS with a site like yours to produce webpages that load quickly and get your green scores in your performance monitors.

We look at an end-to-end solution that we have evolved and battle tested over the years at Miranj. I cover identifying target templates, leveraging the Critical library to extract critical CSS, automating the extraction process using Gulp, reducing response size for repeat visitors, and getting this entire system to work with the caching layer(s) that you may already be using.

Prateek Rungta

September 24, 2021
Tweet

More Decks by Prateek Rungta

Other Decks in Programming

Transcript

  1. CMS Browser Server /hom e <html>
 <head > <body >

    <header > .. . <section > <section > .. . <footer>
 </html>
  2. Bolt 
 Kirby 
 Ghost 
 Drupal 
 Joomla 


    Magento 
 Cra ft CMS 
 WordPress 
 Expression Engine
  3. “The time from when the page starts loading to when

    any part of the page’s content is rendered on the screen.” web.dev/fcp
  4. “The render time of the largest image or text block

    visible within the viewport, relative to when the page first started loading.” web.dev/lcp
  5. 1. Render full page (HTML, CSS, assets etc.) 2. Define

    viewport width & height 3. Filter CSS selectors used in the viewport
  6. 1. Get a fully rendered sample page (per template) 2.

    Feed this HTML & CSS to the tool 3. Save generated Critical CSS (per template) 4. Watch for changes in template or CSS files, repeat steps 1-3.
  7. 1. One sample page per template const samples = {


    article: 'http://site.local/article-2',
 page: 'http://site.local/about',
 index: 'http://site.local/page/2',
 category: 'http://site.local/categories/perf',
 }
  8. 2. Extract Critical CSS using `npm i critical` function extract(src,

    destination) {
 return critical.generate({
 src,
 css: ['dist/styles.css'],
 target: `dist/${destination}.critical.css`,
 minify: true,
 dimensions: [
 { width: 400, height: 900 },
 { width: 1300, height: 900 },
 ],
 })
 }
  9. 3. Run the extraction for all templates Object.entries(samples)
 .forEach(([template, sample])

    => {
 exports[`critical:${template}`] = () => extract(sample, template)
 })
 
 exports.critical = gulp.parallel(
 ...Object.keys(samples)
 .map(template => `critical:${template}`)
 )
  10. 4. Watch for changes in template or CSS files, repeat

    exports.default = () => {
 gulp.watch('dist/styles.css', 'critical')
 gulp.watch('templates/**/*.{html,twig}', 'critical')
 }
  11. <html > <head > <style>
 /* Critical CSS */
 </style>


    <link rel=stylesheet href=styles.css > ... 📦 Bundle with HTML
  12. <html > <head > <style > /* Critical CSS *

    / </style > 
 <link rel=stylesheet href=styles.css
 media=print
 onload="this.media='all'; this.onload=null;">
 ... 🚶 Async load full CSS
  13. <html> <!-- Repeat Visit -- > <head > <link rel=stylesheet

    href=styles.css> .. . ✅ Cached locally
  14. <html> <!-- Repeat Visit -- > <head > <style >

    /* Critical CSS * / </style > <link rel=stylesheet href=styles.css
 media=print
 onload="this.media='all'; this.onload=null;">
 ... 📦 Avoid extra baggage
  15. <!-- First Visit -->
 
 <html > <head > <style>


    /* Critical CSS */
 </style>
 
 <link rel=styleshee t href=styles.css media=print onload="this.media='all'"> ... <!-- Repeat Visit -->
 
 <html > <head > 
 <link rel=styleshee t href=styles.css>
 
 ...
  16. How do we figure out if a request is a

    first or repeat visit? 🤔
  17. Does the request contain 🍪? 
 ✅ has cookie =

    repeat visit ❌ no cookie = first visit
  18. <!-- First Visit -->
 
 <html > <head > <style>


    /* Critical CSS */
 </style>
 
 <link rel=styleshee t href=styles.css media=print onload="this.media='all'"> ... <!-- Repeat Visit -->
 
 <html > <head > 
 <link rel=styleshee t href=styles.css>
 
 ...
  19. <!-- ❌ No Cookie -->
 
 <html > <head >

    <style>
 /* Critical CSS */
 </style>
 
 <link rel=styleshee t href=styles.css media=print onload="this.media='all'"> ... <!-- ✅ Has Cookie 🍪 -->
 
 <html > <head > 
 <link rel=styleshee t href=styles.css>
 
 ...
  20. <!-- ❌ No Cookie -->
 
 <html > <head >

    <style>
 /* Critical CSS */
 </style>
 
 <link rel=styleshee t href=styles.css media=print onload="this.media='all'"> ... <!-- ✅ Has Cookie 🍪 -->
 
 <html > <head > 
 <link rel=styleshee t href=styles.css>
 
 ... Set-Cookie:
 repeat_visit=1
  21. <!-- ❌ No Cookie -->
 
 <html > <head >

    <style>
 /* Critical CSS */
 </style>
 
 <link rel=styleshee t href=styles.css media=print onload="this.media='all'"> ... <!-- ✅ Has Cookie 🍪 -->
 
 <html > <head > 
 <link rel=styleshee t href=styles.<hash>.css>
 
 ... Set-Cookie:
 repeat_visit=<hash>
  22. CMS Browser Cache /home <html>...</html> /about <html>...</html> /blog <html>...</html> /article-1

    <html>...</html> /article-2 <html>...</html> /article-3 <html>...</html>
  23. CMS Browser Cache /home 🍪 <html>...</html> - <html>...</html> /about 🍪

    <html>...</html> - <html>...</html> /blog 🍪 <html>...</html> - <html>...</html>
  24. • Pick one representative sample per template • Automate Critical

    CSS generation via a build tool • Inline critical CSS (only) for first time visitors • Set a cookie to di ff erentiate first vs repeat visits • Cache two versions of each URL