Если вы фронтенд-разработчик, полезно понимать, как браузер превращает HTML, CSS и JavaScript в отрисованную страницу. Это помогает объяснять задержки, отлаживать разметку и заранее видеть, как поведёт себя код.
Разберём устройство браузера: от запроса сети до кадра на экране.
Из чего состоит браузер
В браузере несколько крупных подсистем: сетевой стек, парсер HTML/CSS, движок JavaScript, менеджер документа (DOM) и рендерер, который рисует пиксели. Они работают в разных потоках и координируются через событийный цикл.
# в Chrome/Chromium посмотреть страницу
# chrome://version
# chrome://gpu — состояние ускорения
# в Firefox
# about:support
Сетевой стек
Браузер открывает соединение, выполняет DNS-резолюцию, TLS-рукопожатие, отправляет запрос и обрабатывает ответ. Дальше приходят заголовки, HTML по частям, ресурсы CSS, JS, изображения.
# посмотреть загрузку страницы с терминала
curl -sI https://example.com | head -20
# время до ответа
curl -o /dev/null -s -w "%{time_total}s
" https://example.com
Порядок загрузки скриптов важен: defer и async меняют момент выполнения и влияют на отрисовку.
Парсинг в DOM
Парсер HTML строит дерево документа. Если встречается скрипт синхронного выполнения, парсинг может остановиться — поэтому блокирующие скрипты в head замедляют отрисовку.
# оценить дерево
# в DevTools: Elements
# посмотреть разметку из терминала
curl -s https://example.com | head -40
# проверить валидность разметки
tidy -e page.html 2>/dev/null | head
Параллельно парсится CSS и строится дерево стилей (CSSOM). Только когда есть оба дерева, начинается layout.
Layout, Paint, Composite
Layout вычисляет геометрию элементов. Paint заливает цвета и текст. Composite собирает слои и отдаёт их GPU. Знание этих шагов объясняет, почему transform плавнее left.
# в Chrome DevTools: Performance, вкладка Rendering
# включить Paint flashing, чтобы видеть перерисовки
# в Firefox: devtools похожи, но названия другие
Переизмерение размеров в цикле JS заставляет пересчитывать layout. Изменения только визуальных свойств дешевле.
Движок JavaScript
Компилятор JIT переводит код в байт-код и далее в машинный. Есть горячие и холодные пути, сборщики мусора и JIT-оптимизации, которые могут «деоптимизировать» код при неожиданных типах.
# включить детальный вывод (Chrome)
# chrome://flags
# в Firefox: about:config -> javascript.options.*
Измеряйте производительность, а не гадайте: вкладка Performance записывает исполнение JS, перерисовки и сетевые запросы.
Событийный цикл
JS в браузере однопоточный. Событийный цикл обрабатывает задачи и микрозадач, поэтому длинный синхронный цикл блокирует отрисовку и ввод.
// пример: увидеть блокировку
const t = performance.now();
while (performance.now() - t < 500) {} // UI зависнет на 500 мс
// вместо этого — разбейте работу
Методы requestAnimationFrame и setTimeout позволяют вернуть управление и дать браузеру отрисовать кадр.
Безопасность и песочницы
Вкладки изолированы, JavaScript ограничен политиками источника (CSP), сетевым политикам и правам доступа. Браузер проверяет сертификаты и блокирует смешанный контент.
# посмотреть заголовки безопасности
curl -sI https://example.com | grep -iE "content-security|strict-transport|x-frame"
# политики источника в DevTools: Security
Для разработчика важно тестировать CSP заранее, иначе на продакшене сломаются скрипты.
Кэширование
Браузер кэширует ресурсы по заголовкам. Это ускоряет повторные визиты, но мешает при деплое без инвалидации кэша.
# проверить заголовки кэша
curl -sI https://example.com/style.css | grep -i cache
# форсировать обновление в браузере: Ctrl+F5
# параметр из терминала
curl -s -H "Cache-Control: no-cache" https://example.com/ | head -5
Как отлаживать
- Performance — запись сценария с таймлайном.
- Network — порядок и размер запросов.
- Elements — DOM и стили.
- Console — ошибки и логи.
- Rendering — перерисовки, FPS, layout shifts.
- Lighthouse — аудит производительности и доступности.
# Lighthouse из консоли (Chrome DevTools)
# или через CLI
npx lighthouse https://example.com --output html --output-path report.html
Как устроен рендеринг в GPU
Современные браузеры выгружают композицию в GPU. Это важно для плавности: анимации и прокрутка обрабатываются отдельным потоком. Если ускорение отключено, прокрутка становится рывками.
# в Firefox
# about:support -> Разрешения -> ускорение графики
# в Chromium
# chrome://gpu
# проверить драйвер в системе
glxinfo -B 2>/dev/null | grep -E "OpenGL renderer|OpenGL version"
При разработке CSS учитывайте, какие свойства вызывают перекомпозицию, а какие — полный layout. Инструмент Rendering в DevTools показывает это прямо на странице.
Профилирование на реальной странице
Записывайте Performance во время вашего сценария: наведение, клик, ввод. Смотрите на долгие задачи JavaScript, layout и перерисовки. Цель — убрать пикы, а не ускорить «в среднем».
# сохранить профиль
# в DevTools: Performance -> Save profile
# аудит
npx lighthouse https://example.com --quiet --output json --output-path lh.json
# посмотреть ключевые метрики
grep -oE '"(first-contentful-paint|largest-contentful-paint|cumulative-layout-shift)":[0-9.]+' lh.json
Мобильная адаптивность
Браузер адаптирует вёрстку под размер экрана: медиазапросы меняют раскладку, а вьюпорт — масштаб. Проверяйте сценарии на узких и широких экранах, иначе появятся горизонтальные прокрутки и мелкий текст.
# эмуляция в DevTools
# в разделе Device toolbar выберите шаблон
# проверить через терминал: скриншот с нужным разрешением
chromium --headless --window-size=375,812 --screenshot=mobile.png https://example.com 2>/dev/null
file mobile.png
Итог
Браузер — это сетевой стек, парсеры, движок JS и рендерер, связанные событийным циклом. Понимание шагов layout/paint/composite и событийного цикла объясняет большинство проблем с производительностью. Используйте Performance и Lighthouse, следите за кэшем и заголовками безопасности — тогда код будет предсказуемым.