CSS - Селекторы
Содержание
Обзор
CSS действительно хорош во многих вещах, но он действительно, действительно хорош в двух конкретных вещах: выборе элементов и придании им стиля. В этом смысл существования CSS и причина, по которой он является основным веб-языком. В этом руководстве мы рассмотрим различные способы выбора элементов, потому что стили, которые мы пишем, практически бесполезны без возможности выбирать, к каким элементам их применять.
Источник достоверной информации о селекторах CSS описан в спецификации модуля селекторов уровня 4. За одним исключением (о котором мы поговорим позже), все рассмотренные здесь селекторы хорошо поддерживаются всеми браузерами, и уж точно всеми современными браузерами.
Помимо селекторов, в этом руководстве также рассматриваются комбинаторы CSS. Если селекторы определяют, что мы выбираем, то комбинаторы можно рассматривать как то, как применяются стили. Комбинаторы — это дополнительные инструкции, которые мы даём CSS для выбора определённого элемента на странице. Это похоже на то, как мы используем фильтры в поисковых системах, чтобы найти нужный результат.
Краткая справка
Общие Селекторы
/* Universal */
* { box-sizing: border-box; }
/* Type or Tag */
p { margin-block: 1.5rem; }
/* Classname */
.class { text-decoration: underline; }
/* ID */
#id { font-family: monospace; }
/* Relational */
li:has(a) { display: flex; }
Распространенные Комбинаторы
/* Descendant */
header h1 { /* Выбирает все элементы H1 в элементе header */ }
/* Child */
header > h1 { /* Выбирает все элементы H1, которые являются дочерними элементами элементов header */ }
/* General sibling */
h1 ~ p { /* Выбирает абзац, если он следует за H1 */ }
/* Adjacent sibling */
h1 + p { /* Выбирает абзац, если он следует сразу за H1 */ }
/* Chained */
h1, p { /* Выбирает оба элемента */ }
Общие Селекторы
Когда мы говорим о селекторах CSS, мы имеем в виду первую часть набора правил CSS:
/* Набор правил CSS */
selector {
/* Правило стиля */
property: value;
}
Например, давайте выберем все <article>
элементы на заданной странице.
/* Выбрать все <article> элементы ... */
article {
/* ... и применить к ним этот фоновый цвет */
background-color: hsl(25 100% 50%);
}
Это общий процесс выбора элементов для применения к ним стилей. Выбор элемента по его HTML-тегу — это лишь один из типов селекторов. Давайте рассмотрим их в следующем разделе.
Селекторы элементов
Селекторы элементов — это именно тот тип селекторов, который мы рассматривали в последнем примере: выберите HTML-тег элемента и приступайте к оформлению!
Это здорово и всё такое, но подумайте вот о чём: действительно ли вы хотите выбрать все элементы <article>
на странице? Именно это мы и делаем, когда выбираем элемент по его тегу — все HTML-элементы, соответствующие этому тегу, получают стили. В следующей демонстрации мы выбираем все элементы <article>
на странице, а затем применяем к ним белый (#fff
) фон. Обратите внимание, что все три статьи получают белый фон, хотя мы написали только один селектор.
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Но, возможно, на самом деле мы хотим, чтобы у первого элемента был другой фон — может быть, это выделенный фрагмент контента, и нам нужно, чтобы он выделялся на фоне других статей. Для этого нам нужно быть более конкретными в выборе селектора для применения стилей.
Давайте обратимся к другим типам селекторов, которые позволяют более точно указать, что мы выбираем.
Cелекторы идентификаторов
Идентификаторы — это один из способов выбрать элемент, не выбирая другой элемент того же типа. Допустим, мы обновили HTML в нашем <article>
примере так, чтобы первая статья была «помечена» идентификатором:
<article id="featured">
<!-- Article 1 -->
</article>
<article>
<!-- Article 2 -->
</article>
<article>
<!-- Article 3 -->
</article>
Теперь мы можем использовать этот идентификатор, чтобы отличить первую статью от остальных и применить к ней специальные стили. При написании селектора CSS мы добавляем символ хэштега (#
) к имени идентификатора, чтобы правильно его выбрать.
/* Выбрать все <article> элементы */
article {
background: #fff;
}
/* Выбирает любой элемент с id="featured" */
#featured {
background: hsl(35 100% 90%);
border-color: hsl(35 100% 50%);
}
Вот так, теперь первая статья выделяется чуть больше остальных!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Прежде чем вы побежите добавлять идентификаторы по всему HTML-коду, имейте в виду, что идентификаторы считаются грубым подходом к выбору. Идентификаторы настолько специфичны, что их сложно переопределить другими стилями в CSS. Идентификаторы настолько специфичны, что любой селектор, пытающийся их переопределить, должен иметь как минимум идентификатор. Как только вы достигаете вершины этой войны за специфичность, это, как правило, приводит к использованию !important
правил и тому подобного, которые, в свою очередь, практически невозможно переопределить.
Давайте изменим CSS из последнего примера, чтобы увидеть это в действии:
/* Выбрать все элементы с id="featured" */
#featured {
background: hsl(35 100% 90%);
border-color: hsl(35 100% 50%);
}
/* Выбрать все элементы <article> */
article {
background: #fff;
}
Селектор идентификатора теперь стоит перед селектором элемента. В соответствии с тем, как каскад CSS определяет стили, можно было бы ожидать, что все элементы статьи получат белый фон, поскольку этот набор правил стоит после набора правил селектора идентификатора. Но этого не происходит.
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Итак, вы видите, что идентификаторы могут быть немного слишком «конкретными», когда дело доходит до выбора элементов, потому что это влияет на порядок применения стилей в каскаде CSS, что усложняет управление и поддержку стилей.
Другая причина, по которой следует избегать идентификаторов в качестве селекторов? Технически нам разрешено использовать идентификатор только один раз на странице, для каждого идентификатора. Другими словами, у нас может быть один элемент с #featured
идентификатором, но не два. Это сильно ограничивает возможности стилизации, если нам нужно распространить эти стили на другие элементы, не говоря уже о сложности переопределения стилей идентификатора.
Лучше использовать идентификаторы для выбора элементов в JavaScript. Это не только предотвращает конфликты стилей, которые мы видели выше, но и помогает разделить задачи между тем, что мы выбираем в CSS для оформления, и тем, что мы выбираем в JavaScript для взаимодействия.
Ещё кое-что о селекторах ID: идентификатор устанавливает то, что мы называем «якорем» — это модный термин, обозначающий, что мы можем напрямую ссылаться на элемент на странице. Например, если у нас есть статья с присвоенным ей идентификатором:
<article id="featured">...</article>
... тогда мы можем создать ссылку на него следующим образом:
<a href="featured"> Перейти к статье ниже ⬇️</a>
<!-- дальше по странице -->
<article id="featured">...</article>
При нажатии на ссылку вы перейдёте к элементу, как если бы ссылка была привязана к этому элементу. Попробуйте сделать то же самое в следующем примере:
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Эта маленькая HTML-штучка открывает перед нами довольно интересные возможности, если добавить немного CSS. Вот несколько статей, в которых рассматриваются эти возможности.
Селекторы классов
Селекторы классов могут быть наиболее часто используемым типом селекторов CSS, которые вы увидите в интернете. Классы идеальны, потому что они немного более конкретны, чем селекторы элементов, но без излишней громоздкости идентификаторов. Ниже приведена сокращённая иллюстрация, в которой основное внимание уделяется конкретно типам селекторов, которые мы рассмотрели.
Именно это делает селекторы классов такими популярными — они лишь немного более специфичны, чем элементы, но сохраняют достаточную низкую специфичность, чтобы ими можно было управлять, если нам нужно переопределить стили в одном наборе правил стилями из другого.
Единственное отличие при написании класса заключается в том, что перед названием класса мы ставим точку (.
) вместо хэштега (#
).
/* Выбрать все <article> элементы */
article {
background: #fff;
}
/* Выбирает любой элемент с class="featured" */
.featured {
background: hsl(35 100% 90%);
border-color: hsl(35 100% 50%);
}
Вот как выглядит наш пример <article>
при замене #featured
на .featured
.
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Тот же результат, но с большей специфичностью. И да, мы можем комбинировать разные типы селекторов для одного и того же элемента:
<article id="someID" class="featured">...</article>
Вы видите все возможности, которые у нас есть для выбора<article>
? Мы можем выбрать его с помощью:
- Тип его элемента (
article
) - Его идентификатор (
#someID
) - Его класс (
.featured
)
В следующих статьях вы найдёте несколько полезных идей по использованию селекторов классов в CSS.
Но у нас есть ещё больше способов выбрать такие элементы, так что давайте продолжим.
Селекторы атрибутов
Селекторы идентификаторов и классов технически относятся к этой категории селекторов атрибутов. Мы называем их «атрибутами», потому что они присутствуют в HTML и дают больше информации об элементе. Все нижеперечисленное является атрибутами в HTML:
<!-- ID, Class, Data Attribute -->
<article id="#id" class=".class" data-attribute="attribute">
</article>
<!-- href, Title, Target -->
<a href="https://css-tricks.com" title="Visit CSS-Tricks" target="_blank"></a>
<!-- src, Width, Height, Loading -->
<img src="star.svg" width="250" height="250" loading="laxy" >
<!-- Type, ID, Name, Checked -->
<input type="checkbox" id="consent" name="consent" checked />
<!-- Class, Role, Aria Label -->
<div class="buttons" role="tablist" aria-label="Tab Buttons">
В этом примере кода всё, что начинается со знака равенства (=
), за которым следует значение, является атрибутом. Таким образом, технически мы можем стилизовать все ссылки с помощью атрибута href
со значением https://iniksite.ru
a[href="https://iniksite.ru"] {
color: orangered;
}
Обратите внимание на синтаксис? Мы используем квадратные скобки ([]
) для выбора атрибута вместо точки или хэштега, как в случае с классами и идентификаторами соответственно.
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Знак равенства, используемый в атрибутах, говорит о том, что мы можем делать больше, чем просто сопоставлять что-то, что в точности равно значению. Так и есть. Например, мы можем убедиться, что соответствующий селектор написан с заглавной или со строчной буквы. Это можно использовать для выбора элементов с атрибутом href
при условии, что они не содержат заглавных букв:
/* Case sensitive */
a[href*='iniksite' s] {}
s
в этом месте сообщает CSS, что мы хотим выбрать только ссылку с атрибутом href
, который не содержит заглавных букв.
<!-- Нет совпадений -->
<a href="https://iniksite.ru">...</a>
<!-- Соответствует! -->
<a href="https://iniksite.ru">...</a>
Если регистр не имеет большого значения, мы можем указать это и в CSS:
/* Case insensitive */
a[href*='iniksite' i] {}
Теперь любой из примеров ссылок будет соответствовать независимо от того, есть ли в атрибуте href
прописные или строчные буквы.
<!-- Я совпадаю! -->
<a href="https://iniksite.ru">...</a>
<!-- Я совпадаю тоже! -->
<a href="https://iniksite.ru">...</a>
Существует множество различных типов HTML-атрибутов. Обязательно ознакомьтесь с нашим руководством по атрибутам данных, чтобы получить полное представление не только о [data-attribute]
том, как они связаны с другими атрибутами, но и о том, как стилизовать их с помощью CSS .
Универсальный селектор
Верно, символ звёздочки (*
) сам по себе является селектором, цель которого — выбирать всё подряд. Буквально, мы можем выбрать всё на странице — каждый элемент — с помощью этой маленькой звёздочки. Обратите внимание, что я сказал «каждый элемент», поэтому это не сработает с идентификаторами, классами или даже псевдоэлементами. Это селектор для выбора всех элементов.
/* Выберите ВСЕ ВЕЩИ! */
* {
/* Styles */
}
Или мы можем использовать его с другим типом селектора, чтобы выбрать всё, что находится внутри определённого элемента.
/* Выберите все в <article> */
article * {
/* Styles */
}
Это удобный способ выбрать всё в <article>
даже в будущем, если вы решите добавить другие элементы внутри этого элемента в HTML. Чаще всего универсальный селектор используется для установки border-sizing
для всех элементов, включая все элементы и псевдоэлементы.
*,
*::before,
*::after {
box-sizing: border-box;
}
Есть веская причина, по которой этот фрагмент CSS используется во многих таблицах стилей, и вы можете прочитать о ней в следующих статьях.
Иногда подразумевается универсальный селектор. Например, при использовании псевдоселектора в начале нового селектора. Они выбирают одно и то же:
*:has(article) { }
:has(article) { }
Псевдоселекторы
Псевдоселекторы предназначены для выбора псевдоэлементов, так же как селекторы элементов предназначены для выбора элементов. Псевдоэлемент похож на элемент, но на самом деле он не отображается в HTML. Если вы впервые слышите о псевдоэлементах, у нас есть краткое объяснение, на которое вы можете сослаться.
К каждому элементу прикреплён псевдоэлемент ::before
и ::after
, даже если мы не видим его в HTML.
<div class="container">
<!-- ::before psuedo-element here -->
<div>Item</div>
<div>Item</div>
<div>Item</div>
<!-- ::after psuedo-element here -->
</div>
Это очень удобно, потому что это дополнительные способы, с помощью которых мы можем подключить элемент и применить дополнительные стили, не добавляя разметку в HTML. Старайтесь, чтобы всё было как можно чище, верно?!
Мы знаем, что ::before
и ::after
— это псевдоэлементы, потому что перед ними стоит пара двоеточий (::
). Именно так мы их и выбираем!
.container::before {
/* Styles */
}
Псевдоэлементы ::before
и ::after
также могут быть записаны с помощью одной двоеточной черты — то есть :before
и :after
— но чаще всего используется двойная двоеточная черта, поскольку она помогает отличить псевдоэлементы от псевдоклассов.
Но при использовании псевдоселекторов есть одна загвоздка: они требуют наличияcontent
свойства. Это связано с тем, что псевдоэлементы — это не «настоящие» элементы, а те, которые не существуют с точки зрения HTML. Это означает, что им нужен контент, который можно отобразить… даже если это пустой контент:
.container::before {
content: "";
}
Конечно, если бы мы вставили слова в свойство content
, они отобразились бы на странице.
Сложные селекторы
Сложным селекторам может потребоваться небольшая помощь в продвижении, потому что «сложный» — это очень пугающий термин, с которым вы можете столкнуться на начальном этапе изучения этого материала. Хотя селекторы действительно могут стать сложными и запутанными, общая идея предельно проста: мы можем комбинировать несколько селекторов в одном наборе правил.
Давайте рассмотрим три разных способа написания этих «не таких уж сложных» сложных селекторов.
Список селекторов
Во-первых, можно комбинировать селекторы так, чтобы они использовали один и тот же набор стилей. Для этого нужно разделить каждый селектор запятой.
.selector-1,
.selector-2,
.selector-3 {
/* Мы разделяем эти стили! */
}
Вы часто будете сталкиваться с этим при оформлении заголовков, которые, как правило, имеют одинаковый общий стиль, за исключением, возможно, font-size
.
h1,
h2,
h3,
h4,
h5,
h6 {
color: hsl(25 80% 15%);
font-family: "Poppins", system-ui;
}
Добавление разрыва строки между селекторами может сделать текст более понятным. Вы, вероятно, можете себе представить, насколько сложным и запутанным это может стать. Вот один из примеров:
section h1, section h2, section h3, section h4, section h5, section h6,
article h1, article h2, article h3, article h4, article h5, article h6,
aside h1, aside h2, aside h3, aside h4, aside h5, aside h6,
nav h1, nav h2, nav h3, nav h4, nav h5, nav h6 {
color: #BADA55;
}
М-м-м, ладно. Никому не нужно это в таблице стилей. Трудно понять, что именно выбрано, верно?
Хорошая новость в том, что у нас есть современные способы более эффективного объединения этих селекторов, например, с помощью псевдоселектора :is()
. В этом примере обратите внимание, что технически мы выбираем одни и те же элементы. Если бы мы убрали четыре селектора section
, article
, aside
, nav
, а потомки остались, то получилось бы следующее:
h1, h2, h3, h4, h5, h6,
h1, h2, h3, h4, h5, h6,
h1, h2, h3, h4, h5, h6,
h1, h2, h3, h4, h5, h6, {
color: #BADA55;
}
Единственная разница заключается в том, к какому элементу относятся эти заголовки. Здесь :is()
пригодится, потому что мы можем сопоставить эти четыре элемента следующим образом:
:is(section, article, aside, nav) {
color: #BADA55;
}
Это применится color
к самим элементам, но мы хотим применить это к заголовкам. Вместо того, чтобы перечислять их для каждого заголовка, мы можем снова воспользоваться :is()
и выбрать их одним махом:
/* Matches any of the following headings scoped to any of the following elements. */
:is(section, article, aside, nav) :is(h1, h2, h3, h4, h5, h6) {
color: #BADA55;
}
Пока мы говорим о :is()
, стоит отметить, что у нас также есть :where()
псевдоселектор, и что он делает то же самое, что и :is()
. В чем разница? Специфичность :is()
будет равна специфичности самого специфичного элемента в списке. При этом :where()
сохраняется нулевая специфичность. Итак, если вам нужен подобный сложный селектор, который легче переопределить, используйте :where()
вместо этого.
Селекторы вложенности
Последний пример, показывающий, как :is()
можно использовать для написания более эффективных сложных селекторов, хорош, но теперь, когда вложенность CSS является широко поддерживаемой функцией, мы можем сделать ещё лучше.
Вложенность CSS позволяет лучше видеть взаимосвязь между селекторами. Знаете, как можно чётко увидеть взаимосвязь между элементами в HTML, если сделать отступ для элементов-потомков?
<!-- Parent -->
<article>
<!-- Child -->
<img src="" alt="...">
<!-- Child -->
<div class="article-content">
<!-- Grandchild -->
<h2>Title</h2>
<!-- Grandchild -->
<p>Article content.</p>
</div>
</article>
Вложенность CSS — это способ форматирования наборов правил CSS. Мы начинаем с родительского набора правил, а затем встраиваем в него дочерние наборы правил. Таким образом, если бы мы хотели выбрать элемент <h2>
в последнем примере HTML, мы могли бы написать селектор потомков следующим образом:
article h2 { /* Стили */ }
С вложенностью:
article {
/* Стили статей */
h2 { /* Heading 2 styles */ }
}
Вы, вероятно, заметили, что технически мы можем опуститься на один уровень ниже, поскольку заголовок содержится в другом элементе .article-content
:
article {
/* Стили статей */
.article-content {
/* Container styles */
h2 { /* Heading 2 styles */ }
}
}
Таким образом, в конечном счёте выбор заголовка с вложенными элементами эквивалентен написанию селектора потомков в плоской структуре:
article .article-content h2 { /* Heading 2 styles */ }
Вам может быть интересно, как, чёрт возьми, можно написать составной селектор в формате вложенности. Я имею в виду, что мы могли бы легко встроить составной селектор в другой селектор:
article {
/* Стили статей */
h2.article-content {
/* Heading 2 styles */
}
}
Но мы не можем повторно объявить селектор article
вложенным селектором:
article {
/* Стили статей */
/* Нет! */
article.article-element {
/* Container styles */
/* Нет! */
h2.article-content {
/* Heading 2 styles */
}
}
}
Даже если бы мы могли это сделать, это отчасти противоречит цели аккуратно организованного вложенного блока, который показывает взаимосвязи между селекторами. Вместо этого мы можем использовать символ амперсанда (&
) для обозначения селектора, в который мы вложен. Мы называем его вложенным селектором.
article {
&.article-content {
/* Приравнивается к: article.article-content */
}
}
Селекторы компаундирования
Мы уже много говорили о каскаде и о том, как он определяет, какие стили применять к соответствующим селекторам, используя коэффициент специфичности. Ранее мы видели, что селектор элементов менее специфичен, чем селектор классов, который менее специфичен, чем селектор идентификаторов, и так далее.
article { /* Специфичность: 0, 0, 1 */ }
.featured { /* Специфичность: 0, 1, 0 */ }
#featured { /* Специфичность: 1, 0, 0 */ }
Что ж, мы можем повысить специфичность, объединив несколько селекторов в цепочку. Таким образом, мы придаём нашему селектору более высокий приоритет при оценке двух или более подходящих стилей. Опять же, переопределить селекторы ID невероятно сложно, поэтому мы будем работать с селекторами элементов и классов, чтобы проиллюстрировать объединение селекторов в цепочку.
Мы можем объединить наш селектор article
элементов с нашим селектором .featured
классов, чтобы повысить уровень специфичности.
article { /* Специфичность: 0, 0, 1 */ }
.featured { /* Специфичность: 0, 1, 0 */ }
articie.featured { /* Специфичность: 0, 1, 1 */ }
Этот новый составной селектор более специфичен (и эффективен!), чем два других отдельных селектора. Обратите внимание на то, что в следующем примере составной селектор стоит перед двумя отдельными селекторами в CSS, но всё равно превосходит их, когда каскад оценивает их специфичность.
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Заголовок статьи
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Laborum, numquam tempora! Unde delectus officiis maiores ullam natus reiciendis esse. Laboriosam ea provident aut explicabo fuga natus, labore maiores corrupti corporis!
Интересно, что мы можем использовать «фиктивные» классы в цепочечных селекторах в качестве стратегии управления специфичностью. Рассмотрим реальный пример:
.wp-block-theme-button .button:not(.specificity):not(.extra-specificity) { }
Ого, да? Там много всего происходит. Но идея такова: селекторы классов .specificity
и .extra-specificity
нужны только для того, чтобы повысить специфичность селектора потомков .wp-block-theme .button
. Давайте сравним показатель специфичности с этими искусственными классами (которые :not()
включены в совпадение) и без них.
.wp-block-theme-button .button {
/* Специфичность: 0, 2, 0 */
}
.wp-block-theme-button .button:not(.specificity) {
/* Специфичность: 0, 3, 0 */
}
.wp-block-theme-button .button:not(.specificity):not(.extra-specificity {
/* Специфичность: 0, 4, 0 */
}
Интересно! Я не уверен, что стал бы использовать это в своём CSS, но это менее жёсткий подход, чем использование ключевого слова !important
, которое так же сложно переопределить, как и селектор ID.
Комбинаторы
Если селекторы — это «то, что» мы выбираем в CSS, то комбинаторы CSS — это «то, как» мы их выбираем. Они используются для написания селекторов, которые объединяют другие селекторы для выбора элементов. Начало!
Название «комбинатор» отлично подходит, потому что оно точно отражает множество различных способов, с помощью которых мы можем объединять селекторы. Зачем нам объединять селекторы? Как мы уже обсуждали ранее в разделе «Цепные селекторы», есть две распространённые ситуации, в которых нам может понадобиться это сделать:
- Когда мы хотим увеличить специфичность того, что выбирается.
- Когда мы хотим выбрать элемент на основе условия.
Давайте рассмотрим множество типов комбинаторов, доступных в CSS, чтобы учесть эти две ситуации в дополнение к составным селекторам.
Комбинатор - потомок
Мы называем его «комбинатором потомков», потому что используем его для выбора элементов внутри других элементов, примерно так:
/* Выбрать все элементы в .parent с .child классом */
.parent .child {}
...что позволит выбрать все элементы с классом .child
в следующем примере HTML:
<div class="parent">
<div class="child"></div>
<div class="child"></div>
<div class="friend"></div>
<div class="child"></div>
<div class="child"></div>
</div>
Видите этот элемент с .friend
именем класса? Это единственный элемент внутри .parent
элемента, который не выбран с помощью .parent .child {}
комбинатора-потомка, поскольку он не соответствует, .child
даже если он также является потомком .parent
элемента.
Дочерний комбинатор
Комбинатор дочерних элементов — это, по сути, ответвление комбинатора потомков, только он более специфичен, чем комбинатор потомков, потому что выбирает только непосредственных дочерних элементов, а не любых потомков.
Давайте изменим последний рассмотренный нами пример HTML, добавив элемент-потомок, который находится глубже в генеалогическом древе, например .grandchild
:
<div class="parent">
<div class="child"></div>
<div class="child">
<div class="grandchild"></div>
</div>
<div class="child"></div>
<div class="child"></div>
</div>
Итак, у нас есть .parent
до четырёх .child
элементов, один из которых содержит .grandchild
элемент внутри себя.
Возможно, мы хотим выбрать элемент .child
без случайного выбора элемента .child
второго .grandchild
. Это то, что может сделать дочерний комбинатор. Все следующие дочерние комбинаторы выполняют одну и ту же функцию:
/* Выбрать только «прямых» потомков .parent */
.parent > .child {}
.parent > div {}
.parent > * {}
Видите, как мы объединяем разные типы селекторов, чтобы сделать выборку? Мы объединяем, чёрт возьми! Мы просто делаем это немного по-разному в зависимости от типа дочернего селектора, который мы объединяем.
/* Выбрать только «прямых» потомков .parent */
.parent > #child { /* прямой ребенок с #child ID */
.parent > .child { /* прямой ребенок с .child class */ }
.parent > div { /* прямой ребенок div элемент */ }
.parent > * { /* все прямые дочерние элементы */ }
Очень удобно, что у нас есть возможность не только выбирать только прямые дочерние элементы, но и делать это более или менее конкретно в зависимости от типа селектора. Например, селектор ID более конкретен, чем селектор классов, который более конкретен, чем селектор элементов, и так далее.
Общий комбинатор братьев и сестер
Если у двух элементов один и тот же родительский элемент, то они являются братьями и сёстрами. Мы вскользь рассмотрели этот пример при обсуждении комбинатора потомков. Давайте изменим названия классов из этого примера, чтобы немного прояснить отношения между братьями и сёстрами:
<div class="parent">
<div class="brother"></div>
<div class="sister"></div>
</div>
Таким образом, мы можем выбрать элемент .sister
при условии, что перед ним есть элемент с классом .brother
.
/* Выбрать .sister только если следует .brother */
.brother ~ .sister { }
Символ тильды (~
) указывает на то, что это комбинатор родственных элементов.
Неважно, стоит ли .sister
сразу после .brother
или нет — если .sister
стоит после brother
и у них один и тот же родительский элемент, он будет выбран. Давайте рассмотрим более сложный пример HTML:
<main class="parent">
<!-- .sister immediately after .brother -->
<div class="brother"></div>
<div class="sister"></div>
<!-- .sister immediately after .brother -->
<div class="brother"></div>
<div class="sister"></div>
<!-- .sister immediately after .sister -->
<div class="sister"></div>
<!-- .cousin immediately after .brother -->
<div class="brother"></div>
<div class="cousin">
<!-- .sister contained in a .cousin -->
<div class="sister"></div>
</div>
</main>
Написанный нами комбинатор родственных элементов выбирает только первые три .sister
элемента, потому что только они идут после элемента .brother
и имеют одного и того же родителя — даже в случае с третьим .sister
элементом, который идёт после другого родственного элемента! Четвёртый .sister
элемент находится внутри .cousin
, что не позволяет ему соответствовать селектору.
Давайте рассмотрим это в контексте. Итак, мы можем выбрать все элементы с помощью селектора элементов, поскольку каждый элемент в HTML является div
:
.brother
.sister
.brother
.sister
.sister
.brother
.cousin
.sister
Затем мы можем выбрать только братьев с помощью селектора классов, чтобы придать им другой цвет фона:
.brother
.sister
.brother
.sister
.sister
.brother
.cousin
.sister
Мы также можем использовать селектор классов, чтобы задать другой цвет фона для всех элементов с классом .sister
:
.brother
.sister
.brother
.sister
.sister
.brother
.cousin
.sister
И, наконец, мы можем использовать общий комбинатор родственных связей, чтобы выбрать только тех сестёр, которые идут сразу после брата.
.brother
.sister
.brother
.sister
.sister
.brother
.cousin
.sister
Вы заметили, что цвет фона последнего.sister
элемента остался зелёным, в то время как остальные стали фиолетовыми? Это потому, что он единственный .sister
в группе, который не имеет тот же .parent
цвет, что и .brother
элемент.
Смежный комбинатор
Хотите верьте, хотите нет, но мы можем быть ещё более конкретными в выборе элементов с помощью комбинатора «соседний». Общий селектор братьев и сестёр, который мы только что рассмотрели, выберет все .sister
элементы на странице, если они имеют того же родителя, что и .brother
и находятся после .brother
.
Отличие соседнего комбинатора в том, что он выбирает любой элемент, непосредственно следующий за другим. Помните, как последний .sister
не совпадал, потому что он содержался в другом родительском элементе (то есть .cousin
)? Что ж, мы действительно можем выбрать его отдельно с помощью соседнего комбинатора:
/* Выбрать .sister только если непосредственно следует .brother */
.brother + .sister { }
Обратите внимание, что происходит, когда мы добавляем это к нашему последнему примеру:
.brother
.sister
.brother
.sister
.sister
.cousin
.sister
Первые два элемента .sister
изменили цвет! Это потому, что они являются единственными элементами, которые идут сразу после .brother
. Третий .sister
идёт сразу после другого .sister
, а четвёртый содержится в .cousin
, что не позволяет им обоим соответствовать выбору.
Читайте больше о CSS и селекторах в статьях нашего Блога