Если присмотреться к большинству CSS-файлов на любом современном сайте, то рядом с обычными селекторами обязательно встретятся записи, начинающиеся с символа @: медиа-запросы, импорт сторонних стилей, описания анимаций. Всё это — так называемые at-правила (CSS at-rules). Они задают поведение всего стиля или его части и работают на уровне выше, чем привычные селекторы.
В этой статье разберём пять самых востребованных at-правил — @import, @media, @supports, @keyframes и @layer: какую задачу решает каждое, как пишется и какие нюансы стоит держать в голове. В конце коротко перечислим остальные at-правила, чтобы было, куда копать дальше.
Что такое at-правило
At-правило — это инструкция для браузера, которая начинается с @ и идентификатора. По синтаксису они делятся на две группы:
- однострочные — завершаются точкой с запятой и обычно располагаются в начале файла:
@identifier "значение"; - блочные — содержат фигурные скобки с CSS-правилами или вложенными at-правилами, часто с условием:
@identifier условие { /* CSS-правила или вложенные at-правила */ }
Полный список существующих at-правил есть на MDN. Мы остановимся на тех, которые встречаются в работе чаще всего.
Правило @import — подключение внешних стилей
Правило @import позволяет подгрузить в текущий CSS-файл другой CSS-файл. Удобно, когда стили проекта разбиты на модули — типографика, сетка, компоненты — и хочется собрать их в одну точку входа без подключения нескольких <link> в HTML.
@import url('typography.css');
@import url('grid.css');
@import url('components/buttons.css');
Пример сборки. Допустим, есть три файла: heading.css с правилами для заголовков, paragraph.css для абзацев и общий main.css, который их объединяет.
/* heading.css */
h1 {
text-decoration: underline;
color: crimson;
}
/* paragraph.css */
p {
color: midnightblue;
}
/* main.css */
@import url('heading.css');
@import url('paragraph.css');
body {
font-family: 'Inter', sans-serif;
margin: 24px;
}
В HTML подключаем только main.css, а он сам подтянет всё остальное.
Важный момент: @import-правила должны быть в самом верху файла, до обычных селекторов и блочных at-правил. Браузер скачивает импортируемые стили последовательно — сначала загрузится главный файл, затем по очереди каждый импорт. На больших проектах с десятками импортов это бьёт по производительности, поэтому в продакшене предпочитают объединять файлы на этапе сборки (Vite, Webpack), а @import оставляют для разработки или нечастых случаев. Поддерживается во всех браузерах.
Правило @media — адаптивность
Правило @media, более известное как медиа-запрос, применяет блок стилей только при выполнении заданного условия — например, ширина экрана меньше определённого значения или у устройства тёмная тема. Это базовый инструмент адаптивной вёрстки.
@media (медиа-условие) {
/* стили, которые применятся при выполнении условия */
}
Простой пример: галерея карточек, которая на широких экранах выстраивается в ряд, а на узких — в колонку.
.product-list {
display: flex;
flex-direction: row;
gap: 16px;
width: 80%;
margin: 0 auto;
}
.product-card {
flex: 1;
background: teal;
color: white;
padding: 24px;
text-align: center;
}
/* до 600px - перестраиваем в колонку */
@media (max-width: 600px) {
.product-list {
flex-direction: column;
width: 100%;
}
.product-card {
background: slategray;
}
}
/* до 360px - сужаем дополнительно */
@media (max-width: 360px) {
.product-card {
background: darkslategray;
color: lightyellow;
}
}
Правило большого пальца: при max-width-запросах их пишут от больших значений к меньшим, при min-width — наоборот, от меньших к большим. Иначе более общий запрос перепишет более узкий, и стили не сработают.
Кроме ширины экрана, @media умеет реагировать на ориентацию, плотность пикселей, предпочтения пользователя по цветовой схеме и анимациям. Подробно про последний случай мы разбирали в статье про prefers-reduced-motion.
Правило @supports — проверка возможностей браузера
Когда новая CSS-фича только-только появилась, важно дать резервный вариант для браузеров, которые её ещё не понимают. Раньше для этого использовали JavaScript-проверки и сторонние библиотеки вроде Modernizr, теперь же есть встроенный механизм — @supports. Он применяет блок стилей, только если браузер поддерживает указанное свойство со значением.
@supports (свойство: значение) {
/* стили, которые применятся, если фича поддерживается */
}
Например, проверим поддержку display: grid и зададим сетку, только если она доступна:
@supports (display: grid) {
.article-feed {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
color: navy;
}
}
Можно проверять и совсем свежие свойства — в условии браузер просто вернёт false, если не понимает запись:
@supports (scroll-timeline: auto) {
.progress-bar {
scroll-timeline: auto;
color: forestgreen;
}
}
Конструкции not, and и or позволяют комбинировать проверки. Перед тем как писать резервный сценарий, имеет смысл свериться с caniuse.com — если фича уже у 99% пользователей, оборачивать её в @supports просто не нужно.
Правило @keyframes — описание анимации
Правило @keyframes описывает сценарий анимации: какие свойства и как меняются в течение цикла. Само по себе оно ничего не запускает — чтобы сценарий заиграл, его нужно навесить на элемент через animation-свойства. Подробному разбору самих свойств у нас посвящена отдельная статья про CSS-анимации, а здесь разберём только @keyframes.
Простой случай с двумя точками описывают через from и to:
@keyframes имя-анимации {
from { /* начальное состояние */ }
to { /* конечное состояние */ }
}
Если нужно несколько промежуточных кадров, используется процентная запись:
@keyframes имя-анимации {
0% { /* стартовый кадр */ }
50% { /* середина */ }
100% { /* финальный кадр */ }
}
Живой пример: квадрат пульсирует и плавно меняет градиент по бесконечному циклу.
.pulse-card {
width: 120px;
height: 120px;
border-radius: 16px;
animation: pulse 2.4s ease-in-out infinite;
}
@keyframes pulse {
0% {
transform: scale(1);
background: linear-gradient(135deg, #6a11cb, #2575fc);
box-shadow: 0 0 0 rgba(106, 17, 203, 0.4);
}
50% {
transform: scale(1.08);
background: linear-gradient(135deg, #ff6a00, #ee0979);
box-shadow: 0 12px 32px rgba(238, 9, 121, 0.4);
}
100% {
transform: scale(1);
background: linear-gradient(135deg, #6a11cb, #2575fc);
box-shadow: 0 0 0 rgba(106, 17, 203, 0.4);
}
}
Полный интерактивный пример для @keyframes:
Правило @layer — управление каскадом
На крупных проектах рано или поздно возникает классическая боль: один селектор перекрывает другой не из-за того, что мы так задумали, а из-за более высокой специфичности. Приходится наращивать селекторы или ставить !important, и поддержка стилей превращается в борьбу.
Правило @layer (каскадные слои) предлагает другой подход: разложить стили по именованным слоям, а порядок этих слоёв задать явно. Слой, объявленный позже, имеет приоритет над предыдущими — независимо от специфичности селекторов внутри.
@layer имя-слоя {
/* CSS-правила внутри слоя */
}
Порядок слоёв задаётся отдельной директивой в самом начале файла:
@layer имя-слоя-1, имя-слоя-2, имя-слоя-3;
Здесь имя-слоя-3 — самый приоритетный, имя-слоя-1 — самый низкий.
Разберём на примере. Есть кнопка .theme-button и есть ссылка внутри основной части страницы .main-content a, которая по правилам типографики должна быть красной с подчёркиванием. Но кнопка тоже может оказаться внутри .main-content — и тогда селектор .main-content a (специфичность 0,1,1) перебивает .theme-button (0,1,0). Без слоёв:
/* типографика */
.main-content a {
color: crimson;
text-decoration: underline;
}
/* компонент */
.theme-button {
background: royalblue;
color: #fff;
padding: 8px 14px;
border-radius: 8px;
text-decoration: none;
}
Кнопка внутри .main-content приедет красной и с подчёркиванием. Со слоями проблема решается без переписывания селекторов:
@layer typography, component;
@layer typography {
.main-content a {
color: crimson;
text-decoration: underline;
}
}
@layer component {
.theme-button {
background: royalblue;
color: #fff;
padding: 8px 14px;
border-radius: 8px;
text-decoration: none;
}
}
Теперь стили из слоя component побеждают стили из typography, даже несмотря на более высокую специфичность последних. Если завтра нужно поменять приоритет — достаточно переставить имена в директиве, не трогая сами стили.
Что ещё посмотреть
Помимо разобранных выше, в спецификации есть ещё несколько at-правил, которые встречаются реже, но в нужный момент сильно выручают:
- @font-face — подключение пользовательских шрифтов с указанием формата, диапазона символов и стратегии загрузки;
- @container — контейнерные запросы, реагирующие на размер родителя, а не всего окна. Подробный разбор есть в отдельной статье;
- @property — типизированные кастомные свойства с возможностью анимации;
- @scope — ограничение области действия селектора частью DOM-дерева (полезно для виджетов и компонентов);
- @page — стили для печати и PDF-экспорта;
- @counter-style — кастомные маркеры для списков.
Итог
At-правила — это не «экзотика», а основной инструмент тех мест в CSS, где обычных селекторов не хватает: подключение модулей, реакция на устройство, фича-детекция, анимации, управление каскадом. Понимание базовой пятёрки — @import, @media, @supports, @keyframes, @layer — уже закрывает 90% задач, в которых вообще встречается символ @. Остальные правила удобно держать в фоне и доставать, когда задача под них точно подходит.
Комментарии (0)