Главная » Статьи » Как работает @supports в CSS

Как работает @supports в CSS

Как работает @supports в CSS

От автора: CSS имеет удобную функцию, которая позволяет нам проверять, поддерживает ли браузер определенное свойство или сочетание свойство: значение перед тем, как применять блок стилей — подобно тому, как обрабатывается @media-запрос, например, когда ширина окна браузера уже некоторого заданного размера, вступает в силу CSS внутри него. В том же духе CSS внутри этой функции вступит в силу, когда проверяемая пара свойство: значение поддерживается в текущем браузере.

Эта функция называется @ supports CSS, и это выглядит так:

@supports (display: grid) { .main { display: grid; }
}

Для чего? Ну, это немного сложно. Лично я считаю, что все это обычно не нужно. В CSS есть естественные механизмы отката: если браузер не понимает комбинацию свойство: значение, он будет игнорировать ее и благодаря каскаду использовать что-то объявленное перед ним, если что-то есть. Иногда это может использоваться, чтобы иметь дело с запасными вариантами, и конечный результат был немного менее расширенным. Я, конечно, не из тех парней, у которых все должно быть одинаковым в каждом браузере, но я и не из тех, кто пишет сложные резервные варианты. Я обычно предпочитаю ситуацию, когда отказ комбинации свойство: значение не влияет радикальным образом на функционал.

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

Классический вариант использования

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

/* Мы собираемся чуть ниже написать резервный вариант */ @supports (display: grid) { .photo-layout { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 2rem; }
}

Хорошая сетка! Повторение и автоматическое заполнение столбцов — приятная особенность CSS-сетки. Но, конечно, есть браузеры, которые не поддерживают Grid или поддерживают не все его функции, которые я использую выше.

Например, iOS добавила поддержку CSS-сетки в версии 10.2, но iOS имеет поддержку flexbox с версии 7. Это существенный разрыв для того, чтобы было много людей с более старыми устройствами iOS, которые поддерживают flexbox, но не grid. Я уверен, что есть и другие примеры пробелов, но вы, вероятно, поняли идею.

Может быть допустимо не оставлять запасной вариант для этого, в зависимости от требований. Например, вертикально расположенные элементы уровня блока, а не многостолбцовый макет сетки. Это часто подходит для меня. Но допустим, что это не подходит, например, для фотогалереи или чего-то, что должно иметь какую-то базовую решетчатую структуру. В этом случае лучше подойдет, если мы начнем с flexbox по умолчанию и используем @supports для применения сеточных функций там, где они поддерживаются…

.photo-layout { display: flex; flex-wrap: wrap; > div { flex: 200px; margin: 1rem; }
} @supports (display: grid) { .photo-layout { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); grid-gap: 2rem; > div { margin: 0; } }
}

«Откат» — это код вне блока @supports (свойства над блоком в приведенном выше примере), а код grid размещается либо внутри, либо ниже. Блок @supports не изменяет специфичность, поэтому нам нужен порядок источников, чтобы обеспечить, чтобы переопределение работало.

Обратите внимание, что мне пришлось сбросить поля для div внутри блока @supports. Это та вещь, которую я нахожу немного раздражающей. Между этими двумя сценариями достаточно много пересечений, поэтому требуется супер-понимание того, как они влияют друг на друга. Разве это не заставляет вас желать, чтобы это можно было полностью разделить логически…

В блоках @supports есть логика «not», но это не значит, что она должна использоваться всегда. Джен Симмонс привела этот пример в статье под названием «Использование запросов функций в CSS» несколько лет назад:

/* Рассмотрение ПЛОХОЙ ПРАКТИКИ, по крайней мере, если вы поддерживаете IE 11 и iOS 8 или старше */
@supports not (display: grid) { /* Изолированный код для браузеров, не поддерживающих grid */
}
@supports (display: grid) { /* Изолированный код для браузеров, поддерживающих grid */
}

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

Очень привлекательно писать код в таких логически разделенных блоках @supports, потому что тогда он каждый раз начинается с нуля и не нуждается в переопределении предыдущих значений и работе с этими логическими трудностями. Но давайте вернемся к той же ситуации с iOS, которую мы рассматривали ранее … @supports введен в iOS версии 9 (прямо между вводом flexbox в iOS 7 и сетки в iOS 10.2). Это означает, что любой резервный код flexbox в блоке @supports, использующем оператор not для проверки поддержки (display: grid) {}, не будет работать ни в iOS 7, ни в 8, что означает, что для резервного варианта теперь также требуется резервный вариант. Уф!

Основная причина для использования @supports — это учет очень разных реализаций чего-либо в зависимости от поддержки функций, когда становится легче рассуждать и различать эти реализации, если блоки кода разделены.

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

@supports, вероятно, будет более полезным со временем.

Когда @supports будет поддерживаться во всех браузерах, которые вам нужны, то хорошо бы начать использовать его более агрессивно и без необходимости учитывать сложность рассмотрения того, поддерживается ли собственно сам @supports. Вот данные по поддержке Grid.

По сути, IE 11 и любое iOS-устройство на iOS 8 являются болевыми точками. Если ваши требования не включают их, тогда вы можете использовать @supports более свободно.

Ирония заключается в том, что для очень немногих CSS-функций приводятся понятные варианты использования @supports, но несколько все же есть! По-видимому, можно попробовать новые модные вещи, такие как Houdini.

Когда @supports не делает ничего полезного

Я видел много случаев использования @supports, где конечный результат такой же, как и без него. Например…

@supports (transform: rotate(5deg)) { .avatar { transform: rotate(5deg); }
}

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

Существуют браузерные расширения для экспериментов с @supports. Их два!

Feature Queries Manager Ире Адеринокун

CSS Feature Toggle Extension Кита Кларка

Они оба базируются на идее, что мы можем писать блоки @supports в CSS, а затем включать и выключать их, как будто мы смотрим на рендеринг кода в браузере, который поддерживает или не поддерживает эту функцию. Вот видео инструмента Кейта, примененного к сценарию с использованием сетки и переключением на flexbox:

С этим инструментом интересно экспериментировать и все получается очень аккуратно. Но в этом конкретном сценарии, если бы мне удалось идентично оформить макет с помощью flexbox, я бы, вероятно, просто сделал это и избежал бы некоторых технических трудностей.

Инструмент Ире, о котором она писала в статье «Создание расширения DevTools Manager для запросов функций», использует несколько иной подход: он показывает запросы функций, которые вы фактически написали в своем CSS, и предоставляет переключатели для их включения и выключения. Я не думаю, что он работает через iframes, поэтому я открыл режим отладки, чтобы использовать его в CodePen.

Другие реальные примеры использования для @supports

Вот один пример от Эрика Ворхеса. Здесь он устанавливает некоторые пользовательские чек-боксы и переключатели, но все это упаковывает в блок @supports. Ни один из стилей не будет применен, если блок не пройдет проверку поддержки.

@supports (transform: rotate(1turn)) and (opacity: 0) { /* все стили для пользовательских чек-боксов и переключателей Эрика */
}

Вот еще несколько примеров, с которыми я столкнулся:

Джо Райт и Тьяго Нуньес упомянули, что используют его для position: sticky;. Я хотел бы увидеть демо! Как и в случае, когда вы используете position: sticky;, но должны сделать что-то еще, кроме того, чтобы просто оставить неработающим этот элемент в не поддерживающех браузерах.

Кит Грант и Матиас Отт упоминают, что используют его для object-fit: contain;. У Матиаса есть демонстрационная программа, в которой используется трюк позиционирования для создания изображения, заполняющего контейнер, который затем упрощается и улучшается с помощью этого свойства, когда оно доступно.

Райан Филлер упоминает об использовании @supports для mix-blend-mode. В его примере для элемента устанавливается большая непрозрачность, но, если mix-blend-mode поддерживается, он использует немного меньшую непрозрачность и это свойство, что создает интересный эффект.

.thing { opacity: 0.5;
}
@supports (mix-blend-mode: multiply) { .thing { mix-blend-mode: multiply; opacity: 0.75; }
}

Рик Щенник упоминает свойство backdrop-filter. Он говорит: «Когда оно поддерживается, непрозрачность цвета фона часто нуждается в тонкой настройке».

Нура Сауд упомянул, что @supports может быть использован для распознавания Edge через определенный вендорный префикс свойства: @supports (-ms-ime-align:auto) { }.

Эмбер Вайнберг упомянула об использовании его для clip-path, чтобы регулировать размер или отступы для элемента, когда clip-path недоступно.

Ральф Хольцманн упомянул об использовании для проверки на предмет «notch» (переменных среды).

Стейси Квернмо упомянула, что она использовала @supports для различных свойств, необходимых для сброса заглавных символов. Джен Симмонс упоминает этот вариант использования в своей статье. В CSS есть свойство initial-letter, которое фантастически работает для заглавных букв, но используется в сочетании с другими свойствами, которые вы можете вообще не захотеть применять, если не поддерживаются initial-letter (или если есть совершенно другой сценарий отката).

Вот бонусный пример от Ника Колли, в котором не используется @supports, а вместо этого используется @media! По сути то же самое. Это может предотвратить «зависание» состояния наведения на сенсорных устройствах, например:

@media (hover: hover) { a:hover { background: yellow; }
}

Логика в @supports

Основная:

@supports (initial-letter: 4) { }

not:

@supports not (initial-letter: 4) { }

and:

@supports (initial-letter: 4) and (transform: scale(2)) { }

or:

@supports (initial-letter: 4) or (-webkit-initial-letter: 4) { }

комбинации:

@supports ((display: -webkit-flex) or (display: -moz-flex) or (display: flex)) and (-webkit-appearance: caret) { }

Вариант JavaScript

В JavaScript есть API для этого. Чтобы проверить, существует ли…

if (window.CSS && window.CSS.supports) { // По-видимому старые Opera имеют странную реализацию, поэтому вы можете также сделать: // !!((window.CSS && window.CSS.supports) || window.supportsCSS || false)
}

Чтобы использовать это, передайте свойство в одном параметре, а значение в другом:

const supportsGrid = CSS.supports("display", "grid");

… или передайте все в одной строке, отражающей синтаксис CSS:

const supportsGrid = CSS.supports("(display: grid)");

Проверка селекторов

На момент написания этой статьи только Firefox поддерживает такое тестирование (с экспериментальным флагом), но есть способ протестировать поддержку селекторов с помощью @supports. Демо MDN:

@supports selector(A > B) {
}

Как насчет вас?

Конечно, мы хотели бы увидеть в комментариях множество вариантов использования @supports. Так что поделись с нами!

Автор: Chris Coyier

Источник: https://css-tricks.com/

Редакция: Команда webformyself.