Split Critical CSS dans Tailwind v3/v4 sur Laravel + Vite
Lorsqu'une page semble lente, les utilisateurs fixent un écran vide tandis que le CSS bloque le rendu. Une solution pragmatique consiste à livrer juste assez de styles pour la vue au-dessus du pli et à différer le reste. Ce guide montre une configuration propre à deux entrées dans Laravel + Vite, avec des exemples prêts à la production pour Tailwind v3 et v4, pourquoi PageSpeed/Core Web Vitals est important, et ce qu'il faut éviter.

Pourquoi PageSpeed est important (LCP/CLS)
Le CSS critique est l'ensemble minimal de styles nécessaires au rendu du premier écran (au-dessus du pli). En livrant cette partie tôt (en ligne ou sous forme de fichier minuscule) et en reportant le reste du CSS, vous réduisez le travail de blocage du rendu et améliorez le LCP. Une configuration soignée des polices de caractères peut également réduire les changements inattendus de mise en page et favoriser le CLS.
Stratégie de base (Laravel + Vite)
- Deux points d'entrée :
critical.css
pour le premier écran ;app.css
pour tout le reste (plugins, utilitaires étendus, typographie longue). - Ordre de chargement : livrez les éléments critiques sur
<head>
(en ligne ou lien normal). Différez le reste avecrel="preload" as="style"
+onload
et un fallback<noscript>
. - Évitez les doublons : gardez la base/les composants dans critical et déplacez le gros des utilitaires dans le bundle différé ; assurez-vous que les fichiers sources analysés par chaque build ne se chevauchent pas.
Tailwind v3 : deux configurations + un preset
1) Partagez votre thème une fois
// tailwind.shared.js
module.exports = {
theme: {
extend: {
// colors, spacing, etc.
},
},
plugins: [],
};
2) Construction critique (analyse uniquement les modèles au-dessus du pli)
// tailwind.critical.config.js
module.exports = {
presets: [require('./tailwind.shared')],
content: [
'./resources/views/layouts/app.blade.php',
'./resources/views/partials/header.blade.php',
'./resources/views/home/hero.blade.php',
],
};
/* resources/css/critical.css */
@config "tailwind.critical.config.js";
@tailwind base;
@tailwind components;
@tailwind utilities;
3) App bundle (exclure les fichiers utilisés par critical)
// tailwind.app.config.js
module.exports = {
presets: [require('./tailwind.shared')],
content: [
'./resources/**/*.blade.php',
'./resources/**/*.vue',
'!./resources/views/partials/header.blade.php',
'!./resources/views/home/hero.blade.php',
],
};
/* resources/css/app.css */
/* Avoid duplicating base/components (already shipped in critical) */
@config "tailwind.app.config.js";
@tailwind utilities;
Si vous avez des noms de classes dynamiques, ajoutez-les à safelist
dans les deux configurations.
4) Construire et se connecter via Vite (Laravel)
// vite.config.ts
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
export default defineConfig({
plugins: [
laravel({
input: [
'resources/css/critical.css',
'resources/css/app.css',
'resources/js/app.js',
],
refresh: true,
}),
],
})
<!-- Blade: load critical normally (or inline it) -->
@vite('resources/css/critical.css')
<!-- Defer the rest: preload + onload + noscript -->
@php $appCss = Vite::asset('resources/css/app.css'); @endphp
<link rel="preload" as="style" href="{{ $appCss }}" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="{{ $appCss }}"></noscript>
Tailwind v4 : sources CSS-first avec contrôle fin
Dans Tailwind v4, la configuration est CSS-first. Pour éviter les chevauchements entre les bundles critiques et les bundles d'applications, désactivez l'analyse automatique et déclarez les sources explicitement.
1) Jetons partagés
/* resources/css/theme.css */
@theme {
/* brand tokens, breakpoints, etc. */
--color-brand-500: oklch(0.72 0.12 250);
--breakpoint-2xl: 96rem;
}
2) CSS critique : ne scannez que ce qui est nécessaire
/* resources/css/critical.css */
@import "tailwindcss" source(none);
@import "./theme.css";
/* Enumerate just the above-the-fold templates */
@source "../views/layouts/app.blade.php";
@source "../views/partials/header.blade.php";
@source "../views/home/hero.blade.php";
/* Import required layers explicitly */
@layer theme, base, components, utilities;
@import "tailwindcss/theme" layer(theme);
@import "tailwindcss/base" layer(base);
@import "tailwindcss/components" layer(components);
@import "tailwindcss/utilities" layer(utilities);
3) App CSS : tout le reste (exclure ce que critical couvre déjà)
/* resources/css/app.css */
@import "tailwindcss" source(none);
@import "./theme.css";
/* Scan the project... */
@source "../views/**/*.blade.php";
/* ...except templates you already used for critical */
@source not "../views/partials/header.blade.php";
@source not "../views/home/hero.blade.php";
/* App bundle: keep it lean for post-fold content */
@layer theme, utilities;
@import "tailwindcss/theme" layer(theme);
@import "tailwindcss/utilities" layer(utilities);
/* Inline safelist if you generate classes dynamically */
@source inline("md:grid lg:gap-6 bg-brand-500");
4) Configuration du site et chargement de Blade
// vite.config.ts (same as v3)
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
export default defineConfig({
plugins: [
laravel({
input: [
'resources/css/critical.css',
'resources/css/app.css',
'resources/js/app.js',
],
refresh: true,
}),
],
})
<!-- Blade: same pattern as v3 -->
@vite('resources/css/critical.css')
@php $appCss = Vite::asset('resources/css/app.css'); @endphp
<link rel="preload" as="style" href="{{ $appCss }}" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="{{ $appCss }}"></noscript>
Ce qui a sa place dans critical (et ce qui ne l'a pas)
- Inclure : les réinitialisations de base, la structure de l'en-tête/nav, la section des héros, les boutons/liens essentiels, la typographie minimale du premier écran.
- À éviter : composants lourds sous le pli, typographie longue
.prose
, rares widgets.
Polices de caractères et mini-préparation CLS
Les changements de mise en page se produisent souvent lorsque la police de secours est remplacée par la police web. Utilisez size-adjust
et les métriques connexes pour mieux correspondre à la police de repli, et ne préchargez que les polices vraiment essentielles.
@font-face {
font-family: "InterVar";
src: url("/fonts/InterVar.woff2") format("woff2");
font-weight: 100 900;
font-display: swap;
/* Tweak metrics to reduce shifts */
size-adjust: 100%;
ascent-override: 92%;
descent-override: 24%;
line-gap-override: 0%;
}
Vérifiez le résultat
- Exécutez PageSpeed/Lighthouse et comparez LCP; cochez les cases "Réduire les ressources bloquant le rendu" et "Réduire les feuilles de style CSS inutilisées".
- Vérifiez qu'il n'y a pas de doublons entre les lots ; si vous constatez un surpoids, revoyez les sources scannées.
- N'oubliez pas : les résultats des laboratoires sont indicatifs ; surveillez la tendance générale et les données sur le terrain.
Pièges courants
- Chevauchement des sources → doublons : dans la version 3, corrigez vos bulles
content
; dans la version 4, utilisezsource(none)
avec@source
et@source not
explicites. - Plugins/typographie dans critical : cela gonfle facilement le fichier - gardez-le dans
app.css
. - Inlining critical vs CSP : si votre CSP est strict, envoyez critical comme un minuscule fichier externe.
- migration v3 → v4 : déplacez les tokens de
theme.extend
vers@theme
, passez decontent
à@source
, et préférez les importations CSS-first.
Alternatives si la saisie à deux entrées n'est pas votre truc
- Critiques auto-générés (par exemple, critical, critters) : plus rapide à démarrer ; plus difficile à déboguer sur des modèles complexes.
- Une seule configuration + plusieurs sources: conservez une configuration (v3) ou une configuration CSS (v4) et gérez l'inclusion/exclusion via globs/
@source
. - CSS au niveau de la route: les paquets par page ne sont chargés que là où c'est nécessaire ; puissant mais ajoute de la complexité à l'infrastructure.
- Component-scoped critical: styles minuscules en ligne pour les composants clés au-dessus du pli ; discipline requise, fonctionne bien pour les blocs répétés.
Résumé
Avec un petit bundle critique dans <head>
et un bundle principal différé, vous donnez au navigateur moins de choses à bloquer et aux utilisateurs une première peinture plus rapide. Tailwind v3 favorise deux configurations et des chemins d'accès prudents à content
; Tailwind v4 rend cela encore plus propre avec le contrôle CSS-first de @source
. Sur Laravel + Vite, il s'agit d'une configuration simple et facile à maintenir qui améliore sensiblement la vitesse perçue.
Contactez-nous
Un projet en tête?
Indiquez le contexte et l’objectif visé. Nous répondons sous 1 jour ouvrable avec la prochaine étape la plus simple (planning, budget indicatif ou audit rapide).