NextJS Core Web Vitals - verwijder render blocking CSS

De ultieme NextJS Core Web Vitals gids - verwijder render blocking CSS

Arjen Karel Core Web Vitals Consultant
Arjen Karel - linkedin
Last update: 2024-11-27

Verwijder render blocking CSS in NextJS

CSS is render blocking. Dit betekent dat een browser niet begint met renderen wanneer hij CSS in de head van de pagina vindt totdat al die CSS is geparsed. Als de browser verplicht is om een of meer externe CSS-bestanden te downloaden, kan dat kostbare tijd in beslag nemen. In dit artikel laat ik je zien hoe je die render blocking CSS-bestanden in je NextJS-app kunt verwijderen om het renderen te versnellen. Dit zal je paint metrics (First Contentful Paint en Largest Contentful Paint) verbeteren

Standaard maakt NextJS 2 stylesheets voor een pagina. De eerste is de globale stylesheet en de tweede een paginaspecifieke stylesheet. Hoeveel tijd gaat dat ons kosten? Dat hangt af van veel factoren zoals het apparaat van de bezoeker, de netwerksnelheid, het netwerkverbindingsprotocol, de afstand tot de server, de grootte van de stylesheet etc. Gemiddeld, voor al mijn klanten, op alle apparaten heb ik gevonden dat dit ongeveer 200ms duurt. Op de NextJS website duurt het downloaden van die 2 stylesheets 600ms op een snelle 3g verbinding. Dit zal alle paint metrics met 600ms vertragen. Tijd om actie te ondernemen en deze render blocking stylesheets te verwijderen!

Optie 1: Genereer Critical CSS

De eerste en snelste optie is om Critical CSS te genereren. Critical CSS is een verzameling CSS-regels die nodig zijn om het zichtbare deel van de pagina te renderen. Die regels worden inline in de HEAD van de pagina geplaatst. Vervolgens worden parallel de originele CSS-bestanden gedownload terwijl de browser doorgaat met renderen. Zodra de originele CSS-bestanden zijn gedownload, worden ze in de pagina geïnjecteerd.

Critical CSS is nu beschikbaar in NextJS als een experimentele functie. Het genereren van Critical CSS in NextJS is uiterst eenvoudig. Voeg gewoon experimental: { optimizeCss: true } toe aan je next.config.js en voeg install critters@0.0.7 toe als een dependency in je project.

const nextConfig = {
  reactStrictMode: true,
  experimental: { optimizeCss: true }
}

Optie 2: inline CSS in de HEAD van de pagina.

Als je geen experimentele functies in je NextJS-app wilt inschakelen om de Core Web Vitals te verbeteren, zou je kunnen overwegen om je CSS te inlinen. Je moet een aangepaste head-sectie maken en hiernaar verwijzen in je _document.tsx.

Het nadeel van deze methode is dat de inline CSS waarschijnlijk groter zal zijn dan bij de eerste methode. Als je je stylesheets echter schoon en effectief houdt, zal deze methode de Core Web Vitals voor je NextJS-app waarschijnlijk aanzienlijk verbeteren!

import { Html, Head, Main, NextScript } from "next/document";
import { readFileSync } from "fs";
import { join } from "path";

class InlineStylesHead extends Head {
  getCssLinks: Head["getCssLinks"] = ({ allFiles }) => {
    const { assetPrefix } = this.context;
    if (!allFiles || allFiles.length === 0) return null;
    return allFiles
      .filter((file: any) => /\.css$/.test(file))
      .map((file: any) => (
        <style
          key={file}
          nonce={this.props.nonce}
          data-href={`${assetPrefix}/_next/${file}`}
          dangerouslySetInnerHTML={{
            __html: readFileSync(join(process.cwd(), ".next", file), "utf-8"),
          }}
        />
      ));
  };
}

export default function Document() {
  return (
    <Html>
      <InlineStylesHead />
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}  

Optie 3: Styled Components

Styled Components is een CSS-in-JS tool waarmee je CSS in JavaScript-bestanden kunt schrijven. Dit heeft veel voordelen. Je kunt bijvoorbeeld klassenamen herhalen, ongebruikte CSS-code eenvoudig verwijderen en code gemakkelijker beheren in vergelijking met traditionele CSS-bestanden. Wat betreft de Core Web Vitals betekent dit dat je alleen de stijlen injecteert die op die pagina nodig zijn. Best netjes, toch?

Vanaf NextJS versie 12.1 is het makkelijker dan ooit om styled components te gebruiken in je NextJS-app. Voeg compiler:{styledComponents: true} toe aan je next.config.js, installeer styled-components (yarn add styled-components en wanneer het klaar is met installeren, voer yarn add -D @types/styled-components uit), update het bestand _document.js om server side rendering voor styled components te ondersteunen en je bent klaar om te gaan!

const nextConfig = {
    reactStrictMode: true,
    compiler: {
    styledComponents: true,
  }
}
import Document, { DocumentContext } from "next/document";
import { ServerStyleSheet } from "styled-components";

export default class MyDocument extends Document {
  static async getInitialProps(ctx: DocumentContext) {
    const sheet = new ServerStyleSheet();
    const originalRenderPage = ctx.renderPage;

    try {
      ctx.renderPage = () =>
        originalRenderPage({
          enhanceApp: (App) => (props) =>
            sheet.collectStyles(<App {...props} />),
        });

      const initialProps = await Document.getInitialProps(ctx);
      return {
        ...initialProps,
        styles: (
          <>
            {initialProps.styles}
            {sheet.getStyleElement()}
          </>
        ),
      };
    } finally {
      sheet.seal();
    }
  }
}

Find out what is actually slow.

I map your critical rendering path using real field data. You get a clear answer on what blocks LCP, what causes INP spikes, and where layout shifts originate.

Book a Deep Dive
NextJS Core Web Vitals - verwijder render blocking CSSCore Web Vitals NextJS Core Web Vitals - verwijder render blocking CSS