:focus-visible и обратная совместимость

:focus-visible и обратная совместимость

От автора: для чего нужен focus visible? Четко видимые стили в состоянии выделения фокусом ввода важны для пользователей, работающих в основном с клавиатуры. Однако эти стили часто могут быть нежелательными, когда они применяются в результате взаимодействия мыши / указателя. Классическим примером этого являются кнопки, которые вызывают определенное действие на странице, например, перемещение кадров карусели. В то время, как нам важно, чтобы пользователь клавиатуры мог видеть, когда фокус ввода находится на кнопке, пользователя мыши могут ввести в заблуждение не те изменения стилей кнопки после клика кнопки, которых он ожидал. Он может задаться вопросом, почему стили «застревают»? Или, возможно, состояние / функционал кнопки каким-то образом изменились?

По этой причине современные браузеры применяют простую эвристику, чтобы определить, применять ли стиль фокуса ввода по умолчанию. В общем случае, если элемент был выделен фокусом ввода в результате клика мышью, браузеры опускают индикацию фокуса по умолчанию. (Примечание: некоторые браузеры используют более сложную эвристики, например, Firefox не опускает стили фокуса по умолчанию, даже в результате клика мышью, если пользователь ранее использовал TAB / SHIFT+TAB для навигации по странице).

Однако, когда авторы определяют явные стили :focus, эвристика браузера игнорируется. Стили :focus применяются каждый раз, когда элемент выделен фокусом, либо в результате взаимодействия с клавиатурой, либо мышью / указателем.

Чтобы решить эту проблему, авторам пришлось прибегать к хакерским «решениям», обычно использующим JavaScript (например, отличное What Input?).

Недавно представленный псевдо-класс :focus-visible (стандартизированная версия -moz-focusring из Firefox) предназначен для предоставления стандартизированного решения, основанного на CSS. Вместо определения традиционных стилей :focus авторы могут использовать :focus-visible, и браузеры (используя свою встроенную эвристику) будут применять эти стили только в той же ситуации, что и стили :focus по умолчанию. Обратите внимание, что на момент написания данной статьи ни в одном из браузеров еще не реализовано :focus-visible (см. информацию canisue.com по :focus-visible), но если вы «смотрите в будущее» и уже планируете использовать этот псевдо-класс чтобы воспользоваться его преимуществами после реализации в браузерах, прочитайте эту статью…

В качестве базового примера предположим, что наши текущие стили включают следующее:

button:focus { /* определенные явные стили фокуса кнопки */ }

Эти явные стили :focus настоящее время применяются каждый раз, когда кнопка выделяется фокусом. В будущем, когда браузеры начнут поддерживать :focus-visible, вместо этого мы сможем использовать:

button:focus-visible { /* определенные явные стили фокуса кнопки */ }

В принципе, авторы не смогут просто заменить:focus на :focus-visible, так как это нарушит совместимость и оставит пользователей клавиатуры без явных стилей :focus (кроме того, что по умолчанию браузер может по-прежнему применять их). В идеале нам нужно использовать :focus-visible только в браузерах, которые его поддерживают. К сожалению, поскольку :focus-visible является псевдо-классом, мы не можем использовать @supports, так как запросы функций не поддерживают их (пока?), как часть условий. Но, даже если бы это было так, то, чтобы обслуживать как неподдерживающие, так и поддерживающие браузеры, мы по существу определяли бы стили :focus как обычно, а затем удаляли бы эти стили и повторяли их снова для :focus-visible. Это рабочее решение, но не совсем красивое.

/* это на самом деле не работает, так как @supports не поддерживает псевдо-классы... но это демонстрирует, насколько неэлегантным является решение, сначала задавать, а потом отменять стили :focus */ button:focus { /* определенные явные стили фокуса кнопки */ }
@supports (:focus-visible) { button:focus { /* отменяем все указанные выше стили фокуса кнопки */ } button:focus-visible { /* и затем вновь переопределяем эти стили */ } } 

Мы можем прибегнуть к JavaScript, чтобы попытаться определить поддержку :focus-visible (например, посмотрите обсуждение на StackOverflow того, как определить, поддерживает ли браузер указанный псевдо-класс CSS), а затем динамически менять определения стилей или целые таблицы стилей … но это, кажется, не совсем соответствует цели создать решение на чистом CSS.

Наиболее жизнеспособным (хотя все еще не особенно элегантным) решением может быть использование обратного псевдо-класса :not() и (как ни парадоксально это звучит) определить стили для не :focus-visible, но отменять стили :focus, когда он отсутствует.

button:focus { /* определенные явные стили фокуса кнопки */ }
button:focus:not(:focus-visible) { /* отменяем все указанные выше стили фокуса кнопки, если кнопка выделена фокусом ввода, но браузер обычно не отображает стили фокуса по умолчанию */ } 

Обратите внимание, что это работает даже в браузерах, которые не поддерживают :focus-visible, потому что хотя :not() включает псевдо-классы, как часть списка поддерживаемых селекторов, браузеры будут игнорировать все это, если использован псевдо-класс, который они не распознают / поддерживают, что означает, что весь блок button:focus:not(:focus-visible) { … } никогда не будет применен.

Возможно, мы получим определенные преимущества от использования :focus-visible, если хотим предоставить дополнительные лучшие стили для браузеров, которые его поддерживают, поскольку мы могли бы предположить, что они будут применяться эти стили только в случае выделения фокусом ввода с клавиатуры (или, точнее, когда эвристика браузера определила, что индикация видимого фокуса подходит для данного случая). Но это все равно означало бы, что в старых / неподдерживающих браузерах мы сознательно предоставляем неидеальный опыт.

button:focus { /* определенные явные стили фокуса кнопки */ } button:focus:not(:focus-visible) { /* отменяем все указанные выше стили фокуса кнопки, если кнопка выделена фокусом ввода, но браузер обычно не отображает стили фокуса по умолчанию */ } button:focus-visible { /* определенные *еще более* явные стили фокуса кнопки */ } 

Итак, к чему мы пришли? После того, как все браузеры реализуют поддержку :focus-visible, для ситуации, когда применение отдельных стилей для элемента, выделенного фокусом ввода в результате клика мышью / указателем, считается нежелательным, мы просто будем использовать :focus-visible там, где мы раньше использовали :focus. Тем не менее, для поддержки браузеров, которые не реализуют псевдо-класс, нам придется либо использовать полифилл для поддержки :focus-visible, либо всегда использовать менее элегантный метод :not(:focus-visible) в ситуациях, когда в браузере не установлена стандартная индикация фокуса по умолчанию.

Автор: Patrick H. Lauke

Источник: https://developer.paciellogroup.com/

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