@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 пишется после директивы, перед скобками с условием. В такой записи код внутри фигурных скобок будет выполнен, если указанное в круглых скобках свойство не поддерживается браузером:

        
          
          @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: 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)).