Медиазапросы
Сайт открывают и на телефоне шириной 360 пикселей, и на мониторе шириной 2500. Адаптивная вёрстка подстраивает страницу под любой экран: меняет число колонок, размеры и отступы. Главный её инструмент — медиазапросы.
Тег viewport
Без этого тега телефон показывает страницу уменьшенной, как на широком экране, и медиазапросы не срабатывают. Он обязателен в <head> каждой страницы:
<meta name="viewport" content="width=device-width, initial-scale=1">
<p>Теперь ширина страницы равна ширине экрана устройства.</p>Правило @media
Медиазапрос — это блок @media с условием в скобках. Правила внутри него действуют, только пока условие выполняется:
<style>
.box { padding: 16px; background: lightskyblue; }
@media (min-width: 500px) {
.box { background: gold; }
}
</style>
<div class="box">Узкое окно — голубой, широкое — жёлтый</div>Условие проверяет ширину окна, в котором показана страница. Окно примера по ширине равно колонке текста. Сузьте окно браузера, пока пример не станет уже 500 пикселей, — блок поголубеет. Удобнее всего — режим устройства в инструментах разработчика, о нём урок в конце курса.
min-width и max-width
| Условие | Когда срабатывает |
|---|---|
(min-width: 600px) | Ширина окна 600px и больше |
(max-width: 599px) | Ширина окна 599px и меньше |
(600px <= width <= 900px) | От 600 до 900 пикселей — новая запись диапазона |
Ширины, на которых раскладка меняется, называют точками перелома (breakpoints). Их выбирают по содержимому: там, где вёрстка начинает выглядеть плохо.
Сначала телефон
Удобный подход называют mobile first: сначала пишут простые стили для узкого экрана, а потом в @media (min-width: ...) дополняют их для широкого:
<style>
.cards { display: grid; gap: 8px; }
.cards div { padding: 16px; background: lightskyblue; }
@media (min-width: 500px) {
.cards { grid-template-columns: 1fr 1fr 1fr; }
}
</style>
<div class="cards">
<div>Один</div><div>Два</div><div>Три</div>
</div>На широком окне три колонки, на узком — одна. Узкая версия получилась вообще без медиазапроса.
Перестройка каркаса
Медиазапрос может поменять шаблон сетки целиком. На телефоне меню идёт над текстом, на широком экране — слева от него:
<style>
.page { display: grid; gap: 8px; grid-template-areas: "menu" "main"; }
.page > * { padding: 8px; background: honeydew; }
nav { grid-area: menu; }
main { grid-area: main; }
@media (min-width: 500px) {
.page { grid-template-columns: 120px 1fr; grid-template-areas: "menu main"; }
}
</style>
<div class="page">
<nav>Меню</nav>
<main>Содержимое страницы</main>
</div>Другие условия
Медиазапросы проверяют не только ширину. Условия соединяют словом and:
| Условие | Что проверяет |
|---|---|
(orientation: landscape) | Экран повёрнут горизонтально |
(hover: hover) | Есть мышь, на элемент можно навести |
(prefers-color-scheme: dark) | В системе включена тёмная тема |
(prefers-reduced-motion: reduce) | Пользователь попросил меньше анимации |
print | Страницу печатают: @media print |
Например, @media (min-width: 500px) and (hover: hover) сработает только на широком экране с мышью.
Частая ошибка
Медиазапрос не повышает специфичность — силу селектора. Если обычное правило стоит ниже медиазапроса, оно его перебивает, и при любой ширине ничего не меняется:
<style>
@media (min-width: 300px) {
.box { background: gold; }
}
.box { padding: 16px; background: lightskyblue; }
</style>
<div class="box">Всегда голубой: правило ниже победило</div>Пишите медиазапросы после основных стилей того же элемента.