Кратко
СкопированоДиректива @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)).