Оптимизация CSS: critical CSS и purge неиспользуемых стилей
Неиспользуемый CSS увеличивает размер файла и замедляет FCP. Bootstrap с несколькими компонентами занимает 140 кБ — после purge остаётся 5–15 кБ. Tailwind с полным набором классов — 3.5 МБ; после purge — 5–50 кБ.
Tailwind CSS: автоматический purge
Tailwind 3+ удаляет неиспользуемые классы при production-сборке автоматически на основе анализа контента:
// tailwind.config.ts
import type { Config } from 'tailwindcss';
export default {
content: [
'./resources/views/**/*.blade.php',
'./resources/js/**/*.{ts,tsx}',
// Важно: включить все файлы, где используются классы
'./resources/js/**/*.json', // если классы генерируются динамически
],
theme: { extend: {} },
plugins: [],
} satisfies Config;
Динамические классы (конкатенация строк) — purge не найдёт их:
// Плохо — purge не увидит
const color = 'red';
<div className={`text-${color}-500`} /> // text-red-500 будет удалён
// Хорошо — полные имена классов
const colorMap = {
red: 'text-red-500',
blue: 'text-blue-500',
};
<div className={colorMap[color]} />
PurgeCSS для Bootstrap/кастомного CSS
// postcss.config.js
import purgecss from '@fullhuman/postcss-purgecss';
export default {
plugins: [
purgecss({
content: [
'./resources/views/**/*.blade.php',
'./resources/js/**/*.tsx',
'./public/**/*.html',
],
safelist: {
// Классы добавляемые JS/Livewire/Alpine
standard: ['modal-open', 'show', 'active', 'fade'],
deep: [/^modal/, /^alert/, /^toast/],
greedy: [/swiper/],
},
defaultExtractor: content =>
content.match(/[\w-/:]+(?<!:)/g) || [],
}),
],
};
Critical CSS — inline стили для первого экрана
Идея: стили, нужные для рендеринга above-the-fold контента, вставлять inline в <head>. Остальное — загружать асинхронно.
Автоматически через Vite (critters):
// vite.config.ts
import { defineConfig } from 'vite';
import { critters } from 'critters';
export default defineConfig({
plugins: [
critters({
preload: 'media', // async load для некритичных
pruneSource: true, // убрать из внешнего CSS то что уже inline
logLevel: 'silent',
})
]
});
Вручную для Laravel:
// Blade: inline critical CSS, async для остального
<style>{!! file_get_contents(public_path('css/critical.css')) !!}</style>
<link rel="preload" href="{{ mix('css/app.css') }}" as="style"
onload="this.onload=null;this.rel='stylesheet'">
<noscript>
<link rel="stylesheet" href="{{ mix('css/app.css') }}">
</noscript>
Генерация critical CSS — critical npm-пакет или penthouse:
npx critical https://example.ru/ --inline --minify > critical.css
CSS-in-JS — проблемы производительности
Styled-components, Emotion генерируют CSS в runtime — дополнительная нагрузка на JS. Для production предпочтительнее статический CSS:
- Tailwind CSS — утилитарные классы, нет runtime overhead
- CSS Modules — локальные классы, компилируются в статический CSS
- Vanilla Extract — typed CSS, zero-runtime
// CSS Modules в React
import styles from './ProductCard.module.css';
function ProductCard({ product }) {
return (
<div className={styles.card}>
<img className={styles.image} src={product.image} alt={product.name} />
<h3 className={styles.title}>{product.name}</h3>
</div>
);
}
Минификация и сжатие
// vite.config.ts — LightningCSS для быстрой минификации
export default defineConfig({
css: {
transformer: 'lightningcss',
lightningcss: {
targets: browserslistToTargets(browserslist('>= 0.5%')),
drafts: { customMedia: true },
}
},
build: {
cssMinify: 'lightningcss',
}
});
LightningCSS также автоматически добавляет вендорные префиксы и полифиллы под настроенный browserslist.
Метрики
Цели после оптимизации:
| Метрика | До | Цель |
|---|---|---|
| CSS bundle (gzip) | 50–140 кБ | < 20 кБ |
| Tailwind после purge | 3.5 МБ | 5–50 кБ |
| Render-blocking CSS | Есть | Нет (critical inline) |
| Покрытие CSS (Coverage) | 10–30% | > 80% |
DevTools → Coverage → перезагрузить страницу → посмотреть % неиспользуемого CSS.
Срок оптимизации: 4–8 часов для настройки purge + critical CSS в сборке.







