Селектор псевдокласса :focus-visible
Могу поспорить, что одним из наиболее распространённых нарушений доступности в интернете, это удаление интерактивных элементов, таких как ссылок, кнопок и полей ввода форм для их состояния . Одна из основных целей — служить визуальным индикатором для пользователей использующих для навигации клавиатуру
Состояние видимого фокуса критически важно в качестве инструмента поиска путей, поскольку эти пользователи переключаются между элементами интерфейса, и помогает акцентироваться на интерактивном элементе. В частности, видимый фокус описывается в WCAG Success Criterion 2.4.11: Focus Appearance (Minimum)
Псевдокласс предназначен для отображения кольца фокуса только тогда, когда пользовательский агент с помощью эвристики определяет, что оно должно быть видимым. Другими словами: браузеры будут сами определять, когда применить видимость фокуса на основе таких вещей, как метод ввода, тип элемента и контекст взаимодействия. Для тестирования на компьютере с клавиатурой и мышью, вы должны увидеть стили, когда вы переключитесь клавишей Tab на интерактивный элемент, но не при клике мышью по нему, за исключением полей и , для которых отображается при фокусировке для всех типов ввода.
Примечание. Дополнительные сведения см. в .
Последние версии браузеров Firefox и Chromium, похоже, теперь обрабатывают в соответствии со спецификацией, в которой сказано, что UA (user agent) должен удалять стили при совпадении . Safari ещё не поддерживает , поэтому нужно убедиться, что стиль добавлен в качестве запасного варианта, что бы избежать удаления для доступности.
Присвоим кнопке и полю текстового ввода следующие стили, и посмотрим, что произойдёт:
Firefox и Chromium
input
Корректно удаляется стиль , когда фокус переместиться на элемент с помощью мыши, применится , что приведёт к смене цвета границы и скрытию обводки при переключении с клавиатуры.
button
Используется не только без дополнительного правила , которое удаляет обводку при , но и отобразиться при вводе с клавиатуры.
Safari
input
Продолжает использовать только стили.
button
Кажется, теперь частично используется на кнопке, скрывая стили при клике мышью, но по-прежнему показывая стили при переключении с клавиатуры.
Итак, на данный момент рекомендуется продолжать включать в стили , постепенно переходя на . Далее идёт пример с CodePen, с которым вы можете поэкспериментировать:
Селектор псевдокласса :any-link
Хотя этот псевдокласс , он уже довольно давно имеет кроссбраузерную поддержку. Псевдокласс будет соответствовать любой гиперссылке, если у неё есть . Он будет соответствовать одновременно обоим и одновременно. По сути, это может уменьшить количество ваших стилей на один селектор, если вы добавляете базовые свойства, такие как , который вы хотите применить ко всем ссылкам независимо от статуса их посещения.
Важное замечание о специфичности заключается в том, что селектор псевдокласса выиграет против в качестве селектора, даже если находится ниже в каскаде, поскольку он имеет специфику класса. В следующем примере, цвет ссылки будет пурпурный:. Поэтому, если вы вводите , имейте в виду, что вам нужно будет включить его в экземпляры , в качестве селектора, если они будут напрямую конкурировать за специфику
Поэтому, если вы вводите , имейте в виду, что вам нужно будет включить его в экземпляры , в качестве селектора, если они будут напрямую конкурировать за специфику.
Селектор псевдокласса :is()
Так же известный как псевдокласс «соответствовать любому», может принимать список селекторов, с которыми нужно сопоставлять. Например, вместо того, что бы перечислять стили заголовков по отдельности, вы можете сгруппировать их с помощью селектора .
Пара уникальных особенностей списка селекторов :
-
Если указанный селектор недействительный, правило по-прежнему будет соответствовать допустимым селектором. Дано: правило будет соответствовать и .
-
Вычисленная специфичность будет равна прошедшим селекторам с наивысшей специфичностью. Например, будет иметь специфичность — , тогда как: будет иметь специфичность
Первая особенность поведения, заключающаяся в игнорировании недопустимых селекторов, является ключевым преимуществом. Когда используется остальные селекторы в группе, где один не валидный, браузер выбрасывает всё правило. Это применяется в некоторых случаях, когда префиксы поставщиков по-прежнему необходимы, а группировка селекторов с префиксом и без префикса приводит к сбою правила во всех браузерах. С помощью вы можете безопасно группировать эти стили, и они будут применяться, когда совпадут и игнорироваться, когда не совпадут.
Для меня, группировка стилей заголовков, как упоминалось ранее, уже большая победа этого селектора. Это также тип правил, который мне комфортно использовать без отката, когда группируются не критичные стили, такие как:
В этом примере, взятом из , наличие большей унаследованный от базовых стилей или отсутствие не большая проблема неподдерживаемых браузеров. Это просто не идеально. Поэтому вы не хотите использовать , для критически важных стилей, таких как CSS Grid и CSS Flexbox, которые управляют вашим интерфейсом.
Кроме того, когда связан с другим селектором вы можете проверить, соответствует ли базовый селектор селекторы потомку внутри . Например, следующее правило выбирает только абзацы являющиеся прямыми потомками элемента . Универсальный селектор используется, как ссылка на базовый селектор .
Для улучшения текущей поддержки, если вы хотите начать его использовать, вам придётся продублировать стили включив дублирование правила с помощью и . Не забудьте сделать их отдельными правилами, иначе не поддерживающий браузер их просто выбросит! Другими словами, включите всё следующее:
Следует также упомянуть, что наряду с новыми селекторами есть обновлённый вариант — . Так же доступный как .
Примечание. В настоящее время (из современных браузеров) только Safari не поддерживает это at-правило.
Вы можете проверять поддержку селектора псевдокласса с помощью чего-то вроде следующего, но на самом деле вы лишаетесь поддержки Safari, поскольку Safari поддерживает , но не поддерживает .
Составные селекторы
Установить правила для элементов, удовлетворяющих сразу нескольким условиям, позволяют составные селекторы, представляющие собой последовательности простых (базовых) селекторов, записанных друг за другом без пробелов.
С помощью составных селекторов можно, например, уточнить параметры для элементов разного типа, но относящихся к одному классу:
.note { border: 1px double #ccc; box-shadow: 3px 3px 2px #ccc; font-size: 0.94em; } p.note { padding: 20px 7px 20px 30px; } div.note { padding: 5px 7px 5px 30px; }
Примечание: В составном селекторе допустим только один селектор типа или универсальный селектор. В последовательности селекторов эти селекторы должны располагаться первыми.
В следующем примере HTML-кода элемент принадлежит одновременно к трём классам: , и .
<div class="block-image aligncenter size-full"> <img src="images/figure1.gif" alt="Фото 1"> </div>
Если необходимо установить правило для подобных элементов, принадлежащих к трём классам одновременно, то это можно сделать с помощью составного селектора (см. пример ниже). При этом порядок следования имён классов в составном селекторе значения не имеет.
.block-image.size-full.aligncenter { margin: 10px; }
Псевдоэлементы для псевдоэлементов?
В одном из примеров Аны Тюдор (о котором она не так давно подробно рассказывала) в скомпилированном CSS встречается такой селектор:
input::-webkit-slider-thumb:before { // стили...
Как? Ладно, псевдоэлементы могут быть не в конце селектора. Ладно, у них могут быть состояния. Но свои псевдоэлементы?
К сожалению, увидеть именно этот селектор в работе мне так и не удалось. Но в модуле селекторов 4 уровня есть , что псевдоэлементы могут оказываться весьма непростыми:
Примером такого псевдоэлемента с внутренней структурой текущая версия спецификации приводит ::shadow. Больше нигде в этом модуле такой псевдоэлемент не упоминается. В модуле псевдоэлементов — тоже. Упоминается он только в модуле CSS Scoping 1 уровня — причем только в публичном черновике, из он пропал. За эти два года сама теневая DOM изрядно , ну и связанный с ней CSS заодно.
Так что, похоже, единственный пока псевдоэлемент, у которого могут быть настоящие полноценные потомки (!), остается нестандартным. Хотя по-прежнему работает в Chrome. По логике, раз у чего-то есть контент, то могут быть и генерируемые псевдоэлементы перед и после этого контента… но нет: никакой ::shadow::before у меня так и не заработал, да и по спецификации ::shadow не генерирует никаких боксов, отображаются только сами его потомки. По новой спецификации, правда, специальные места для вставки теневых ветвей — «слоты» — должны вести себя как элементы с display:contents, а псевдоэлементы у таких элементов (там, где он поддерживается, т.е. в Firefox) вполне отображаются. Ведь визуально они — полные аналоги настоящих потомков. Но на старую хромовскую реализацию это, разумеется, уже повлиять не может.
Так что, как бы ни хотелось мне закончить статью работающим примером псевдоэлемента для псевдоэлемента, на сегодняшний день мне пришлось в этом признать поражение. Но, как мы видели, новые черновики готовят нам массу сюрпризов, и кое-что из того, что прежде казалось немыслимым, уже работает в каком-то из браузеров (пусть за флагом и т.п.). Возможно, найти такой (или еще более невозможный) пример удастся вам? Добро пожаловать в комментарии!
Псевдоэлементы с псевдоклассами
Несколько минут назад мы выяснили, что псевдоклассы применяются к элементам, а псевдоэлементы — не элементы. Значит, псевдоэлементов со своими псевдоклассами быть не может?
Я был уверен в этом до прошлого года, когда увидел этот твит Шиме Видаса, ведущего ежедневного дайджеста webplatformdaily.org. Но пример c действительно работает в «хромоподобных» браузерах — при активации другого окна цвет выделения меняется!
Я предположил, что такой синтаксис — нововведение CSS Selectors 4, поэтому и работает только в браузерах с его поддержкой. На что Шиме указал мне на удивительную вещь: оказывается, из CSS Selectors 3 он не противоречит! Действительно, формальное определение «последовательности простых селекторов» не ограничивает числа как псевдоклассов, так и псевдоэлементов, ограничение в один псевдоэлемент на цепочку есть только в текстовом пояснении, а формального запрета на псевдоклассы после псевдоэлементов нет вообще. Практической пользы от этого знания мало, разве что лишнее напоминание о разнице между «валидностью» и «соответствием стандарту» и о том, что полагаться на валидаторы (хотя сам валидатор CSS на подобную запись как раз ругается). Но приятно чувствовать себя «почти знатоком». А заодно еще большим уважением проникаешься к создателям парсеров и анализаторов CSS, которые вынуждены постоянно это всё распутывать.
Впрочем, 3-й уровень селекторов вполне можно уже считать устаревшим (помните, что статус рекомендации у W3C означает не «готово, используйте», а скорее «используется так давно, что мы сами уже почти разобрались, как это работает»?:). Давайте снова заглянем :
То есть не для всех и не всегда… но в принципе можно! Но как же правило, что псевдоклассы применяются только к элементам? Можно сказать, что оно осталось в силе, только элементы теперь учитываются не в DOM, а в дереве отрисовки (или «», в терминах спецификации CSS Display 3 уровня).
Обратите внимание: навешивать на псевдоэлементы можно псевдоклассы только одного типа — для действий пользователя. Варианты вроде стандарт пока прямо запрещает
С одной стороны, это логично ( считают элементы в DOM, а псевдоэлементы туда не попадают), с другой — обидно, как от любого ограничения. Зато чуть понятнее, для чего вообще нужна их классификация.
Впрочем, именно для выделения в неактивном окне спецификация псевдоэлементов недавно предложила отдельный псевдоэлемент (::selection-inactive). Видимо, даже для авторов спецификации псевдокласс для псевдоэлемента — слишком уж радикальное новшество. Зато в браузерах (как минимум, Chrome, Firefox и Edge) успешно поддерживаются состояния для многих псевдоэлементов форм, типа .
Псевдоклассы и псевдоэлементы
И псевдоклассы, и псевдоэлементы были с самого начала CSS, с CSS1 (в этом году !). И там же было такое пояснение различия между ними:
Потом пришел CSS2, а за ним и CSS2.1. В июне 2011-го он с горем пополам стал стандартом, а в сентябре того же 2011-го стандартом стал модуль селекторов 3 уровня (и формально по сей день стандарт). Именно в нем у псевдоэлементов появилось двойное двоеточие. За это время приходили и уходили другие спецификации, от «вечного кандидата в рекомендации» до совсем чернового предложения от Adobe, и все они норовили прибавить что-то своё. А еще HTML5 со своими интерактивными новинками…
Но то отличие в главном по-прежнему актуально.
Любой псевдокласс соответствует какому-то элементу. Или в каком-то определенном состоянии, после каких-то действий пользователя (под фокусом, при наведении), или в каком-то определенном месте DOM-дерева (пятый в ряду, третий с конца…), или отвечает каким-то дополнительным условиям (напр. не является заголовком) — если некий элемент вдруг оказался в этом состоянии/в этом месте/с такими параметрами, к нему применится соответствующий псевдокласс. Само название указывает, что они — некое подобие классов. Как и классы, псевдоклассы можно комбинировать в каких угодно сочетаниях. У одного элемента их может быть сколько угодно (например, , причем в любом порядке.
Действующий стандарт выделяет , по не всегда понятной логике (чем :target не динамический?). В идущем ему на смену черновике CSS Selectors 4 классификацию чуть обновили:
- языковые (, )
- псевдоклассы места (все ссылочные и )
- действия пользователя (, , …)
- временные (в теории, помогут подсветить элементы по мере озвучки их скринридером, показать субтитры для видео в нужный для них момент и т.п.)
- состояния ввода (, …)
- структурные (, , …)
- новые псевдоклассы для выбора элементов по колонке таблицы или грида.
- функциональные псевдоклассы для комбинации других селекторов (, и — только б не спугнуть! — долгожданный ).
А вот псевдоэлементы — судя по названию же, лишь отдаленное подобие элементов. Они выбирают что угодно: букву, фрагмент текста с другими элементами внутри, кнопку в составном поле ввода или вообще что-то, чего и близко не было в исходном документе — только не реальный DOM-элемент. Но это непонятное что-то получит визуальное представление и займет достойное место в , а затем и на экране, наравне с настоящими элементами.
У элемента, которого нет, по идее, не может быть и соседей, тем более потомков. Поэтому в действующем стандарте (в вольном переводе):
Именно поэтому мы привыкли видеть псевдоэлементы в селекторах последними. Правда, в том же стандарте прячется осторожная оговорка, что это, возможно, не навсегда… но не будем забегать вперед.
Какие есть псевдоэлементы? Само собой, и . Чуть менее известны (хотя еще старше и работали даже в IE5!) и . Эти 4 псевдоэлемента были в CSS2 (что дает им почетное право писаться с одним двоеточием). Удивительно, но в действующем стандарте и описаны! Лишь еще вскользь упомянут. Всё пёстрое богатство разнобраузерной «псевдофауны», что мы знаем по подборкам наподобие этой, стандарт словно игнорирует.
Относительно недавно обновился черновик нового отдельного модуля псевдоэлементов 4 уровня, в котором их чуть больше и вдобавок они логически сгруппированы:
- текстовые эффекты ()
- генерируемый контент (, , ::placeholder и ::marker)
- средства для выделения и подсветки — и его друзья.
Но здесь самое время остановиться и перейти от истории и теории к практике главной темы этой статьи — отношений псевдоэлементов с псевдоклассами и друг с другом:). Начнем с самого простого!
:first-line, :first-letter
Этот селектор немного отличается от описанных выше, но если его использовать с
умом, он может очень пригодиться при проектировании внешнего вида контента и
поможет улучшить его эстетические качества. Приём выделения первой буквы или
строки применяется в дизайне печатных изданий уже много лет, взгляните на эти
. Вам также стоит ознакомится со статьей Джона Тена (Jon
Tan) под названием «12 примеров типографики абзацев», написанной еще
в 2008, в которой описано как можно получить красивые эффекты полагаясь
исключительно на селекторы.
Также вас может заинтересовать «Буквица: история применения и передовой опыт
современности в CSS», целая статья от Лауры Франц (Laura Franz),
посвященная буквице.
Селектор псевдокласса :where()
Селектор псевдокласса почти идентичен , за исключение одного критического отличия: он всегда будет иметь нулевую специфичность. Это имеет невероятные последствия для людей, создающих фреймворки, темы и дизайн-системы. Используя селектор псевдокласса , автор может установить значения по умолчанию, а последующие разработчики могут включать переопределения или расширения без противоречий в специфичности.
Рассмотрим следующий набор стилей . Используя , даже с селектором с более высокой специфичностью, специфичность остаётся нулевой. Как вы думаете, какой цвет рамки будет у изображения в следующем примере?
Первое правило имеет нулевую специфичность, поскольку содержится в селекторе псевдокласса. Итак, против второго правила — победит второе. Введя селектор в качестве последнего правила, оно побеждает благодаря каскаду. Это потому, что оно будет вычисляться с той же специфичностью, что и правило , поскольку часть не увеличивает специфичность.
Использование селектора псевдокласса вместе с резервными вариантами немного сложнее из-за нулевой специфичности, поскольку вероятно, это является причиной почему вы используете его вместо . И если вы добавите резервные правила, они, вероятно, превзойдут в силу его природы. У него лучшая поддержка чем у , поэтому попытка использовать его для создания запасного варианта вряд ли принесёт большой выигрыш. По сути, помните о невозможности правильно создать резервные правила для и внимательно проверьте свои собственные данные, чтобы определить для вашей уникальной аудитории.
Вы можете сами протестировать с правилами указанными выше:
Псевдоэлементы для псевдоклассов
Почему-то некоторые до сих пор этому удивляются. Но раз псевдокласс выбирает элемент — почему бы этому элементу не обзавестись еще и псевдоэлементом?
Простейший случай, пожалуй — особое оформление для первого/последнего элементов в ряду. Например, дорисовать стрелки для крайних пунктов подобного меню. А заодно и перекрасить эти стрелки при наведении: псевдокласс для этого взят уже другой (), но элементы-то выбираются те же самые (ссылки, в т.ч. крайние), а значит, мы фактически перекрашиваем те же самые псевдоэлементы. Что и требовалось.
Ситуаций, где псевдоэлемент нужен только при определенном динамическом состоянии, немало. Давний пример — подсветка столбцов таблицы при наведении. Или всевозможные «выкрутасы» при валидации форм. Например, вариант, когда форма не отвлекает пользователя во время добавления, но «поздравляет» его, когда всё заполнено корректно (пример). Кстати, присмотритесь к этому примеру повнимательнее: и могут быть не только с краю! Увы, этот пример не работает в IE (он не понимает ).
Предлагается, но «с риском» — :has()
Последний псевдокласс, который представляет собой очень интересное предложение, но на данный момент не реализованное даже в «экспериментальных функциях» браузеров, это — . Фактически, он внесён в , как «с риском», что означает признание испытывающим трудности с завершением его внедрения, и поэтому он может быть исключён из рекомендации.
В случае реализации , по сути будет «родительским селектором», которые многие разработчики CSS стремились сделать доступным. Он будет работать с логикой, аналогичной комбинации обоих и с дочерними селекторами, где вы ищите наличие потомков, но применённый стиль будет относиться к родительскому элементу.
Согласно следующему правилу, если бы содержал , тогда бы в уменьшились верхний и нижний :
Опять же, это не реализовано ни в одном современном браузере даже экспериментально — но об этом интересно подумать! Робин Рендел (Robin Rendle) предоставил дополнительную информацию об этом будущем селекторе на CSS-Tricks
Псевдоклассы и псевдоэлементы
Обычно стили CSS применяются к тем элементам веб-страницы, которые видны в ее исходном коде. Но существуют случаи, когда необходимо создать стиль для определенного состояния элемента (например, внешний вид посещенной ссылки либо вид ссылки при наведенном на нее курсоре), а также для элемента, который четко не обозначен в структуре страницы. Примером такого элемента может быть первый символ в абзаце или первая строка.
С помощью псевдоклассов в CSS можно устанавливать стиль для уже существующих элементов веб-страницы, который будет применяться в случае каких-то действий пользователя. Псевдоэлементы же отличаются тем, что могут определять стиль несуществующего содержимого, а также четко не обозначенных элементов.
Популярные псевдоклассы CSS
Вы можете придавать элементам стиль, который будет зависеть от состояния этих элементов. Вот список некоторых псевдоклассов:
- – этот псевдокласс задает стиль ссылкам, по которым пользователь еще не перешел;
- – этот же, наоборот, применяет стиль к уже посещенным ссылкам;
- – определяет стиль элемента, когда на него наведен курсор (может применяться не только к ссылкам);
- – задает стиль активной ссылке (то есть, в момент клика по ней);
- – применяет стиль к элементу при фокусировке на нем (например, при установке курсора в строку поиска);
- – этот полезный псевдокласс позволяет выбрать и стилизовать только те элементы, которые не содержат селектор, указанный в скобках.
Как записываются псевдоклассы CSS? Необходимо добавить стиль с названием необходимого элемента + имя псевдокласса. Пример:
a:link { color: red; } a:hover { color: #26A65B; } a:visited { color: #CCC; }
В записанном стиле сказано, что обычные, непосещённые ссылки должны быть красного цветаa:link {color: red;}, ссылка при наведении должна менять цвет на другойa:hover {color: #26A65B;}, а посещённая ссылка должна иметь третий цветa: visited {color: #CCC;}.
Популярные псевдоэлементы CSS
Если псевдоклассы записываются с одним двоеточием, то псевдоэлементы – с двумя. Это было внедрено в CSS3 для того, чтобы различать псевдоклассы и псевдоэлементы между собой. Однако раньше этой разницы не существовало и с псевдоэлементами использовалось одно двоеточие. Сейчас браузеры поддерживают оба варианта написания (но не для всех случаев). Рассмотрим некоторые псевдоэлементы:
- – используется вместе со свойством и позволяет вывести необходимые данные после содержимого элемента;
- – выполняет похожую функцию, что и предыдущий, только выводит данные перед содержимым элемента;
- – этот псевдоэлемент распознается браузерами только при использовании двух двоеточий и позволяет установить цвет и фон для текста, который выделен пользователем;
- – используется для изменения стиля первого символа в тексте элемента;
- – используется для изменения стиля первой строки текста элемента.
Пример использования псевдоэлементов:
blockquote::before { content: "«"; } blockquote::after { content: "»"; } blockquote::selection { color: #C8F7C5; background-color: #1E824C; }
Мы написали стиль для длинных цитат, который добавляет кавычки «ёлочки» в начале и в конце содержимого тега , а также изменяет цвет и фон выделенного пользователем текста цитаты.
Выводы
В этой главе вы узнали о таких важных и часто используемых в CSS вещах, как селекторы потомков, псевдоклассы и псевдоэлементы. В дальнейшем мы будем часто к ним возвращаться, поэтому запомните основные моменты по пройденной теме:
Благодаря селекторам потомков вам доступны гибкие и компактные настройки CSS-стилей.
Псевдоклассы позволяют создавать стиль для различных состояний элемента веб-страницы.
С помощью псевдоэлементов в CSS можно задать стиль для тех элементов страницы, которые четко не обозначены в структуре документа.
Следующая часть главы – о дочерних селекторах.
:empty и :only-child()
Они входят в список структурных псевдоклассов, однако именно эти два почему-то
менее популярны, хоть и довольно полезны.
Псевдокласс пригодится когда нужно прописать больший/меньший
отступ/границу для тех элементов, которые содержат только один дочерний элемент,
или же вы можете уменьшить размер шрифта если элемент содержит несколько
дочерних элементов.
Синтаксис:
Пример:
По сути этот селектор эквивалентен .
Синтаксис:
Учтите, что даже переход на новую строку считается текстовым узлом, помните об
этом в процессе проектирования структуры страницы.
Пример:
Больше о них и о других можно прочитать в разделе .