Комбинаторы: потомок, дочерний, соседние элементы

Когда нужно выбрать элемент не сам по себе, а по его положению относительно другого - например, абзац сразу внутри блока или заголовок, за которым следует текст, - на помощь приходят комбинаторы. Это специальные знаки между двумя селекторами: пробел, >, + и ~ - каждый описывает свою связь между элементами.

Попробуй прямо в этом окне: все три абзаца становятся оранжевыми (это работает "article p" - потомок на любой глубине). Жирными и с голубым фоном становятся только первый и третий абзацы - они прямые дети article и настоящие соседи заголовка. А вот подчёркивание получает только самый первый абзац - только он идёт сразу за h2 без ничего между ними. Абзац внутри div остаётся без жирности, подчёркивания и фона: у него другой родитель - div, а не article, так что для селекторов "дочерний" и "сосед" он вообще не в счёт.

Селектор потомка (пробел)

Если между двумя селекторами стоит просто пробел, это селектор потомка: он находит второй элемент внутри первого на любой глубине вложенности, даже если между ними ещё десять других тегов.

article p { color: tomato; } - покрасит любой абзац внутри article, даже если он спрятан ещё в одном div.

article, p { color: tomato; } - запятая вместо пробела превращает это в два независимых селектора (все article И все p на странице), а не в связь "абзац внутри article".

Дочерний селектор (>)

Знак > между селекторами сужает поиск: он находит только прямых детей первого элемента, то есть тех, кто вложен ровно на один уровень, а не спрятан ещё глубже.

article > p { font-weight: bold; } - только абзацы, которые лежат прямо внутри article, а не внутри вложенного div.

article > div > p { } путают с article p - первое требует именно такой цепочки вложенности (article, в нём сразу div, в нём сразу p), а не просто "абзац где-то внутри article".

Селектор соседнего элемента (+)

Знак + связывает двух соседей с общим родителем: он находит элемент, который идёт СРАЗУ после первого, без других тегов между ними. Обычный текст и HTML-комментарии между ними не мешают - в счёт идут только другие теги.

h2 + p { text-decoration: underline; } - подчеркнёт абзац, только если он идёт первым сразу после h2.

h2 + p, ожидая, что сработает и для второго, и для третьего абзаца после заголовка - + находит только САМОГО БЛИЖАЙШЕГО соседа, а не всех подряд.

Селектор всех последующих соседей (~)

Знак ~ - более щедрая версия +: он находит ВСЕХ последующих соседей первого элемента с тем же родителем, а не только самого ближнего. Между ними может быть сколько угодно других тегов.

h2 ~ p { background: #eef; } - подсветит все абзацы, которые идут после заголовка и делят с ним одного родителя, сколько бы их ни было.

h2 ~ p, ожидая, что подсветится и абзац, спрятанный внутри вложенного div, - для ~ важно, чтобы элементы были настоящими соседями с ОДНИМ родителем, а не просто располагались где-то после заголовка по тексту разметки.

Из истории Все четыре комбинатора появились не сразу, а растянулись на пятнадцать лет. Селектор потомка (пробел) был уже в самой первой версии CSS 1996 года - в спецификации CSS1 есть пример «H1 EM { color: red }», и там же прямо сказано: «other relationships (e.g. parent-child) may be introduced in later revisions» - то есть авторы CSS1 сознательно отложили дочерний селектор на будущее. Так и вышло: дочерний > и соседний + появились в CSS2, которая стала рекомендацией W3C 12 мая 1998 года (разделы спецификации «5.6 Child selectors» и «5.7 Adjacent sibling selectors»). А вот селектор ~ для ВСЕХ последующих соседей добавили ещё позже - только в CSS3 Selectors Level 3, ставшей рекомендацией W3C 29 сентября 2011 года. Источники: w3.org - спецификация CSS1, 1996, w3.org - селекторы CSS2, 1998, w3.org - Selectors Level 3, 2011.

Частые ошибки новичков

ОшибкаЧто происходитКак исправить
Путать пробел (потомок) и > (дочерний) Пробел находит элемент на любой глубине вложенности, а > - только прямых детей. С пробелом правило часто задевает больше элементов, чем задумывалось Использовать >, если важно ограничиться именно прямыми детьми, а не любой вложенностью
Путать + и ~ + находит только самого ближайшего следующего соседа, а ~ - вообще всех последующих. Если между элементами появится ещё один тег, + перестанет работать, а ~ - нет Использовать + для "прямо следующий элемент", ~ - для "любой из последующих"
Считать, что элемент внутри вложенного тега - тоже "сосед" И + , и ~ требуют, чтобы элементы были настоящими соседями с ОДНИМ родителем. Элемент, спрятанный в другом теге между ними, соседом не считается, даже если по тексту разметки идёт между ними Проверять реальную структуру вложенности, а не только порядок тегов на глаз
Путать комбинатор с составным селектором Комбинатор всегда стоит МЕЖДУ двумя разными селекторами (a b, a > b) и связывает разные элементы. Слитная запись без пробела (a.klass) - это один и тот же элемент сразу с двумя условиями, а не комбинатор Смотреть, есть ли пробел или знак между частями селектора - это и есть комбинатор; без пробела это одно условие на один элемент

Шпаргалка

КомбинаторЧто выбирает
a b (пробел)Потомок - b внутри a на любой глубине
a > bДочерний - b, который прямой ребёнок a
a + bСоседний - b, который идёт сразу после a, с тем же родителем
a ~ bВсе последующие соседи - любой b после a с тем же родителем
СпецифичностьСами комбинаторы вес селектора не добавляют - считаются только теги, классы и id по обе стороны от них

Коротко: отвечаем на вопросы

В чём разница между div a {} и div > a {}?

div a найдёт ссылку на любой глубине внутри div, даже если она обёрнута ещё одним тегом. div > a сработает только для ссылки, которая лежит прямо внутри div, без промежуточных тегов вокруг неё.

Можно ли использовать несколько комбинаторов в одном селекторе подряд?

Да, их можно комбинировать сколько угодно: например, article > h2 + p сначала найдёт h2, который прямой потомок article, а затем - абзац, идущий сразу за этим h2.

Влияют ли комбинаторы на специфичность селектора?

Сами по себе нет - пробел, >, + и ~ веса не добавляют. На специфичность влияют только теги, классы и id, которые стоят по обе стороны от комбинатора.

Почему h2 + p ничего не подсветил, хотя абзац идёт сразу после заголовка на вид?

Скорее всего, между ними на самом деле есть ещё один тег - например, обёртка div. Обычный текст и HTML-комментарии на это не влияют, а вот любой другой элемент между h2 и p разрывает соседство для +.

Категория
css
Поделиться в социальных сетях

Отправить комментарий

0 Комментарии

Отправить комментарий (0)

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×