Кратко
СкопированоДиректива @supports
позволяет проверить, поддерживает ли браузер свойство, правило или CSS-селектор. Если условие срабатывает, то будет выполнен CSS-код, написанный внутри фигурных скобок.
Такие проверки называют feature queries.
Пример
СкопированоПроверяем, поддерживает ли браузер свойство display
со значением grid
:
/* Фолбэк */.container { display: flex;}@supports (display: grid) { .container { display: grid; }}
/* Фолбэк */ .container { display: flex; } @supports (display: grid) { .container { display: grid; } }
Как понять
СкопированоПроверка свойств с помощью @supports
нужна довольно редко, потому что:
- Большинство часто используемых CSS-свойств поддерживаются основными браузерами и дополнительно это проверять не нужно.
- В браузере есть «нативный фолбэк» — если он не понимает пару
свойство
, он просто игнорирует её и эти стили не применяются.: значение
Но иногда мы хотим использовать свойства, которые пока не обрели полную браузерную поддержку (или никогда не обретут).
Например, мы верстаем блок с display
и используем свойство grid
, которое не поддерживается в IE11 (Can I Use).В этом случае вёрстка в IE11 потеряет межблочные промежутки и будет выглядеть немного странно. Именно здесь может пригодиться @supports
:
.block { margin: 8px;}@supports (grid-gap: 8px) { .block { grid-gap: 8px; }}
.block { margin: 8px; } @supports (grid-gap: 8px) { .block { grid-gap: 8px; } }
Что получится:
- Сначала браузер считает стили вне директивы, то есть мы сразу обеспечиваем себе красивый фолбэк с помощью внешних отступов, которые поддерживаются везде (как будто ничего и не произошло).
- Дальше браузер проверит, может ли он обработать свойство
grid
со значением- gap 8px
:
- Если поддержка этого свойства есть, стили внутри директивы
@supports
применятся и перекроют наш фолбэк. - Если браузер такое свойство не поддерживает, он просто проигнорирует всё, что написано внутри директивы. Но мы помним, что ничего не сломается, потому что выше уже существует фолбэк.
Если вы знакомы с JavaScript-библиотекой Modernizr, то можно считать, что директива @supports
приводит к такому же результату, хоть и работает по-другому.
Как пишется
СкопированоПроверка правила
СкопированоВ круглых скобках после @supports
пишется свойство и его значение, которые нужно проверить:
@supports (--foo: bar) { .block { color: var(--color); }}
@supports (--foo: bar) { .block { color: var(--color); } }
Обратите внимание: даже если важно проверить только поддержку самого свойства (независимо от его значения), значение всё равно нужно указать. Иначе браузер не сможет распознать условие и проигнорирует всю директиву. Такой код не сработает:
@supports (--foo) { .block { color: var(--color); }}
@supports (--foo) { .block { color: var(--color); } }
Оператор not
СкопированоМы можем использовать логические операторы внутри директивы, чтобы строить более сложные проверки. Операторы записываются в виде ключевых слов.
Ключевое слово not
пишется после директивы, перед скобками с условием. В такой записи код внутри фигурных скобок будет выполнен, если указанное в круглых скобках свойство не поддерживается браузером:
@supports not (transform: perspective(150px)) { div { color: red; }}
@supports not (transform: perspective(150px)) { div { color: red; } }
Оператор and
СкопированоКлючевое слово and
позволяет проверить несколько условий друг за другом. Пишется между проверяемыми свойствами, вне круглых скобок. Код внутри фигурных скобок будет выполнен, если все условия верны:
@supports (transform: perspective(150px)) and (display: grid) { div { display: grid; transform: perspective(150px); }}
@supports (transform: perspective(150px)) and (display: grid) { div { display: grid; transform: perspective(150px); } }
Условий может быть больше, чем два. В этом случае их так же можно соединить через оператор and
:
@supports (transform: perspective(150px)) and (display: grid) and (color: black) { div { display: grid; transform: perspective(150px); color: black; }}
@supports (transform: perspective(150px)) and (display: grid) and (color: black) { div { display: grid; transform: perspective(150px); color: black; } }
Если условий несколько, дополнительные скобки можно опустить:
/* Вариант с дополнительными скобками вокруг 2 и 3 свойства */@supports (transform: perspective(150px)) and ((display: grid) and (color: black)) { div { display: grid; transform: perspective(150px); color: black; }}/* Вариант без дополнительных скобок, но с таким же результатом проверки */@supports (transform: perspective(150px)) and (display: grid) and (color: black) { div { display: grid; transform: perspective(150px); color: black; }}
/* Вариант с дополнительными скобками вокруг 2 и 3 свойства */ @supports (transform: perspective(150px)) and ((display: grid) and (color: black)) { div { display: grid; transform: perspective(150px); color: black; } } /* Вариант без дополнительных скобок, но с таким же результатом проверки */ @supports (transform: perspective(150px)) and (display: grid) and (color: black) { div { display: grid; transform: perspective(150px); color: black; } }
Оператор or
СкопированоКлючевое слово or
позволяет проверить несколько условий друг за другом. Код внутри фигурных скобок будет выполнен, если хотя бы одно из условий верно:
@supports (transform: perspective(150px)) or (display: grid) { div { color: #00DD00; }}
@supports (transform: perspective(150px)) or (display: grid) { div { color: #00DD00; } }
Проверяемых свойств снова может быть больше двух, а дополнительные скобки так же, как и в примере с and
, можно опустить.
Проверка селектора
СкопированоЕсли нужно проверить селектор, используется функция selector
. Ключевое слово пишется после директивы, а в скобках указывается проверяемый селектор.
Код в фигурных скобках выполняется, если указанный селектор поддерживается браузером:
@supports selector(:is(ul, ol)) { ul > li, ol > li { color: red; }}
@supports selector(:is(ul, ol)) { ul > li, ol > li { color: red; } }
Комбинирование операторов
СкопированоОператоры можно комбинировать между собой и выстраивать цепочки проверок.
@supports (transform: perspective(150px)) and ((display: grid) or (display: flex)) { div { color: #00DD00; }}
@supports (transform: perspective(150px)) and ((display: grid) or (display: flex)) { div { color: #00DD00; } }
Однако в таких цепочках условий важно следить за расстановкой скобок. В проверке выше, например, скобки опустить нельзя, иначе условие будет интерпретировано неправильно:
@supports (transform: perspective(150px)) and (display: grid) or (display: flex) { div { color: #00DD00; }}
@supports (transform: perspective(150px)) and (display: grid) or (display: flex) { div { color: #00DD00; } }
При отсутствии скобок у оператора or
проверка почти всегда будет возвращать истинное значение (поскольку display
сейчас поддерживается во всех современных браузерах), а значит код в фигурных скобках всегда будет выполняться.
Вряд ли это то, что хотелось получить от такой цепочки условий.
В такие комбинации операторов можно включать и функцию selector
:
@supports (selector(:is(ul, ol))) and (display: grid) { div:is(ul, ol) { color: #00DD00; }}
@supports (selector(:is(ul, ol))) and (display: grid) { div:is(ul, ol) { color: #00DD00; } }
Совместимость с другими директивами
СкопированоДирективу @supports
можно использовать не только на верхнем уровне CSS, но и внутри других условий.
Например, можно комбинировать с @media
— это работает как в одну сторону (@supports
внутри @media
), так и в другую (@media
внутри @supports
):
/* Такой код валиден */@supports (--foo: bar) { @media screen and (max-width: 768px) { .block { color: var(--color); } }}/* Такой код тоже валиден */@media screen and (max-width: 768px) { .block { color: #00DD00; } @supports (--foo: bar) { .block { color: var(--color); } }}
/* Такой код валиден */ @supports (--foo: bar) { @media screen and (max-width: 768px) { .block { color: var(--color); } } } /* Такой код тоже валиден */ @media screen and (max-width: 768px) { .block { color: #00DD00; } @supports (--foo: bar) { .block { color: var(--color); } } }
Браузерная поддержка
СкопированоДиректива @supports
поддерживается почти во всех последних версиях браузеров, кроме IE и Opera для Android (Can I Use). Поэтому если всё же нужно поддерживать старые браузеры, с ней стоит обращаться аккуратно.
Есть неочевидная ловушка, в которую можно попасть, если увлечься использованием @supports
. Например, у нас есть такой код:
@supports not (display: grid) { div { color: #00DD00; }}@supports (display: grid) { div { color: #00DD00; }}
@supports not (display: grid) { div { color: #00DD00; } } @supports (display: grid) { div { color: #00DD00; } }
Казалось бы, всё в порядке: браузер либо не поддерживает свойство display
и тогда выполняется код первого условия, либо поддерживает и тогда выполняется код второго.
А как быть, если браузер не поддерживает саму директиву @supports
?
На этот случай в коде выше фолбэка нет, а значит вёрстка может сломаться, поскольку ни один набор стилей не будет применён.
Поэтому лучше использовать такую конструкцию:
div { display: flex;}@supports (display: grid) { div { display: grid; }}
div { display: flex; } @supports (display: grid) { div { display: grid; } }
Сначала пишем стили для фолбэка, а уже дальше используем директиву, проверяем поддержку свойства и применяем модные-молодёжные стили, если браузер позволяет это делать 💅
Полезные материалы
СкопированоБраузерные расширения, которые помогут посмотреть на @supports
в действии и поиграть с условиями:
- Feature Queries Manager от Ире Адеринокун: плагин, добавляющий в консоль браузера вкладку, где можно посмотреть все имеющиеся на странице feature queries и поиграть с ними (для Chrome и FireFox).
- CSS Feature Toggle Extension от Кейт Кларк: плагин, позволяющий «отключать» поддержку свойств, чтобы посмотреть, как страница будет выглядеть в браузерах без поддержки этих свойств (для Chrome, Opera и Edge (Chromium)).