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

В этой статье я расскажу, как можно проверить, поддерживает ли браузер то или иное CSS свойство.

CSS проверка на поддержку


Долгое время проверить поддержку с помощью одного CSS было невозможно. Но в 2013 году Firefox, Chrome и Opera «объявили» о поддержки специальной директивы под названием @supports и её JavaScript аналога — функции CSS.supports(), про которую я буду писать ниже. С помощью этой директивы, можно проверить браузер на поддержку указанного CSS свойства.

Общий вид директивы

@supports (property: value) {
   /* Стили */
}

Пример использования

Если браузер поддерживает свойство display: flex, то он запустит свойства из директивы.

@supports (display: flex) {
   /* Стили */
}

Ключевое слово not

С помощью ключевого слова not, можно осуществить проверку на отсутствие поддержки какого-либо свойства.

Если браузер не поддерживает display: flex, то он запустит свойства из директивы

@supports not (display: flex) {
   /* Стили */
}

Ключевое слово or

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

Если браузер поддерживает display: flex или display: -webkit-flex, то он запустит свойства из директивы

@supports (display: flex) or (display: -webkit-flex) {
   /* Стили */
}

Ключевое слово and

Если указать ключевое слово and, то можно проверить поддержку браузером двух или более свойств сразу.

Если браузер поддерживает display: flex и display: -webkit-flex, то он запустит свойства из директивы

@supports (display: flex) and (display: -webkit-flex) {
   /* Стили */
}

Множественные проверки и условия

Если браузер поддерживает display: flex или display: -webkit-flex, и flex-wrap: wrap, то он запустит свойства из директивы

@supports ((display: flex) or (display: -webkit-flex)) and (flex-wrap: wrap) {
   /* Стили */
}

Примечание: директива @supports достаточно новая и IE её не поддерживает.

JavaScript проверка на поддержку


Есть четыре варианта на поддержку браузером CSS свойства с помощью JavaScript, про которые я знаю.

  1. С помощью функции CSS.supports(), про которую я упоминал выше.

    Технология работы функции почти не отличается от работы директивы. Отличие состоит в том, что функция CSS.supports() возвращает true, если свойство поддерживается, и false — если нет.

    Есть два варианта использования функции. Первый включает передачу двух аргументов — свойства и его значения:

    Если браузер поддерживает display: flex, то скрипт вернёт true.

    CSS.supports("display", "flex"); /* true / false */

    Второй вариант требует передачи в качестве аргумента целой строки:

    Если браузер поддерживает display: flex или display: -webkit-flex, и flex-wrap: wrap, то скрипт вернёт true.

    CSS.supports("((display: flex) or (display: -webkit-flex)) and (flex-wrap: wrap)"); /* true / false */

    Примечание: так же, как и директива @supports, эта функция новая и IE её не поддерживает.
  2. С помощью применения новых свойств элементу через JavaScript.

    Когда-то я заметил, что браузер не может установить свойству элемента значение, которое не поддерживает. Таким образом, если, после применения нового значения свойству через JavaScript, оно не изменилось, то браузер не поддерживает данное значение.

    В итоге у нас выходит следующая функция:

    var SupportsCSS = function (property, value) {
       try {
          // Создаём элемент
          var element = document.createElement('span');
          // Проверяем, поддерживает ли браузер данное свойство
          if (element.style[property] !== undefined) 
             element.style[property] = value; // Если поддерживает, то присваиваем значение
          else 
             return false; // Если нет, то возвращаем false
    
          // Если браузер поддерживает данное значение для указанного свойства, то значения будут равны
          return element.style[property] === value;
       } catch (e) {
          // В случае со старым IE, при присваивании значения, которое не поддерживается, вылетает ошибка
          return false;
       }
    };

    Или же можно обойтись без try...catch, если будем записывать свойства через cssText:

    var SupportsCSS = function (property, value) {
        // Создаём элемент
        var element = document.createElement('span');
        // Проверяем, поддерживает ли браузер данное свойство
        if (element.style[property] !== undefined)
            element.style.cssText = property + ':' + value; // Вносим новое свойство в style элемента
        else
            return false; // Если браузер не поддерживает свойство, то возвращаем false
    
        // Если браузер поддерживает данное значение для указанного свойства, то значения будут равны
        return element.style[property] === value;
    };

    Проверка с помощью этой функции выглядит следующим образом:

    SupportsCSS('display', 'flex'); /* true / false */
    SupportsCSS('display', '-webkit-flex'); /* true / false */
    SupportsCSS('display', '-ms-flexbox'); /* true / false */
    

    Преимущество данной функции в том, что она будет работать во многих браузер, в том числе старых. Я протестировал функцию в браузерах IE, Edge, старом Safari, Chrome, Opera.

    Примечание: если вы проверяете поддержку свойства в старом браузере, через эмулятор современного, то данный метод будем показывать true на значениях, которые не поддерживаются.

    Это происходит из за того, что хоть вы и эмулируете старую версию, но браузер, через который вы это делаете, знает это значение CSS свойства и может применить.

  3. С помощью других JavaScript «плюгинов».

    Для проверка на поддержку браузером CSS свойства, можно использовать готовые JS плагины. К примеру, Modernizr.
  4. С помощью парсинга User-Agent.

    Используя этот метод, мы можем определить браузер пользователя и вывести нужные значения.

Определения поддержки браузером того или иного CSS свойства позволяет более детально подстроить сайт под разные браузера и их версии. Ещё нужно помнить: чем меньше CSS кода мы используем в проекте, тем меньше мороки будет с корректировкой.

На этом закончу статью. Я рассказал про все варианты проверки, про которые знал. Если вы знаете ещё варианты — пишите про них в комментариях.

Комментарии (24)


  1. IIvana
    27.08.2017 03:53
    +2

    Никогда не был связан с вэб-девом, но недавно сделал сайт и вэб-интерфейс своему пет-проекту. Так ради прогиба под IE я был вынужден даже параметры в CSS убрать и заменить захардкоренными константами… Не представляю, как на фронте сражаются с IE. Мне вообще посоветовали не учитывать его при разработке, а уделить внимание только троице Фокс/Хром/Опера ну и Сафари может еще и мобильные варианты. Это общая тенденция? IE все игнорируют за его плохое поведение? :)


    1. MiXei4
      27.08.2017 04:12
      +2

      Если под параметрами вы имеете в виду переменные, то их никто не использует, потому что их так и не утвердили окончательно, насколько я знаю, и оно в любой момент может поменяться. Если не использовать такие «новые» инструменты, то IE работает обычно как полагается.


      1. RifleR
        27.08.2017 21:55
        +3

        Переменные в css сейчас можно спокойно использовать, если не нужна поддержка IE. Все остальные браузеры (в том числе Edge) поддерживают данный функционал. И, исходя из этого, а также из того, что статус https://www.w3.org/TR/css-variables/ — Candidate Recommendation, можно сделать вывод, что спецификация больше меняться не будет (вернее, что вероятность этого крайне мала).


      1. SelenIT3
        28.08.2017 12:13

        потому что их так и не утвердили окончательно

        Когда W3C что-нибудь «утверждает окончательно» (дает статус Recommendation), как правило, это значит, что это что-то изрядно устарело. И совершенно не значит, что это что-то не поменяется (классика — CSS2.1 стал рекомендацией лишь в 2011-м, а через год обнаружили, что в нем «забыли упомянуть» целый новый контекст форматирования, табличный:). Статус Recommendation актуален разве что для юристов-патентоведов.


        Использовать что-либо на практике W3C советует начиная со статуса кандидата в рекомендации. У CSS-переменных статус именно такой.


    1. lazyboa
      27.08.2017 12:39

      5.77% market share. Где это выливается в сколько-нибудь значимое количество посетителей, там не игнорируют.


  1. ercode
    27.08.2017 08:45
    +6

    Поддержка @supports в CSS не коррелирует с поддержкой flex.
    Конечно, применяя @supports — можно быть уверенным в том, что браузер будет гарантированно поддерживать flex. Но при этом заметный процент пользователей (чаще всего мобильных, десктопного Осла я не буду упоминать) получит вместо flex который они поддерживают, какую-то замену.
    Ну и вариант для определения: detect_flex

    По User-Agent, вы имели ввиду front end и back end?


    1. yuri_spivak Автор
      27.08.2017 08:49

      К слову, да.


    1. SelenIT3
      28.08.2017 12:18

      Пардон, но кто именно из актуальных мобильных браузеров не понимает @supports? Blackberry Browser да всё тот же осёл, только мобильный? Даже Опер-в-Мини и UC Browser, с которыми обычно больше всего проблем, как минимум в этом проблем не доставляют...


      По-моему, в мобильном царстве, с поголовным доминированием вебкита-блинка, уже довольно давно дела с поддержкой новинок в целом гораздо лучше, чем на десктопах — именно потому, что не надо учитывать старых ослов.


  1. dagen
    27.08.2017 08:46
    +1

    Кастомные css-свойства и css-переменные всё-таки разные понятия.


    И замечательно все используют, PostCSS в помощь (postcss-custom-properties), с соответствующими ограничениями, конечно. Маловероятно, что спека со статусом с 2015 года "Candidate Recommendation" изменится. А с выходом Edge 15 переменные и кастомные свойства стали реализованными во всех основных браузерах без всяких флагов.


    Глобальная поддержка у них (судя по caniuse) 69%, а на проектах нашей компании значительно выше (порядка 85%) из-за отличий в аудитории. Как только поддержка станет достаточной, можно будет включить опцию "preserve" и получить полность работоспособные динамические кастомные css-свойства.


    Цель использования кастомных css-свойств у нас — темизация общей библиотеки компонентов для разных проектов компании.


    P.S. надеюсь мой коммент не сильно устареет, прежде чем будет одобрен))


    1. dom1n1k
      27.08.2017 09:47

      И замечательно все используют, PostCSS в помощь (postcss-custom-properties), с соответствующими ограничениями, конечно.
      Это не просто ограничения. Зафолбеченные кастомные свойства просто-напросто теряют смысл до нуля. Получается просто подстановка статических значений, которая гораздо логичнее и удобнее решается средствами CSS-препроцессоров. Использовать для этого новые спецификации плюс postcss-костыли к ним — это тонкая разновидность мазохизма, по-моему. Вся польза там именно в динамике и увы, это возможно только когда есть нативная поддержка.


      1. dagen
        27.08.2017 14:55
        +3

        Ну почему же, мазохизма тут не более, чем использовать babel (что уже не первый год стандарт де-факто) — и то и то парсер+трансформер вместе с огромным выбором плагинов, которые в обоих случаях работают с предоставленным AST.

        И само собой есть браузерные ограничения, как и в случае с babel.


        1. dom1n1k
          27.08.2017 16:22
          +2

          Бабель дает хоть какие-то преимущества в обмен на лишние телодвижения. То есть имеются как плюсы, так и минусы, мазохизм выходит хотя бы не бесплатный. А уж что перевешивает — каждый решает сам.
          А в обсуждаемом случае я не смог придумать ни одного плюса.


    1. SelenIT3
      28.08.2017 12:23

      Кастомные css-свойства и css-переменные всё-таки разные понятия.

      Немного неожиданно… Или имеется в виду формальное определение, что переменные — это тип значения, а кастомные свойства — способ его задания?


  1. gdmsnsjhfjdnd
    27.08.2017 11:38

    забыли про ссылку


    https://ru.stackoverflow.com/a/710802/3158


    1. yuri_spivak Автор
      27.08.2017 11:38
      +3

      Если посмотреть на ник и аватарку, то можно заметить, что это мой вопрос и ответ :)


  1. Keyten
    28.08.2017 00:08

    Всю статью ожидал getComputedStyle, а его там нет.


    1. yuri_spivak Автор
      28.08.2017 06:07

      У меня был вариант вставить эту функцию, но там что-то не получалось и я на это плюнул.


      1. Keyten
        28.08.2017 15:03
        +2

        Скорее всего, вы забыли вставить элемент на страницу прежде чем юзать getComputedStyle.

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



        Кстати, точно таким же образом можно вычислять соотношение разных CSS-единиц (сколько px в em, например), т.к. часть величин непостоянные и зависят от разрешения экрана.


        1. yuri_spivak Автор
          28.08.2017 15:09
          -1

          Благодарю за объяснение. Но менять статью я не буду :)


          1. Keyten
            30.08.2017 12:11

            Я и не предлагал :)
            Уточнения к статье в комментариях — не редкость на хабре


  1. mwizard
    28.08.2017 05:15

    Выходит, можно при первом визите пользователя провести все тесты при помощи JS, затем отправить результат на сервер, сохранить его в cookie, и сервер сможет выдавать правильные сгенерированные стили под именно этот браузер, исходя из уровня актуальной поддержки.


  1. lxsmkv
    28.08.2017 05:54

    Спасибо, а то я все ломал голову как устроен html5test.com


  1. kiZer-pew-pew
    28.08.2017 12:18

    autoprefixer в помощь. большинство косяков с браузерами не отследишь, в частности проблемы с поведением элементов с flex-ом(процентные padding-и сверху, снизу) или например когда элемент в позиции fixed ведет себя как adsolute, или вообще остается в потоке, но это все что касается flexbox, но бывают локальные проблемы просто потому что css св-ва отрабатывают немного по разному и тут дело не в поддержке. Так что проще просто знать где что и как себя поведет.


  1. SelenIT3
    28.08.2017 14:22
    +1

    К сожалению, пока новинки только приживаются, нужно иметь в виду, что поддержка браузером свойства/значения и возможность его использовать — не одно и то же. Например, Хром с 57 версии поддерживал justify-content: space-evenly — и радостно рапортовал об этом в @supports() — но… до 61-й версии оно там работало только в гридах, но не во флексбоксах. Или @supports (display: grid), который внезапно дает true в Edge, потому что какая-никакая реализация гридов там есть (а поддержку настоящих гридов надо проверять чем-то вроде @supports (grid-area: auto)).