Перейти к содержимому

8. CSS Performance

CSS может серьёзно влиять на производительность. Неправильные анимации вызывают Layout Reflow, тяжёлые селекторы замедляют рендеринг.

<!-- Стили первого экрана встроены — нет блокировки! -->
<style>
/* Только то, что видно без скролла */
body { margin: 0; font-family: sans-serif; }
.header { background: #000; color: #fff; padding: 16px; }
.hero { min-height: 100vh; display: flex; align-items: center; }
</style>
<!-- Остальные стили загружаем асинхронно -->
<link rel="preload" href="/styles.css" as="style" onload="this.rel='stylesheet'">
Окно терминала
# lightningcss (быстрее, чем PostCSS)
npx lightningcss-cli --minify input.css -o output.min.css
# cssnano через PostCSS
npm install cssnano postcss-cli
npx postcss input.css --use cssnano -o output.min.css
/* ❌ Анимируем свойства, вызывающие Reflow */
.bad-animation {
transition: width 0.3s, height 0.3s, margin 0.3s;
}
.bad-animation:hover {
width: 200px; /* REFLOW! */
margin-top: 20px; /* REFLOW! */
}
/* ✅ Анимируем только transform и opacity (GPU!) */
.good-animation {
transition: transform 0.3s ease, opacity 0.3s ease;
}
.good-animation:hover {
transform: scale(1.05) translateY(-4px); /* только Composite */
opacity: 0.9; /* только Composite */
}
/* ✅ will-change для сложных анимаций */
.animated-card {
will-change: transform; /* GPU слой заранее */
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.animated-card:hover {
transform: translateY(-8px) scale(1.02);
}
/* ВАЖНО: убирайте will-change когда анимация не активна */
.animated-card.animation-done {
will-change: auto;
}
/* Изолируем область рендеринга */
.widget {
contain: layout; /* layout не распространяется наружу */
}
.card {
contain: style layout; /* полная изоляция стилей и layout */
}
.sidebar {
contain: paint; /* paint ограничен этим элементом */
}
/* contain: strict = layout + style + paint + size */
.isolated-component {
contain: strict;
}
/* content-visibility — ленивый рендеринг */
.off-screen-section {
content-visibility: auto;
contain-intrinsic-size: 0 400px; /* резервируем место
}
/* CSS читает селекторы справа налево! */
/* ❌ Медленно — проходит по ВСЕМ span на странице */
.container .wrapper .list .item span { color: red; }
/* ✅ Быстро — сразу находим нужный класс */
.item-text { color: red; }
/* ❌ Универсальный селектор */
* { box-sizing: border-box; } /* читает каждый элемент */
/* ✅ Лучше через :where для нулевой специфичности */
:where(*, *::before, *::after) { box-sizing: border-box; }
/* ❌ Attribute selectors — медленнее класса */
[data-theme="dark"] .button { ... }
/* ✅ Класс быстрее */
.button-dark { ... }

CSS Custom Properties (Variables) для производительности

Заголовок раздела «CSS Custom Properties (Variables) для производительности»
/* Меняем переменную → браузер не пересчитывает весь layout */
:root {
--primary: #89b4fa;
--spacing: 16px;
--radius: 8px;
--transition: 0.2s ease;
}
/* Тема через CSS переменные — без JS! */
[data-theme="dark"] {
--bg: #1e1e2e;
--text: #cdd6f4;
}
[data-theme="light"] {
--bg: #ffffff;
--text: #333333;
}
.button {
background: var(--primary);
padding: var(--spacing);
border-radius: var(--radius);
transition: transform var(--transition);
}
/* ✅ font-display: swap — показываем fallback сразу */
@font-face {
font-family: 'MyFont';
src: url('/fonts/MyFont.woff2') format('woff2');
font-display: swap;
font-weight: 400 700; /* Variable font диапазон */
}
/* ✅ Системные шрифты как fallback */
body {
font-family: 'MyFont', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, sans-serif;
}
/* ✅ size-adjust — убираем Layout Shift при загрузке шрифта */
@font-face {
font-family: 'MyFont-fallback';
src: local('Arial');
size-adjust: 105%;
ascent-override: 95%;
}
/* ✅ Mobile-first → добавляем для большего экрана */
.container {
padding: 16px; /* mobile */
}
@media (min-width: 768px) {
.container {
padding: 32px; /* tablet+ */
}
}
@media (min-width: 1280px) {
.container {
padding: 48px; /* desktop+ */
}
}
/* ✅ Загружаем CSS только для нужного медиа */
<link rel="stylesheet" href="print.css" media="print">
<link rel="stylesheet" href="large-screen.css" media="(min-width: 1280px)">