Работа с CSS селекторами это важный момент любой части Front-end разработки. Чем лучше вы их знаете, тем больше времени вы экономите себе и своим коллегам.

Перевод статьи Level up your CSS selector skills

Я использую CSS много лет, но есть одна вещь, которую я детально не рассматривал этого момента — это тема CSS селекторов.

Зачем мне это нужно? Мы уже все хорошо знаем селекторы, верно? Но проблема тут в том, что со временем можно привязаться к использованию одного и того же проверенного набора селекторов на каждом проекте, чтобы достигнуть того, что нам нужно сделать.

По-этому я взял на себя смелость провести детальное ревью CSS селекторов и пройтись по некоторым самым интересным из них, которые были новыми для меня или с которыми я просто не сталкивался прежде.

Я также открыл несколько новых, крутых селекторов, которые будут доступны в будущем, но пока что не широко поддерживаемы.

Я приглашаю вас присоединиться ко мне, чтобы посмотреть на различные типы CSS селекторов. Сколько из них вы уже используете в вашей ежедневной работе? Было бы интересно узнать.

Готовы прокачаться в плане CSS селекторов? Ок, поехали.

Комбинированные селекторы

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

Селектор главного потомка A B

Селектор прямого/непосредственного потомка A > B

Смежный селектор A + B

Родственный селектор A ~ B

Смежный селектор A + B должен уже быть вам знаком, он выбирает элемент B, который идет сразу после A. Но что по поводу родственного селектора A ~ B? Он выбирает все родственные элементы, которые идут после A. Вот их пример:

Строка New York выбрана, потому что она идет сразу же за первой строкой, а последние два города подсвечены красным, как основные родственные селекторы подходящие под все города после четвертого.

Селекторы атрибутов

Мне реально нравятся селекторы атрибутов. Они довольно гибкие, когда вам надо выбрать элементы, включающие в себя атрибуты с конкретными значениями.

Этот пример демонстрирует выборку все чекбоксов в инпуте и применение стилей к их ассоциированным лейблам, сделав их жирными и синими.

Затем мы переписываем стиль для чекбокса с именем chk2 и цвет его лейбла становится красным. Обратите внимание, как другие лейблы не подвергаются стилизации.

Селекторы атрибутов не только вообще для форм, они могут выбирать любые атрибуты на любом элементе. И вы можете выбрать любой атрибут, а не только те которые официально поддерживаются. Более того, вы можете просто проверить наличие атрибута, как написано дальше:

button[icon]

Он выбирает элементы <button>, которые содержат атрибут icon. Он выберет атрибут в не зависимости пустой или и имеет какие-то значения. Вот несколько примеров:

Первая ссылка не имеет атрибута target, так что её не выбираем. Следующие две ссылки выбираются, так как у них есть пустой атрибут target или один со значением, это не важно. И под конец, последняя ссылка становится розовой, так как выбирается из-за наличия атрибута fluffy. Её значение нерелевантно и просто должно быть само по себе, чтобы селектор a[fluffy] его выбрал.

Практический пример этого мог бы быть в подсвечивании изображений, которые не имеют атрибута alt. Этот атрибут требуется для доступности, так что он важен в целях SEO, так что вам нужно убедиться в том, что все изображения его имеют. Мы можем использовать следующее правило, чтобы этого добиться:

img:not([alt]) {
border: 2px red dashed;
}

Если вы хотите выбрать конкретную группу атрибутов, то для вас есть группа очень полезных селекторов:

A[attr^=val] Атрибуты, которые начинаются со значения val.

A[attr|=val]Атрибуты, которые начинаются со значения val или он первый в списке, разделенном тире.

A[attr*=val] — Значение появляется везде в атрибуте.

A[attr~=val] — Значение является одним из разделенным пробелом.

Первые два примера очень схожи, кроме A[attr|=val], который также выбирает значения разделенные тире. Именно это может быть полезно для выбора языковых атрибутов. Как пример <p lang=“en-us”>.

Выбор расширений файлов становится очень простым с A[attr$=“val”], а в купе с ::after вы можете легко показать совпавшие файлы. Не используя attr() и конкатенацию для совмещения их со строкой.

Со значением A[attr*val] вы можете показать любой домен, не зависимо от того, какой протокол он использует или какой субдомен у него.

И на последок, у нас есть A[attr~=val], который отлично подходит для выбора значений в атрибутах, состоящих их списка значений, разделенных пробелами. Он выбирает только целое слово, а не фрагмент, как *= оператор, так что много множества слов выбраны не будут.

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

Большинство основных браузеров поддерживает выборку чувствительную к регистру, кроме Internet Explorer и Microsoft Edge.

Селекторы пользовательского интерфейса

Если вы работали над стилизацией форм, то вы без сомнений встречали эти типы псевдо-классов:

:enabled

:disabled

:checked

Для примера, мы можем использовать :checked для стилизации простого to-do списка.

Это довольно стандартно, но к нашему распоряжению есть другие интересные псевдо-классы.

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

Мы можем использовать псевдо классы для выбора значений ввода, верны они или нет. А так же не напрямую для CSS, в таких случаях как выбор любых требуемых элементов, перед тем как форма будет отправлена.

:valid

:invalid

:required

:optional (не обязательно)

Если вы начнете писать в форму ввода адреса электронной почты, то потом оно должно стать валидным. Однако, форма ввода рабочего адреса всегда нужна и должна быть валидной, так что мы не можем оставить её пустой. Обратите внимание на то, как мы можем связывать псевдо-классы (:required:invalid), чтобы достигнуть того, что нам нужно.

Далее у нас есть два псевдо класса, которые могут подходить, если элемент формы (который поддерживает атрибуты min и max) находится в нужном диапазоне или нет.

:in-range

:out-of-range

И снова, мы можем использовать кнопку с типом reset, чтобы сбросить все до дефолтных значений чисел элемента ввода.

Завершая эту секцию, давайте взглянем на :ready-only:read-writeи :placeholder-shown псевдо-классы.

Используя их, вы сможете легко выбрать элементы, которые только для чтения или редактируемые. Таким элементам не обязательно быть только полями формы ввода, как и продемонстрировано на примере выше.

И под конец, :placeholder-shown, который выберет элементы с которыми не взаимодействовали и будет до сих пор показываться текст дефолтного плейсхолдера. Этот селектор должен использоваться очень аккуратно, так как он пока широко не распространен.

Структурные селекторы

Это очень мощные селекторы и они могут выделять элементы, основываясь на их позиции в DOM. Они дают вам гибкости в выборе элементов на чистом CSS, что могло бы с другой стороны потребовать работы с JavaScript.

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

Для примера :nth-child() получает значение, которое будет соответствовать конкретному дочернему элементу, относительно его родительского контейнера.

И так, если бы у нас был бы список элементов, то следующий селектор выбрал бы третий по списку.

ul:nth-child(3)

Однако, параметр не обязательно должен быть простым числом, он может быть простым выражением, что в свою очередь делает этот псевдокласс более мощным.

ul:nth-child(2) — Выберет второй дочерний элемент

ul:nth-child(4n) — Выберет каждый четвертый дочерний элемент (4, 8, 12, …)

ul:nth-child(2n + 1) — Выберет каждый второй дочерний элемент, начиная с первого (1, 3, 5, …)

ul:nth-child(3n — 1) — Выберет каждый третий дочерний элемент, начиная с минус первого (2, 5, 8, …)

ul:nth-child(odd) — Выберет нечетные элементы (1, 3, 5, …)

ul:nth-child(even) — Выберет четные элементы (2, 4, 6, …)

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

Вы можете использовать простые выражения со следующими структурными селекторами:

:nth-child()

:nth-last-child()

:nth-of-type()

:nth-last-of-type()

:nth-last-child() и :nth-last-of-type() очень схожи с :nth-child()и :nth-of-type(), кроме того, что они выбирают последний элемент, а не первый.

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

ul:last-of-type li:nth-last-of-type(2)::after {
content: “ (2nd from end)”;
/* Other styles… */
}

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

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

:first-child

:last-child

:only-child

:first-of-type

:last-of-type

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

Для примера, вы можете удивиться почему And so on… текст синий внутри тега <section>. На самом деле весь контент секции синий, как последний потомок главного дива — контейнера. Другие элементы секции имеют свои собственные цвета, переписанные другими селекторами, оставляя только один параграф разукрашенным в синий цвет.

Селекторы контента

Эта секция о специальном наборе селекторов для выбора контента. Для нас доступны следующие из них:

::first-line

::first-letter

::selection

::first-line и ::first-letter работают только для блочных элементов. Так же аккуратно используйте ::first-letter только на конкретных элементах, иначе каждый параграф будет буквицу, что возможно не то, чего вы хотели бы.

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

Вот список контент селекторов, за которыми стоит следить:

::inactive-selection — Выбирает контент внутри негативного окна.

::spelling-error — Проверяет грамматику и правописание для редактируемых элементов.

::grammar-error — Выбирает грамматические ошибки.

::marker — Выбирает маркеры списков.

::placeholder — Выбирает текст плейсхолдеров элементов формы.

Разнообразные селекторы

И так, у нас есть немного времени упомянуть несколько других селекторов, которые не подходят ни под одну из предидущих категорий. Не переживайте, это почти уже всё. К сожалению, большинство из них экспериментальные, так что вам нужно подождать немного перед их использованием в деле.

:target выбирает элемент с id, который соответствует части данного URL. Так что если бы у нас был элемент с id part1 и ссылка:

https://mysite.com#part1

Мы бы могли выбрать этот элемент:

:target { border: 1px red solid; }

Если у вас большой селектор, тогда :matches() сможет его упростить. Для примера, если у вас такой селектор:

nav p.content,
header p.content,
main p.content,
sidebar p.content,
footer p.content {
margin: 15px;
padding: 10px;
}

То он может быть упрощен с :matches() и эквивалентен:

:matches(nav, header, main, sidebar, footer) p:content {
margin: 15px;
padding: 10px;
}

Отлично, это поможет сделать таблицы стилей более читаемыми. Далее у нас есть :any-link, очень удобный селектор и делает тоже самое, что и :link и :visited вместе.

Так что эти два селектора были бы фактически тем же самым:

:any-link {
color: red;
}
:link, :visited {
color: red;
}

И мы подходим к последним селекторам в этой статье:

:dir()

:lang()

Оба они относятся к языку сайта.

:dir() берёт параметр ltr или rtl, в зависимости от направления текста, который вы хотите выбрать и сейчас поддерживается Firefox.

Так что :dir(rtl) выбрал бы все элементы с контентом в направлении справа на лево.

Каждый элемент в HTML документе может выставлять свой индивидуальный язык, используя атрибут lang.

<div lang=”en”>The language of this element is set to English.</div>
<div lang=”el”>Η γλώσσα αυτού του στοιχείου έχει οριστεί στα ελληνικά.</div>
<div lang=”is”>Tungumál þessa þáttar er sett á íslensku.</div>

Один и тот же простой текст введен в три дива, но с указанием страны, добавленным в конец контента. Также, коды стран используются атрибуте Lang представляя соответствующую страну.

en — Английский язык

el — Греческий язык

is — Исландский язык

Дивы могут быть выбраны по :lang селектору:

:lang(en) { color: red; }
:lang(el) { color: green; }
:lang(is) { color: blue; }

Вот демонстрация: