Як працює @supports

9 хв. читання

В CSS є чудова фіча, що дає можливість перевірити чи підтримує браузер певну властивість чи пару властивість:значення перед застосуванням відповідних стилів (подібно до того, як @media-запити визначають певні СSS-стилі в залежності від розміру вікна браузера). За тією ж логікою, визначений у блоці @supports CSS буде залучено, якщо браузер підтримує його. Поглянемо на наступний фрагмент коду:

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

Але такою фічею не варто зловживати. CSS підтримує механізм резервів (наприклад, коли браузер не сприймає пару властивість:значення, він проігнорує її та застосує властивості, визначені до цього, завдяки каскаду. @supports можна іноді використовувати для боротьби з резервними властивостями, щоб зменшити кількість коду. Але краще за все організувати свій код так, щоб непідтримувана властивість не мала значного впливу на функціонал.

@supports очевидно має свої способи використання!

Класичне застосування

Приклад на початку статті досить примітивний та напевно вже зустрічався вам у схожих статтях про @supports. Більш конкретний приклад:

/* Тут будуть резервні стилі*/
@supports (display: grid) {
  .photo-layout {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    grid-gap: 2rem;
  }
}

Повтори та автозаповнення стовпців — приємна фіча CSS grid. Але, звичайно, існують браузери, що не підтримують grid або не підтримують усі його особливості, використані вище.

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

«Я працював зі старішою версією мобільного Safari і дуже багато сайтів, що використовували grid відображались некоректно. Доведеться чекати ще близько рік, щоб користуватися ним»

Іноді прийнятно не вказувати резервні варіанти. Усе залежить від вимог. Наприклад, можемо отримати вертикально складені блокові елементи, а не макет grid з кількома стовпцями. Але це не варіант у випадку з галереєю, де потрібна базова структура сітки. У такому випадку, краще використовувати flexbox за замовчуванням та @supports для фіч grid, де вони підтримуються.

.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 не змінює специфіки застосування стилів, тому нам потрібен такий порядок коду, щоб переконатися, що перевизначення працюють.

Помітьте, тут скинуто значення margin прямо всередині блоку @supports. І це дійсно дратує. Зважаючи на те, що властивості з двох блоків перетинаються, варто розуміти як вони впливають один на одного.

Напевно, вам хотілося б, щоб вони були повністю логічно розділені...

@supports підтримує логіку not, але це не означає, що її треба постійно застосовувати

Декілька років тому Jen Simmons розмістив такий приклад у статті Використання feature queries у CSS:

/* Вважається поганою практикою, принаймні, якщо ви підтримуєте IE 11 і iOS 8 і більше */
@supports not (display: grid) {
   /* Ізольований код, якщо не підтримується grid */
}
@supports (display: grid) {
   /* Ізольований код, якщо grid підтримується*/
}

Зверніть увагу на оператор not у першому блоку. Так ми визначаємо браузери, що не підтримують grid, щоб застосувати там певні стилі. Такий підхід вважається поганою практикою, тому що треба звертати увагу на підтримку браузером безпосередньо @supports

Можливість писати код у логічно розділених блоках @supports здається дуже привабливою, тому що кожен раз ви починаєте з нуля та не повинні переписувати попередні значення. Але повернемося до ситуації з iOS, яку ми розглядали раніше. @supports підтримуються в iOS з версії 9 (одразу між підтримкою flexbox в iOS 7 та grid в iOS 10.2). Тобто будь-який резервний код з flexbox у блоці @supports, що використовує оператор not для перевірки підтримки (display: grid) {} не працюватиме як в iOS 7, так і у 8.

@supports будуть також корисними для врахування різних реалізацій чогось, в залежності від підтримки фіч браузерами. Якщо блоки коду відокремлені, різні реалізації легше розрізняти.

Ймовірно, ми дійдемо до того, що зможемо використовувати взаємовиключні блоки, не турбуючись ні про що. До речі…

@supports згодом стануть ще кориснішими

Після того, як @supports стане підтримуватись усіма основними браузерами, ви зможете активніше застосовувати цю функцію.

Як працює @supports
Браузери, що наразі підтримують @supports за даними Caniuse. Номер свідчить про мінімальну версію, яка підтримує фічу.

Проблемними залишаються IE 11 та iOS пристрої на iOS 8. Якщо ж вас влаштовують вимоги, вільно використовуйте @supports.

Іронія в тому, що не було представлено багато CSS фіч, які очевидно б потребували використання @supports. Але декілька існують: можна протестувати такі новинки, як Houdini.

Коли @supports зайвий

Часто @supports застосовують там, де він зовсім не потрібний, тому що не впливає на результат. Наприклад:

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

Здається, тут є сенс. Якщо трансформація підтримується, застосовуємо її. Але такий підхід зайвий, якщо «резервна» поведінка не передбачається. Якщо ми приберемо тут @supports, результат буде незмінним.

Розгляньте інший приклад за посиланням.

@supports та розширення для браузера

Наступні розширення допоможуть вам при роботі з @supports.

Обидва розширення працюють за принципом, відповідно до якого ми можемо створювати блоки @supports у CSS, вмикати та вимикати їх та спостерігати як рендериться код у браузері, що підтримує чи не підтримує певні фічі.

Перше розширення має дещо інший підхід: воно показує feature queries, які ви насправді пишете у своєму CSS та надає перемикач для їх вимкнення та вмикання.

Більше юзкейсів для @supports

Erik Vorhes пропонує приклад стилізації чекбоксів та радіо-кнопок з використанням блоків @supports. Ні один з блоків не застосовується, поки не проходить перевірку.

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

Ще декілька прикладів:

  • Joe Wright та Tiago Nunes пропонують використовувати фічу для position: sticky;.
  • Keith Grant та Matthias Ott вказують на використання object-fit: contain;. У демо за посиланням застосовано хитрість з позиціюванням, щоб зображення начебто заповнювало контейнер.
  • Ryan Filler використовує @supports для mix-blend-mode. Він встановлює більше значення opacity для елемента, але якщо mix-blend-mode підтримується, він змінює значення opacity.
.thing {
  opacity: 0.5;
}
@supports (mix-blend-mode: multiply) {
  .thing {
    mix-blend-mode: multiply;
    opacity: 0.75;
  }
}
  • Rik Schennink пропонує властивість backdrop-filter. За його словами необхідні деякі додаткові налаштування, якщо підтримується прозорість фону.
  • Nour Saud розповідає, що використання @supports стане у пригоді для виявлення Edge через спеціальну властивість із префіксом: @supports (-ms-ime-align:auto) { }.
  • Amber Weinberg пропонує використовувати @supports для clip-path, тому що розміри або padding елементу буде адаптуватися, якщо властивість не підтримується.
  • Ralph Holzmann розповідає про юзкейс з тестуванням змінних середовища.
  • Stacy Kvernmo вказує на використання фічі для різних властивостей, необхідних для символів буквиці. Jen Simmons також розповідає про цей юзкей у своїй статті. У CSS є властивість initial-letter, що чудово підходить для символів буквиці, але вона використовується у поєднанні з іншими властивостями, які ви не захочете застосовувати, якщо initial-letter не підтримується (або якщо резервний сценарій зовсім інший).

Як бонус від Nick Colley юзкейс з @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)
}

Щоб використовувати API, передайте властивість одним параметром, а значення — іншим.

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

Або передайте все одним параметром зі збереженням CSS-синтаксису:

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

Тестування селектора

На момент написання статті лише Firefox підтримує такий спосіб тестування (в експериментальному порядку), але це єдиний спосіб протестувати підтримку селекторів з @supports. Демо MDN:

@supports selector(A > B) {
}
Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 4.8K
Приєднався: 10 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація