Ответ сгенерирован нейросетью и может содержать ошибки
Это один из самых важных вопросов для оптимизации производительности. CSS — это рендер-блокирующий ресурс, и вот почему и как это работает.
Браузер не может начать рендер страницы, пока не загрузит и не разберёт CSS. Это сделано специально: если браузер начнёт рендер без стилей, пользователь увидит неоформленный контент (Flash of Unstyled Content — FOUC), а потом стили применятся и всё переформатируется (jank).
Основной механизм загрузки:
1. HTML парсер начинает работу
2. Встречает <link rel="stylesheet">
3. СТОП! Парсер паузирует
4. Браузер загружает CSS
5. CSS парсится и применяется
6. Парсер HTML продолжает работу
7. JavaScript может выполняться
8. Страница рендерится
<!DOCTYPE html>
<html>
<head>
<!-- Эта ссылка БЛОКИРУЕТ рендер -->
<link rel="stylesheet" href="/css/styles.css">
</head>
<body>
<h1>Заголовок</h1>
<!-- Браузер ждёт CSS, прежде чем рендерить этот контент -->
<div class="container">...</div>
</body>
</html>
Если styles.css весит 500KB и загружается 3 секунды, пользователь видит белый экран 3 секунды!
HTML -> DOM
CSS -> CSSOM (CSS Object Model)
DOM + CSSOM -> Render Tree
Render Tree -> Layout (Reflow)
Layout -> Paint
Paint -> Composite
Браузер не может создать Render Tree, пока не готов CSSOM. Это критический путь рендера.
Проблема 1: Внешний CSS
<!-- Если сеть медленная, это заблокирует всё -->
<link rel="stylesheet" href="https://cdn.example.com/huge-styles.css">
Решение: Критический CSS (Critical CSS)
<!-- Встроить критический CSS прямо в HTML -->
<style>
body { font-family: sans-serif; }
.hero { background: blue; color: white; }
</style>
<!-- Загрузить остальной CSS асинхронно -->
<link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
Проблема 2: CSS перед скриптами
<head>
<link rel="stylesheet" href="/styles.css"> <!-- Блокирует -->
<script src="/app.js"></script> <!-- Ждёт CSS -->
</head>
Решение: CSS в head, скрипты в конце body
<head>
<link rel="stylesheet" href="/styles.css">
</head>
<body>
<div id="app"></div>
<script src="/app.js"></script>
</body>
Проблема 3: Множественные CSS файлы
<!-- Каждый файл требует отдельного запроса -->
<link rel="stylesheet" href="/reset.css">
<link rel="stylesheet" href="/typography.css">
<link rel="stylesheet" href="/layout.css">
<link rel="stylesheet" href="/components.css">
Решение: Объединить в один файл или использовать preload
<!-- Parallel loading -->
<link rel="preload" href="/styles.css" as="style">
<link rel="stylesheet" href="/styles.css">
<!-- Эти CSS МОГУТ не блокировать рендер -->
<link rel="stylesheet" href="/desktop.css" media="(min-width: 768px)">
<link rel="stylesheet" href="/mobile.css" media="(max-width: 767px)">
<!-- Браузер загружает оба, но применяет только подходящий -->
<!-- Однако, СКАЧИВАЕТ оба файла -->
Браузер НЕ блокирует рендер на CSS, который не подходит по media query, но всё равно загружает файл.
1. Critical CSS инлайн
// build.js - выделить критический CSS
const critical = require('critical');
critical.generate({
base: './dist',
src: 'index.html',
target: 'index.html',
inline: true,
minify: true
});
<!-- Результат -->
<style>
/* критический CSS встроен inline */
body { ... }
</style>
<link rel="stylesheet" href="/non-critical.css" media="print" onload="this.media='all'">
2. Отложить неавтоматизированный CSS
<!-- Встроить критический -->
<style>
body { margin: 0; font-family: sans-serif; }
.hero { padding: 2rem; }
</style>
<!-- Загрузить остальное асинхронно -->
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript>
<link rel="stylesheet" href="/styles.css">
</noscript>
3. Использовать preload для приоритета
<head>
<!-- Дай браузеру знать, что это важно, но не блокируй -->
<link rel="preload" href="/fonts.css" as="style">
<link rel="preload" href="/critical.css" as="style">
<link rel="stylesheet" href="/critical.css">
<link rel="stylesheet" href="/fonts.css">
</head>
4. Code splitting в Next.js
// styles.module.css загружается только когда компонент нужен
import styles from './Button.module.css';
export function Button() {
return <button className={styles.btn}>Click</button>;
}
First Contentful Paint (FCP) - время до первого пикселя
Largest Contentful Paint (LCP) - время до основного контента
Cumulative Layout Shift (CLS) - неожиданное движение элементов
Все три метрики зависят от CSS!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Встроенный критический CSS -->
<style>
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #fff;
}
.hero {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 4rem 2rem;
text-align: center;
}
h1 { margin: 0; font-size: 2rem; }
</style>
<!-- Прелоад шрифтов -->
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
<!-- Загрузить остальной CSS асинхронно -->
<link rel="preload" href="/styles.css" as="style">
<link rel="stylesheet" href="/styles.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/styles.css"></noscript>
</head>
<body>
<div class="hero">
<h1>Welcome</h1>
</div>
<main>
<!-- Контент -->
</main>
<!-- Скрипты в конце -->
<script src="/app.js"></script>
</body>
</html>
CSS — рендер-блокирующий ресурс по дизайну. Стратегия:
Это может улучшить FCP на 50-70% на медленных сетях!