Руководство по недавно поддерживаемым современным селекторам псевдоклассов CSS
Опубликовано: 2022-03-10 Селекторы псевдокласса — это те, которые начинаются с символа двоеточия « :
» и соответствуют состоянию текущего элемента. Состояние может быть связано с деревом документов или в ответ на изменение состояния, например :hover
или :checked
.
:any-link
Несмотря на то, что этот псевдокласс определен в Selectors Level 4, он уже довольно давно поддерживает кроссбраузерность. Псевдокласс any-link
будет соответствовать якорной гиперссылке, если у нее есть href
. Это будет эквивалентно одновременному совпадению :link
и :visited
. По сути, это может уменьшить ваши стили на один селектор, если вы добавляете основные свойства, такие как color
, которые вы хотели бы применить ко всем ссылкам, независимо от их статуса посещения.
:any-link { color: blue; text-underline-offset: 0.05em; }
Важное замечание о специфичности заключается в том, что :any-link
выиграет у a
в качестве селектора, даже если a
расположен ниже в каскаде, поскольку он имеет специфичность класса. В следующем примере ссылки будут фиолетовыми:
:any-link { color: purple; } a { color: red; }
Поэтому, если вы вводите :any-link
, имейте в виду, что вам нужно будет включить его в экземпляры a
в качестве селектора, если они будут напрямую конкурировать за специфичность.
:focus-visible
Могу поспорить, что одним из самых распространенных нарушений доступности в Интернете является удаление outline
интерактивных элементов, таких как ссылки, кнопки и входные данные формы, для их состояния :focus
. Одной из основных целей этого outline
является служить визуальным индикатором для пользователей, которые в основном используют клавиатуру для навигации. Видимое состояние фокуса имеет решающее значение в качестве инструмента поиска пути, когда эти пользователи перемещаются по интерфейсу, и помогает усилить то, что является интерактивным элементом. В частности, видимый фокус описан в Критерии успеха WCAG 2.4.11: Внешний вид фокуса (минимум).
Псевдокласс :focus-visible
предназначен для отображения кольца фокуса только тогда, когда пользовательский агент с помощью эвристики определяет, что оно должно быть видимым. Другими словами: браузеры будут определять, когда применять :focus-visible
, основываясь на таких вещах, как метод ввода, тип элемента и контекст взаимодействия. В целях тестирования на настольном компьютере с клавиатурой и мышью вы должны видеть стили :focus-visible
, прикрепленные при переходе к интерактивному элементу, но не при щелчке по нему, за исключением ввода текста и текстовых областей, которые должны отображать :focus-visible
для всех типов ввода фокуса.
Примечание . Дополнительные сведения см. в рабочем черновике спецификации :focus-visible
.
Последние версии браузеров Firefox и Chromium, похоже, теперь обрабатывают :focus-visible
при вводе формы в соответствии со спецификацией, в которой говорится, что UA должен удалять стили : :focus
при совпадении :focus-visible
. Safari еще не поддерживает :focus-visible
, поэтому нам нужно убедиться, что стиль :focus
включен в качестве запасного варианта, чтобы избежать удаления outline
для обеспечения доступности.
Имея кнопку и ввод текста со следующим набором стилей, давайте посмотрим, что произойдет:
input:focus, button:focus { outline: 2px solid blue; outline-offset: 0.25em; } input:focus-visible { outline: 2px solid transparent; border-color: blue; } button:focus:not(:focus-visible) { outline: none; } button:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 2px #fff, 0 0 0 4px blue; }
Хром и Фаерфокс
-
input
Корректно удалите стили:focus
, когда элементы фокусируются с помощью мыши, в пользу:focus-visible
что приводит к изменениюborder-color
и скрытиюoutline
при вводе с клавиатуры. -
button
Не только использует:focus-visible
без дополнительного правила дляbutton:focus:not(:focus-visible)
, которое удаляет контур на:focus
, но и разрешает видимостьbox-shadow
только при вводе с клавиатуры
Сафари
-
input
Продолжает использовать только стили:focus
-
button
Кажется , теперь это частично соответствует назначению:focus-visible
на кнопке, скрывая стили:focus
при нажатии, но по-прежнему показывая стили:focus
при взаимодействии с клавиатурой.
Поэтому на данный момент рекомендуется продолжать включать стили :focus
, а затем постепенно расширять до использования :focus-visible
, что позволяет демонстрационный код. Вот CodePen для продолжения тестирования:
:focus-within
Псевдокласс :focus-within
поддерживается всеми современными браузерами и действует почти как родительский селектор, но только в очень специфических условиях. При прикреплении к содержащему элементу и совпадению дочернего элемента с :focus
стили могут быть добавлены к содержащему элементу и/или любым другим элементам внутри контейнера.
Практическим усовершенствованием для использования этого поведения является стилизация метки формы, когда связанный ввод имеет фокус. Чтобы это работало, мы помещаем метку и ввод в контейнер, а затем присоединяем :focus-within
к этому контейнеру, а также выбираем метку:
.form-group:focus-within label { color: blue; }
Это приводит к тому, что метка становится синей, когда ввод имеет фокус.
Эта демонстрация CodePen также включает добавление схемы непосредственно в .form-group
:
:is()
Также известный как псевдокласс «сопоставляется с любым», :is()
может принимать список селекторов для сопоставления. Например, вместо того, чтобы перечислять стили заголовков по отдельности, вы можете сгруппировать их под селектором :is(h1, h2, h3)
.
Пара уникальных особенностей списка селекторов :is()
:
- Если указанный селектор недействителен, правило будет по-прежнему соответствовать допустимым селекторам. Учитывая
:is(-ua-invalid, article, p)
, правило будет соответствоватьarticle
иp
. - Вычисленная специфичность будет равна специфичности переданного селектора с наивысшей специфичностью. Например,
:is(#id, p)
будет иметь специфичность#id
— 1.0.0 — тогда как:is(p, a)
будет иметь специфичность 0.0.1.
Ключевым преимуществом является игнорирование недопустимых селекторов. При использовании других селекторов в группе, где один селектор недействителен, браузер отбрасывает все правило. Это вступает в игру в нескольких случаях, когда префиксы поставщиков все еще необходимы, а группировка селекторов с префиксом и без префикса приводит к сбою правила во всех браузерах. С помощью :is()
вы можете безопасно сгруппировать эти стили, и они будут применяться, когда они совпадают, и игнорироваться, когда они не совпадают.
Для меня группировка стилей заголовков, как упоминалось ранее, уже является большой победой с этим селектором. Это также тот тип правила, который мне было бы удобно использовать без запасного варианта при применении некритичных стилей, таких как:
:is(h1, h2, h3) { line-height: 1.2; } :is(h2, h3):not(:first-child) { margin-top: 2em; }
В этом примере (который исходит из стилей документа в моем проекте SmolCSS) большая line-height
унаследованная от базовых стилей, или отсутствие margin-top
на самом деле не является проблемой для неподдерживающих браузеров. Это просто далеко от идеала. Для чего вы не хотели бы использовать :is()
, так это для критически важных стилей макета, таких как Grid или Flex, которые значительно контролируют ваш интерфейс.
Кроме того, при привязке к другому селектору вы можете проверить, соответствует ли базовый селектор селектору-потомку внутри :is()
. Например, следующее правило выбирает только те абзацы, которые являются прямыми потомками статей. Универсальный селектор используется как ссылка на базовый селектор p
.
p:is(article > *)
Для лучшей текущей поддержки, если вы хотите начать использовать ее, вы также захотите удвоить стили , включив повторяющиеся правила, используя :-webkit-any()
и :matches()
. Не забудьте сделать эти индивидуальные правила, иначе даже поддерживающий браузер их выбросит! Другими словами, включите все нижеперечисленное:
:matches(h1, h2, h3) { } :-webkit-any(h1, h2, h3) { } :is(h1, h2, h3) { }
На этом этапе стоит упомянуть, что наряду с самими новыми селекторами есть обновленная @supports
, которая является @supports selector
. Это также доступно как @supports not selector
.
Примечание . В настоящее время (из современных браузеров) только Safari не поддерживает это правило.
Вы можете проверить наличие поддержки :is()
с помощью чего-то вроде следующего, но на самом деле вы потеряете поддержку Safari, поскольку Safari поддерживает :is()
, но не поддерживает @supports selector
.
@supports selector(:is(h1)) { :is(h1, h2, h3) { line-height: 1.1; } }
:where()
Псевдокласс :where()
почти идентичен :is()
за исключением одного важного отличия: он всегда будет иметь нулевую специфичность. Это имеет невероятные последствия для людей, которые создают фреймворки, темы и дизайн-системы . Используя :where()
, автор может установить значения по умолчанию, а последующие разработчики могут включать переопределения или расширения без конфликта специфики.
Рассмотрим следующий набор стилей img
. Используя :where()
, даже с селектором более высокой специфичности специфичность остается нулевой. Как вы думаете, в следующем примере граница какого цвета будет у изображения?
:where(article img:not(:first-child)) { border: 5px solid red; } :where(article) img { border: 5px solid green; } img { border: 5px solid orange; }
Первое правило имеет нулевую специфичность, так как оно полностью содержится в :where()
. Таким образом, непосредственно против второго правила выигрывает второе правило. Представляя селектор только элемента img
в качестве последнего правила, он выиграет из-за каскада. Это связано с тем, что оно будет вычисляться с той же специфичностью, что и правило :where(article) img
, поскольку часть :where()
не увеличивает специфичность.
Использование :where()
вместе с резервными вариантами немного сложнее из-за функции нулевой специфичности, поскольку эта функция, вероятно, является причиной того, что вы захотите использовать ее поверх :is()
. И если вы добавите резервные правила, они, скорее всего, превзойдут :where()
из-за самой своей природы. И он имеет лучшую общую поддержку , чем @supports selector
поэтому попытка использовать его для создания резервного варианта вряд ли принесет большую (если вообще) выгоду. По сути, помните о невозможности правильно создать запасные варианты для :where()
и тщательно проверьте свои собственные данные, чтобы определить, безопасно ли начинать использовать для вашей уникальной аудитории.
Вы можете дополнительно протестировать :where()
с помощью следующего CodePen, который использует селекторы img
, указанные выше:
Улучшено :not()
Базовый селектор :not()
поддерживается начиная с Internet Explorer 9. Но селекторы уровня 4 улучшают :not()
, позволяя ему принимать список селекторов, точно так же, как :is()
и :where()
.
Следующие правила дают тот же результат в поддерживаемых браузерах:
article :not(h2):not(h3):not(h4) { margin-bottom: 1.5em; } article :not(h2, h3, h4) { margin-bottom: 1.5em; }
Способность :not()
принимать список селекторов отлично поддерживается современными браузерами.
Как мы видели с :is()
, расширенный :not()
также может содержать ссылку на базовый селектор как на потомка с использованием *
. Этот CodePen демонстрирует эту возможность, выбирая ссылки, которые не являются потомками nav
.
Бонус : предыдущая демонстрация также включает пример объединения :not()
и :is()
для выбора изображений, которые не являются соседними братьями и сестрами элементов h2
или h3
.
Предлагается, но «под угрозой» — :has()
Последний псевдокласс, который является очень захватывающим предложением, но не имеет текущего браузера, реализующего его даже экспериментально, — это :has()
. На самом деле, в редакционном черновике Selector уровня 4 он указан как «находящийся под угрозой», что означает, что у него есть трудности с завершением его реализации, и поэтому он может быть исключен из рекомендации.
В случае реализации :has()
по существу станет «родительским селектором», о котором мечтают многие специалисты по CSS. Это будет работать с логикой, похожей на комбинацию :focus-within
и :is()
с селекторами потомков, где вы ищете наличие потомков , но применяется стиль к родительскому элементу.
Учитывая следующее правило, если бы навигация содержала кнопку, то верхняя и нижняя навигация уменьшила бы отступы:
nav { padding: 0.75rem 0.25rem; nav:has(button) { padding-top: 0.25rem; padding-bottom: 0.25rem; }
Опять же, в настоящее время это не реализовано ни в одном браузере даже экспериментально, но об этом интересно подумать! Робин Рендл предоставил дополнительную информацию об этом будущем селекторе на CSS-Tricks.
Почетное упоминание с уровня 3: :empty
Полезный псевдокласс, который вы, возможно, пропустили в селекторах уровня 3, — это :empty
, который соответствует элементу, когда у него нет дочерних элементов, включая текстовые узлы.
Правило p:empty
будет соответствовать <p></p>
, но не <p>Hello</p>
.
Один из способов использования :empty
— скрыть элементы, которые, возможно, являются заполнителями для динамического содержимого, заполненного с помощью JavaScript. Возможно, у вас есть div, который будет получать результаты поиска, и когда он будет заполнен, он будет иметь рамку и некоторые отступы. Но пока нет результатов, вы не хотите, чтобы он занимал место на странице. Используя :empty
, вы можете скрыть его с помощью:
.search-results:empty { display: none; }
Возможно, вы думаете о добавлении сообщения в пустом состоянии и испытываете искушение добавить его с псевдоэлементом и content
. Подводным камнем здесь является то, что сообщения могут быть недоступны для пользователей вспомогательных технологий, которые несовместимы с тем, могут ли они получить доступ к content
. Другими словами, чтобы убедиться, что сообщение типа «нет результатов» доступно , вы можете добавить его как реальный элемент, такой как абзац ( aria-label
больше не будет доступна для скрытого элемента div).
Ресурсы для изучения селекторов
CSS имеет гораздо больше селекторов, включая псевдоклассы. Вот еще несколько мест, где можно узнать больше о том, что доступно:
- Документация по селекторам MDN CSS включает исчерпывающий список по категориям;
- Я написал руководство по расширенным селекторам CSS, состоящее из двух частей, вы можете начать с первой части;
- Получайте удовольствие от изучения селекторов CSS с помощью игры CSS Diner;
- Китти Жиродель создала инструмент объяснения селектора, который разбивает и описывает части предоставленного селектора.