Feature queries в CSS
Container queries спрашивают, какова ширина родителя. Media queries смотрят на viewport. Feature queries задают совсем другой вопрос: понимает ли этот браузер данный CSS? С @supports вы отдаёте надёжную базу, а современную вёрстку или селекторы включаете только там, где движок с ними справляется.
Прогрессивное улучшение, а не ставка
Feature query — это шлюз по возможностям. Старые стили не выкидывают: оставляют раскладку, которая работает везде, а более богатый слой добавляют внутри @supports, когда движок умеет разобрать нужную возможность (например display: grid или gap во flex).
Базовый @supports
Обычная форма проверяет пару свойство–значение. Если браузер понимает это объявление, вложенные правила применяются:
.card-list {
display: block;
}
.card-list .card {
margin-bottom: 1rem;
padding: 1rem;
border: 1px solid #e2e8f0;
border-radius: 0.75rem;
background: #fff;
}
@supports (display: grid) {
.card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
gap: 1rem;
}
.card-list .card {
margin-bottom: 0;
}
}
Снаружи блока карточки складываются в столбец с простым отступом. Внутри @supports (display: grid) тот же список становится адаптивной сеткой — старые движки сохраняют столбец, современные получают grid.
Комбинация условий: and, or, not
Можно требовать несколько возможностей сразу, принимать альтернативы или инвертировать проверку:
@supports (display: grid) and (gap: 1rem) {
.toolbar {
display: grid;
grid-auto-flow: column;
gap: 0.75rem;
align-items: center;
}
}
@supports (display: flex) or (display: grid) {
.cluster {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
}
@supports not (display: grid) {
.card-list .card {
max-width: 36rem;
}
}
and сужает шлюз (должны пройти оба условия). or расширяет его. not стилизует путь без поддержки — удобно для осознанного fallback, если этот fallback действительно читаемый и полный.
Селекторы через selector()
Некоторые возможности — селекторы, а не свойства. Оберните их в selector(), чтобы запрос спрашивал: «умеешь ли разобрать этот селектор?»
.nav a {
color: #0f172a;
text-decoration: none;
}
@supports selector(:has(*)) {
.nav:has(a:focus-visible) {
outline: 2px solid #2563eb;
outline-offset: 4px;
}
.card:has(img) .title {
font-weight: 700;
}
}
Без selector() голый :has() внутри @supports — ненадёжный приём. С ним браузеры без :has() просто пропускают улучшенные правила и оставляют базовые стили ссылок.
Кто какой вопрос задаёт?
📊 Media, container, and feature queries
| Ваш вопрос | Когда уместно | Типичный инструмент |
|---|---|---|
| Насколько широк viewport / контекст устройства? | Оболочка страницы, брейкпоинты | @media (…) |
| Насколько широк этот родитель вокруг компонента? | Карточки в неравных слотах | @container (…) после container-type |
| Поддерживает ли браузер этот CSS? | Прогрессивное улучшение | @supports (…) / selector(…) |
Эти инструменты хорошо складываются: media для страницы, container для слота, @supports для возможностей. Не подменяйте брейкпоинт через @supports и не имитируйте проверку возможности через @media.
Сначала база, потом улучшение
Практичный приём: общий вид держать снаружи шлюза, а усиленную раскладку — внутри:
.feature-panel {
padding: 1.25rem;
border-radius: 0.75rem;
background: #f8fafc;
color: #0f172a;
}
.feature-panel .lead {
margin: 0 0 0.75rem;
font-size: 1.125rem;
line-height: 1.5;
}
.feature-panel .actions {
display: block;
}
.feature-panel .actions a {
display: inline-block;
margin: 0.25rem 0.5rem 0.25rem 0;
padding: 0.5rem 0.875rem;
border-radius: 0.5rem;
background: #e2e8f0;
color: inherit;
text-decoration: none;
}
@supports (display: flex) and (gap: 0.5rem) {
.feature-panel .actions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.feature-panel .actions a {
margin: 0;
}
}
Каждый браузер получает отступы, типографику и кликабельные ссылки. Flex и gap появляются только когда понятны оба — без «дыры», если чего-то не хватает.
Nesting вместе с @supports
Части Modern Toolkit сочетаются. Nesting упорядочивает селекторы; шлюз возможностей по-прежнему у @supports:
.pricing {
padding: 1rem;
border: 1px solid #e2e8f0;
}
@supports (display: grid) {
.pricing {
display: grid;
gap: 1rem;
& .tier {
padding: 1rem;
background: #fff;
}
& .tier .price {
font-size: 1.5rem;
font-weight: 700;
}
}
}
Если сам nesting не поддерживается, держите плоский эквивалент снаружи или считайте вложенную форму частью улучшенного пути — та же логика прогрессивного улучшения.
Попробуйте сами
- Стилизуйте список как простой вертикальный столбец, затем оберните Grid-раскладку в
@supports (display: grid). - Потребуйте
gapчерезand, чтобы отступы flex/grid не применялись наполовину. - Добавьте
@supports not (display: grid)с явнымmax-width— оба пути должны выглядеть намеренно. - Закройте правило с
:has()через@supports selector(:has(*)). - Не переносите весь визуал внутрь
@supports; цвет бренда и типографику оставьте в базе.
Частые ошибки
- Класть единственную рабочую раскладку внутрь
@supportsбез базы — браузеры без поддержки получают сломанную страницу - Писать
@supports (display)без значения — feature query нуждается в паре свойство–значение (или вselector(…)) - Ставить
@supportsтам, где нужен@media(или наоборот) — возможность ≠ ширина viewport - Проверять свойство, без которого база уже не живёт — шлюзуйте только улучшение
- Глубокие стопки вложенных
@supportsради мелких выигрышей — лучше один ясный улучшенный слой
Кратко
@supportsвключает CSS по возможностям браузера (feature queries)- Проверяйте
(property: value), комбинируйте черезand/or/not, для селекторов используйтеselector() - Держите крепкую базу; улучшайте, когда поддержка есть
- Тройка:
@media→ viewport,@container→ размер родителя,@supports→ возможности - Modern Toolkit здесь заканчивается — следующий модуль: Accessibility & Wrap-up (
accessibility)
🧠 Проверьте Свои Знания
Проверьте Свои Знания
Бросьте себе вызов с помощью этой интерактивной викторины и узнайте, насколько хорошо вы понимаете тему
📝 Инструкции
- Внимательно прочитайте каждый вопрос
- Выберите лучший ответ на каждый вопрос
- Вы можете пересдавать тест столько раз, сколько захотите
- Ваш прогресс будет показан вверху