@supports

Директива позволяет проверить, поддерживает ли браузер свойство, правило или селектор.

Время чтения: 8 мин

Кратко

Секция статьи "Кратко"

Директива @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 нужна довольно редко, потому что:

  1. Большинство часто используемых CSS-свойств поддерживаются основными браузерами и дополнительно это проверять не нужно.
  2. В браузере есть «нативный фолбэк» — если он не понимает пару свойство: значение, он просто игнорирует её и эти стили не применяются.

Но иногда мы хотим использовать свойства, которые пока не обрели полную браузерную поддержку (или никогда не обретут).

Например, мы верстаем блок с display: grid; и используем свойство grid-gap, которое не поддерживается в 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;
  }
}

        
        
          
        
      

Что получится:

  1. Сначала браузер считает стили вне директивы, то есть мы сразу обеспечиваем себе красивый фолбэк с помощью внешних отступов, которые поддерживаются везде (как будто ничего и не произошло).
  2. Дальше браузер проверит, может ли он обработать свойство 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"

Мы можем использовать логические операторы внутри директивы, чтобы строить более сложные проверки. Операторы записываются в виде ключевых слов.

Ключевое слово not пишется после директивы, перед скобками с условием. В такой записи код внутри фигурных скобок будет выполнен, если указанное в круглых скобках свойство не поддерживается браузером:

        
          
          @supports not (transform: perspective(150px)) {  div {    color: red;  }}
          @supports not (transform: perspective(150px)) {
  div {
    color: red;
  }
}

        
        
          
        
      

Оператор and

Секция статьи "Оператор 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"

Ключевое слово 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: flex сейчас поддерживается во всех современных браузерах), а значит код в фигурных скобках всегда будет выполняться.
Вряд ли это то, что хотелось получить от такой цепочки условий.

В такие комбинации операторов можно включать и функцию 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: grid и тогда выполняется код первого условия, либо поддерживает и тогда выполняется код второго.

А как быть, если браузер не поддерживает саму директиву @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)).