CSS - Селекторы

CSS - Селекторы
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!

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

<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!

Интересно, что мы можем использовать «фиктивные» классы в цепочечных селекторах в качестве стратегии управления специфичностью. Рассмотрим реальный пример:

.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 и селекторах в статьях нашего Блога

Понравилась статья?
Будем признательны, если поделитесь в соцсетях или мессенджерах, а также присоединитесь к нашей группе Вконтакте. Будет интересно!

Другие статьи по теме:

Как использовать свойства CSS object-fit и object-position
Как использовать свойства CSS object-fit и object-position

Существует множество вариантов для определения размера и расположения фоновых изображений с помощью CSS. В этой статье мы рассмотрим, как использовать object-fit для размещения изображений на определенном пространстве и как использовать object-position для правильного позиционирования в этом пространстве.

Свойство clip-path
Свойство clip-path
Свойство clip-path в CSS позволяет указать конкретную область элемента для отображения, а остальная часть скрыта (или “обрезана”)...
Как создать пользовательский ползунок диапазона с помощью CSS
Как создать пользовательский ползунок диапазона с помощью CSS

Ползунки диапазона (<input type="range">) позволяют пользователям выбирать значение в пределах заданного диапазона, предоставляя альтернативные типы ввода, такие как <input type="number">.

Несколько полезных CSS-трюков для Front-end разработчиков
Несколько полезных CSS-трюков для Front-end разработчиков

Хотим поделиться с вами несколькими CSS трюками, которые вам точно пригодятся при создании сайтов. Они позволят вам без использования Javascript создать анимацию и эффекты.

Имитация стрелочных часов с помощью новых тригонометрических функций CSS sin() и cos ()
Имитация стрелочных часов с помощью новых тригонометрических функций CSS sin() и cos ()
Тригонометрические функции CSS есть в последних версиях Firefox и Safari. Наличие такого рода математической мощи в CSS открывает целую кучу возможностей. В этом материале мы применим пару новых функций: sin()и cos().
Анимационные указатели прокрутки страницы
Анимационные указатели прокрутки страницы

Такие указатели чаще всего применяют на первом экране Главной страницы сайта, когда на ней размещена полноэкранная картинка, видео или слайдер. Чтобы показать Пользователю, что основной контент расположен ниже, в нижней части экрана размещают стрелку, направленную вниз. Чтобы привлечь к ней дополнительное внимание, её делаю анимационный...

QRcode

2010-2025 © Веб студия iNikSite.ru (г. Подольск). Все права сохранены.

Цены на сайте носят ознакомительный характер и не являются публичной офертой! Просим уточнять цены при отправке заявки в нашу компанию. У нас действуют специальные предложения и скидки на различные варианты исполнения заказа и 100% предоплату!

Мы используем файлы cookie. Они помогают улучшить ваше взаимодействие с сайтом.