Почему у нас нет селектора по родителю — Веб-стандарты
Относительно регулярно я вижу дискуссии о том, должен ли CSS включать селектор по родителю и, пока я не выяснил, как работает движок браузера, сам строил предположения по этому поводу.
Вкратце: производительность.
Как работает CSS
В связи с моей работой я делаю много тестов производительности. Для определения «узких мест» мы используем массу приложений. Например, Google Page Speed, который дает рекомендации по улучшению производительности JavaScript и рендеринга. Прежде чем я перейду к рассмотрению этих рекомендаций, нам нужно разобраться как браузеры работают с CSS
Стиль элемента применяется в момент его создания
Мы часто рассматриваем веб-страницы как полноценные документы, наполненные элементами и содержимым. Между тем, браузеры разработаны так, чтобы обрабатывать документ потоково. Они начинают получать документ с сервера и могут начать его отображать до момента полной загрузки. Каждый узел анализируется и отображается в окне по мере получения.
Взгляните на этот документ:
<body>
<div>
<div>
<p>Lorem Ipsum</p>
</div>
<div>
<p>Lorem Ipsum</p>
<p>Lorem Ipsum</p>
<p>Lorem Ipsum <span>Test</span></p>
</div>
</div>
</body>
Браузер начинает сначала и видит элемент <body>
. В этот момент времени считается, что этот узел не имеет дочерних узлов. Ничего более не рассматривается. Браузер определяет соответствующий ему обобщенный набор стилей и применяет его к элементу. Какой шрифт, цвет, интерлиньяж? После того, как это все будет выяснено, элемент отображается на экране.
Далее браузер видит элемент <div>
со значением атрибута ID content
. И снова в этот момент времени браузер считает его пустым. Он не рассматривает другие элементы. Как только браузер рассчитает стиль, элемент отображается на экране. Затем браузер определяет нужно ли перерисовать <body>
— стал ли элемент шире или выше? Я подозреваю, что там есть масса других проверок, но изменение ширины и высоты — самый распространенный способ повлиять на отображение родительского узла.
Процесс продолжается, пока браузер не достигнет корневого узла документа.
Вот как выглядит визуализация процессов перерисовки в Firefox:
CSS селекторы анализируется справа налево
Чтобы определить, применяется ли CSS-правило к определенному элементу, браузер рассматривает селектор справа налево.
Если у вас есть селектор body div#content p { color: #003366; }
, то, когда каждый элемент появляется на странице, браузер проверяет, является ли он параграфом. Если да, он начинает подниматься вверх по DOM и ищет
со значением атрибута ID равным content
. Если он его находит, то продолжает подниматься по DOM пока не найдет <body>
.
Таким образом, читая селектор справа налево, браузер значительно быстрее может определить применяется ли правило к элементу. Чтобы определить, какой из селекторов обладает большей производительностью, нужно выяснить, как много узлов придется рассмотреть, чтобы определить, можно ли применить правило к элементу.
Правила
Возвращаясь к Page Speed, давайте рассмотрим несколько его рекомендаций:
- Избегайте селектора по потомку:
.content .sidebar
; - Избегайте селектора по дочернему элементу:
.content > .sidebar
и селектора по следующему элементу:.content + .sidebar
.
Конечно, селекторы по ID — самые быстрые. Проверить применимость селектора #content
к рассматриваемому элементу можно очень быстро. Есть у него этот ID или нет? Селекторы по классу практически такие же быстрые, так как нет никаких связанных элементов, которые надо проверять.
Селекторы по потомкам, такие как .content .sidebar
— более ресурсоемкие, так как, чтобы определить надо ли применять правило к .sidebar
, браузер должен найти .content
. Cелектор по дочернему элементу, например, .content > .sidebar
, лучше селектора по потомку, так как браузер должен проверить только один элемент вместо множества.
К сожалению, селекторы +
и >
не поддерживаются IE6. Так что если его поддержка актуальна для вас, то про них придется забыть. Примечание переводчика.
Селектор по тегу и универсальный селектор
В рамках рекомендации избегать селекторов по потомку, дочернему или следующему элементам, рекомендуется избегать универсального селектора и селектора по тегу.
Рассмотрим следующий пример:
#content * { color: #039; }
Так как в селекторе присутствует ID, то можно подумать, что этот селектор обрабатывается очень быстро. Проблема в том, что браузер обрабатывает селектор справа налево и сперва проверяется универсальный селектор. Для того чтобы браузер мог определить, должен ли цвет текста элемента быть тёмно-синим, надо проверить каждый предок элемента, пока не будет найден предок с атрибутом ID равным content
или не будет достигнут корень документа.
И это должно быть сделано для каждого элемента на странице.
Теперь, когда мы понимаем, как элемент обрабатывается, как определяется применимость правил к элементу, давайте рассмотрим пример.
Почему IE долго не поддерживал :last-child
Все жаловались: у всех браузеров, кроме IE, есть поддержка :last-child
(она появилась только в IE9!) Некоторые могли подумать насколько же сложнее сделать :last-child, если уже реализован :first-child?
Давайте представим, что мы — браузер и мы парсим документ-пример, который я приводил ранее.
.module > p:first-child { color: red; } /* Первое правило */
.module > p:last-child { color: blue; } /* Второе правило */
Когда мы рассматриваем внутренности первого <div>
, мы видим, что там есть параграф. Браузер видит что-то вроде этого:
<div>
<p>Lorem Ipsum</p>
Нужно ли применить первое правило к параграфу? Да, это параграф; да, это первый дочерний узел; и, да, это непосредственный потомок элемента с классом module
.
Нужно ли применить к этому параграфу второе правило? На данный момент это последний элемент. Но мы могли ещё не загрузить все элементы и не можем быть уверены, что он останется последним.
Вне зависимости от того, как решать эту дилемму, у нас возникает необходимость повторного анализа стилей двух узлов для каждого нового узла, который мы добавляем в DOM. Если я добавлю ещё один параграф следом за первым, мы должны так же повторно перерассчитать стили, которые применяются к предыдущему параграфу.
Как на самом деле это делает браузер?
Я не мог сказать с абсолютной уверенностью, как браузеры парсят :last-child
, так что я создал несколько тестов:
Первый пример весьма скучен. В любом браузере, включая IE9, всё отображается корректно. Внутри <div>
первый элемент красный, а последний синий. Но посмотрите на второй пример, и вы увидите интересные отличия в поведении браузеров.
Второй пример приостанавливается перед добавлением каждого параграфа в <div>
.
В Firefox первый параграф изначально отображается синим. Когда загружается второй параграф, первый становится красным и второй — синим. Когда загружается третий параграф, второй отображается цветом по умолчанию и третий отображается синим. Firefox рассматривает каждый элемент, который был загружен в качестве последнего элемента, пока не будет загружен ещё один.
В Safari, Chrome и Opera мы увидим другой подход. Первый параграф красный. Второй отображается чёрным. Последний параграф отображается чёрным, пока браузер не получит закрывающий тег </div>
. В этот момент последний параграф становится синим. Эти браузеры не рассматривают элемент как последний, пока не будет закрыт родительский.
В Internet Explorer 9 Beta я нашел интересный баг. В то время, как статическая страница отображается корректно, версия с паузами отрабатывает с любопытным побочным эффектом. Первый параграф синий, второй параграф синий и затем — третий. Когда закрывающий тег </div>
загружен, предпоследний параграф меняет цвет на чёрный. IE9 пытается обрабатывать селектор как Webkit и Opera, но… м-м… не выходит. Надо бы отправить багрепорт в Microsoft.
Почему у нас нет селектора по родителю?
Уже дано достаточно пояснений, чтобы можно было вернуться к оригинальному вопросу. Проблема не в том, что у нас не может быть селектора по родителю. Проблема в том, что мы столкнемся с проблемами быстродействия, когда дело дойдет до определения того, какие CSS-правила применимы к данному элементу. Если Google Page Speed не рекомендует использование универсальных селекторов, то можно гарантировать, что селектор по родителю будет первым в списке ресурсоемких селекторов, намного опережая все проблемы с производительностью, которые могут быть вызваны использованием универсального селектора.
Давайте посмотрим почему. Первым делом давайте приведём пример синтаксиса для селектора по родителю.
div.module:has(span) { color: green; }
Проблема в том, что мы не можем определить применимость правила до тех пор, либо пока мы не найдем соответствия, либо пока все элементы, дочерние по отношению к родителю данного, не будут загружены. Ввиду этого мы должны оценивать правило и все остальные (в случае наличия специфических особенностей), применяющиеся к элементу, для каждого дочернего элемента, который мы загружаем.
Посмотрите на часть нашего документа:
<div>
<p>Lorem Ipsum</p>
<p>Lorem Ipsum</p>
<p>Lorem Ipsum <span>Test</span></p>
</div>
Исходя из того, что мы видим, .module
будет отображён без использования правила, применяемого селектором по родителю. Когда будет загружен первый элемент <p>
, нужно повторно оценить применимость селектора по родителю к <div>
. Нужно сделать это снова для следующего параграфа. И снова, для следующего. Наконец, когда <span>
загружен, селектор по родителю будет применен к родительскому <div>
, и элемент нужно будет повторно перерисовать.
И что теперь? Теперь, если изменится любое наследуемое CSS-свойство, каждый потомок должен будет повторно анализироваться и перерисовываться. Ох…
Почему проблему можно решить с помощью JavaScript?
Это только кажется, что JavaScript решает проблему. В общем случае JavaScript-заплатки (заплатки — polyfills — части кода, обеспечивающие функциональность, которую должен обеспечивать браузер. Примечание переводчика). Или регрессивное усовершенствование (или как там вы, молодежь, это сейчас называете) запускаются только один раз, после полной загрузки DOM.
Для того чтобы действительно имитировать поведение CSS, любой скрипт, решающий эту проблему, должен запускаться после отображения каждого элемента на странице, чтобы определить, нужно ли применить нашу «заплатку». Помните CSS-expressions в Internet Explorer? Именно по этой причине они вызывали такие проблемы с производительностью.
Не невозможно
Появится ли когда-нибудь селектор по родителю? Возможно. То, что я опиcал, не невозможно. На самом деле — наоборот. Это значит только то, что нам придётся иметь дело с ухудшением производительности из-за использования этого селектора.
Перевод оригинальной заметки «Why we don’t have a parent selector» Джонатана Снука (Jonathan Snook), опубликованной в блоге «Snook.ca».
Теги: css, методика
родитель-потомок в CSS — Селекторы в CSS — codebra
Рассмотрим пример первый.
Пример 1
<!DOCTYPE html>
<html>
<head>
<title>codebra</title>
</head>
<body>
<ol>
<li>1</li>
<li>2</li>
</ol>
</body>
</html>
HTML документы строятся на иерархии элементов. Каждый элемент является родителем или потомком, или и тем, и другим. Например, элемент body
является родителем для элемента ol
. А элемент ol
является родителем для элементов li
. body
является дочерним элементу html
и так далее.
Родителем и потомком называют те элементы, разница между которыми один уровень. Если разница между элементами несколько уровней, например, body
и li
, то такие элементы называют предок (body
) и потомок (li
).
Родители и потомки из первого примера
И теперь давайте посмотрим реальный пример.
Пример 2
<p>
<span>спан в абзаце</span>
</p>
<h2>
<span>спан в заголовке</span>
</h2>
Теперь первый span
(родитель p
) сделаем красного цвета. Второй span
(родитель h2
) сделаем зеленого цвета. Это реализовано в третьем примере.
Пример 3
p span {
color: red;
}
h2 span {
color: green;
}
Рассмотрим четвертый пример.
Пример 4
<p>
<b>
<span>жирный спан в абзаце</span>
</b>
</p>
То есть можно и больше двух селекторов использовать.
Пример 5
p b span {
color: red;
}
Учебник LESS. Статья «Родительские селекторы в LESS»
В этой статье мы с Вами расширим наши знания об использовании различных CSS селекторов в LESS, научимся работать с псевдоэлементами, и рассмотрим использование специального оператора &, который представляет из себя ссылку на родительский элемент внутри вложенного правила. Подробную информацию о правилах вложенности вы можете получить в статье этого учебника «Правила вложенности».
До того как вы перейдете к прочтению статьи, рекомендую Вам освежить, или получить знания из актуального учебника CSS 3 о том как, и для чего используются селекторы, псевдоклассы и псевдоэлементы при описании стилей:
Использование псевдоклассов
Псевдоклассы дают нам возможность затронуть форматирование на странице такие особенности, или состояния элементов, которые явным образом не задать с использованием селекторов. В этом разделе статьи мы с Вами научимся правильно использовать псевдоклассы в LESS коде и начнем свое знакомство с оператором &, его так же называют оператор родительского элемента (внутри вложенного правила).
Давайте начнем наше знакомство со следующего примера:
<!DOCTYPE html> <html> <head> <title>Пример работы с псевдоклассами в LESS</title> <link rel = "stylesheet/less" href = "8.less"> <!-- подключаем less файл к документу --> <script src = "less.min.js"></script> <!-- подключаем скрипт JavaScript для преобразования метаязыка LESS в CSS --> </head> <body> <button>Клик</button> </body> </html>
В этом примере я разместил только одну кнопку (HTML элемент <button>), стили которой, мы будем описывать с помощью LESS. Обратите внимание, что я для своего удобства подключил скрипт JavaScript, который выступает в роли компилятора и преобразует файл 12.less в каскадные таблицы стилей CSS на «лету». В файле less я разместил следующие стили:
button { height: 50px; // высота элемента width: 100px; // ширина элемента padding: 15px 30px; // внутренние отступы border: 1px solid transparent; // сплошная прозрачная граница размером 1 пиксель (убираем встроенные стили) border-radius: 15px; // форма границ элемента background-image: linear-gradient(to right, #f31, #f64); // линейный градиент в качестве фонового изображения color: #fff; // цвет текста outline-color: transparent; // устанавливает прозрачный цвет контура элемента (убираем встроенные стили) &:hover { // задаем стили при наведении на элемент button color: #000; // цвет текста } &:active { // задаем стили тогда, когда элемент button активен background: orange; // цвет заднего фона } }
Основная задача оператора родительского элемента & заключается в том, чтобы сослаться на родительский элемент, этим приемом пользуются не только в повседневной жизни, но и при написании LESS кода внутри вложенных правил. Можно с уверенностью сказать, что самое распостраненное применение этого оператора это применение его с любыми псевдоклассами. Это связано с тем, что без его использования компиляция будет некорректна, но об этом чуть-чуть попозднее.
Обратите внимание на синтаксис, который мы использовали при описании стилей, в нем в отличии от CSS вместо имени родительского элемента, в нашем случае это button мы просто используем оператор родительского элемента &. В результате компиляции у Вас должны получиться следующие CSS стили:
button { height: 50px; // высота элемента width: 100px; // ширина элемента padding: 15px 30px; // внутренние отступы border: 1px solid transparent; // сплошная прозрачная граница размером 1 пиксель (убираем встроенные стили) border-radius: 15px; // форма границ элемента background-image: linear-gradient(to right, #f31, #f64); // линейный градиент в качестве фонового изображения color: #fff; // цвет текста outline-color: transparent; // устанавливает прозрачный цвет контура элемента (убираем встроенные стили) } button:hover { // задаем стили при наведении на элемент button color: #000; // цвет текста } button:active { // задаем стили тогда, когда элемент button активен background: orange; // цвет заднего фона }
В этом примере мы использовали два псевдокласса, которые позволили нам описать стили для тех состояний, когда указатель мыши наведен на элемент <button> (псевдокласс :hover) и, когда он активен (псевдокласс :active).
Результат нашего примера:
Рис. 12 Пример работы с псевдоклассами в LESS.Использование методологии БЭМ
Применение оператора родительского элемента можно встретить не только вместе с псевдоклассами, но зачастую и при написании CSS кода по такой методологии веб-разработки как БЭМ (Блок-Элемент-Модификатор). Обязательно ознакомьтесь с ней в свободное время, она предлагает общую семантическую модель для всех технологий, использующихся во фронтэнд разработке (HTML, CSS, JavaScript, шаблоны проектирования и так далее).
Обратите внимание на следующее изображение:
Рис.13 Пример организации CSS кода по БЭМ
На изображении представлены два идентичных блока, за тем исключением, что к элементу первого блока применен модификатор, который изменяет цвет текста, а у второго блока использован модификатор, который увеличивает размер шрифта в два раза (надеюсь у Вас хорошая фантазия).
Сделаем по этому изображению разметку (у многих редакторов кода по умолчанию встроен, или доступен для скачивания удобный плагин для быстрой разметки Emmet, он позволяет сделать подобную разметку следующим образом: (div>div*3)*2 и Tab). Результат:
<div> <!-- первый блок --> <div></div> <!-- элемент первого блока --> <div></div> <!-- элемент первого блока --> <div></div> <!-- элемент первого блока --> </div> <div> <!-- второй блок --> <div></div> <!-- элемент второго блока --> <div></div> <!-- элемент второго блока --> <div></div> <!-- элемент второго блока --> </div>
У вас может быть на странице сотни различных (не идентичных) блоков, и при этом правила одного блока не должны влиять на внутренний мир любого другого блока (компонентный подход). Блок должен влиять только на свои элементы, и не может воздействовать на элементы другого блока, элементы блока это ничто иное как его внутренняя реализация. Кроме того, блоки могут быть вложены в другие блоки, но это уже совсем другая история.
Модификаторы в свою очередь задают блокам внешний вид, состояние и поведение, то есть изменение оформления блока производится только при помощи установки, либо снятия модификатора. Еще одним важным моментом является то, что в БЭМ не используют селекторы типа (элементов) и селекторы идентификаторов, а стили блоков и элементов описываются с использованием селекторов классов.
Давайте опишем наши блоки с использованием LESS:
block { // блок font-family: monospace; // семейство шрифтов &__element { // элемент блока padding: 10px; // внутренние отступы margin: 30px; // внешние отступы color: red; // цвет текста &_modifier_active { // модификатор элемента color: green; // цвет текста } } &_modifier_s { // модификатор блока font-size: 15px; // размер шрифта } &_modifier_m { // модификатор блока font-size: 30px; // размер шрифта } }
Обратите внимание на отличие в наименование блоков, как правило их пишут либо в одно слово, либо через дефис, элементы выделяются двумя нижними подчеркиваниями, а модификаторы одним. В результате компиляции у Вас должен получиться следующий CSS код:
block { // блок font-family: monospace; /* семейство шрифтов */ } block__element // элемент блока padding: 10px; /* внутренние отступы */ margin: 30px; /* внешние отступы */ color: red; /* цвет текста */ } block__element_modifier_active { /* модификатор блока */ color: green; /* цвет текста */ } block_modifier_s { /* модификатор блока */ font-size: 15px; /* размер шрифта */ } block_modifier_m { /* модификатор блока */ font-size: 30px; /* размер шрифта */ }
Представленная статья ориентирована прежде всего на изучение LESS и оператора родительского элемента в частности, если Вам на данном этапе не до конца понятна суть методологии БЭМ не растраивайтесь, так как она требует самостоятельного более детального изучения, и не является обязательной на данном этапе обучения.
Конечная разметка документа должна принять следующий вид:
<div class = "block block_modifier_s"> <!-- первый блок (использован модификатор)--> <div class = "block__element block__element_modifier_active"></div> <!-- элемент первого блока (использован модификатор)--> <div class = "block__element"></div> <!-- элемент первого блока --> <div class = "block__element"></div> <!-- элемент первого блока --> </div> <div class = "block block_modifier_m"> <!-- второй блок (использован модификатор) --> <div class = "block__element"></div> <!-- элемент второго блока --> <di class = "block__element"v></div> <!-- элемент второго блока --> <div class = "block__element"></div> <!-- элемент второго блока --> </div>
Нюансы использования &
Ранее при рассмотрении работы с псевдоклассами я уже говорил, что без использования оператора родительского элемента компиляция будет некорректна, давайте рассмотрим в каких случаях это утверждение верно, а в каких нет. Начнем с псевдоклассов:
// без оператора & .test { :hover { // используем псевдокласс :hover color: green; } } // с оператором & .test2 { &:hover { // используем псевдокласс :hover с оператором родительского элемента color: green; } }
В этом примере мы указали два класса, к которым применили псевдокласс :hover. В первом случае не был использован оператор родительского элемента, при компиляции это не вызовет ошибки, но приведет к ошибке во время использования файла с CSS стилями, которые будут не валидны:
.test :hover { // не валидный CSS код (пробел между селектором и псевдоклассом) color: green; } .test2:hover { // валидный CSS код color: green; }
Далее, где не обойтись без использования оператора &, это необходимость использования селектора, в котором родительский элемент имеет составной селектор без пробелов (например, .parentClass.class):
// без оператора & .test1 { .class { // селектор потомков без оператора color: blue; } // отсутствует возможность указать родительский элемент с определенным классом } // с оператором & .test2 { & .class { // селектор потомков с оператором color: blue; } &.class { // селектор класса с определенным классом color: plum; } }
Результат компиляции будет следующий:
.test1 .class { // селектор потомков color: blue; } .test2 .class { // селектор потомков color: blue; } .test2.class { // селектор класса с определенным классом color: plum; }
В следующем примере мы рассмотрим такие селекторы, в которых без использования оператора родительского элемента можно обойтись. Как и в случае с селекторами потомков компиляция даст валидный CSS код:
// без оператора & .test1 { > div { // селектор дочерних элементов color: red; } ~ a { // селектор следующих элементов color: yellow; } + p { // селектор смежных элементов color: plum; } } // с оператором & .test2 { & > div { // селектор дочерних элементов color: red; } & ~ a { // селектор следующих элементов color: yellow; } & + p { // селектор смежных элементов color: plum; } }
Как вы можете заметить при использовании селекторов потомков, дочерних элементов, следующих элементов и смежных элементов наличие оператора родительского элемента (для ссылки на родителя) будет носить лишь декоративный характер, так как компиляция даст валидный (одинаковый) результат в обоих случаях:
.test1 > div { // селектор дочерних элементов color: red; } .test1 ~ a { // селектор следующих элементов color: yellow; } .test1 + p { // селектор смежных элементов color: plum; } .test2 > div { // селектор дочерних элементов color: red; } .test2 ~ a { // селектор следующих элементов color: yellow; } .test2 + p { // селектор смежных элементов color: plum; }
Множественное использование &
Следующая особенность оператора родительского элемета, это возможность использования его внутри вложенного селектора неограниченное количество раз. Это позволит Вам повторно использовать имя родительского элемента при составлении необходимого селектора. Рассмотрим следующий пример:
.block { & > & { // селектор дочерних элементов color: red; } & .& { // селектор потомков color: green; } && { // селектор класса с определенным классом color: yellow; } &, &-s, &-l { // групповой селектор color: blue; } }
В этом примере мы составили селектор дочерних элементов, селектор потомков, селектор класса с классом родительского элемента и групповой селектор, используя в основном только оператор &.
Результат компиляции будет следующий:
.block > .block { // селектор дочерних элементов color: red; } .block .block { // селектор потомков color: green; } .block.block { // селектор класса с определенным классом color: yellow; } .block, // групповой селектор .block-s, .block-l { color: blue; }
Измененение последовательности селекторов
Хочу познакомить Вас еще с одной возможностью оператора родительского элемента, которая позволяет изменить последовательность селекторов, и сделать вложенный элемент родителем. В некоторых случаях полезно внести одну правку, а не переписывать большое количество кода, но без особой необходимости старайтесь избегать подобных стилей. Рассмотрим следующий пример:
.parent { .child { .grandchild & { // делаем из вложенного элемента родителя color: green; a { background: blue; } } .grandchild& { // делаем из вложенного элемента родителя color: green; a { background: yellow; } } } }
Обратите внимание, что мы использовали оператор родительского элемента не до, а уже после селектора, в первом случае, чтобы у нас получился селектор потомков, а во втором селектор класса с определенным классом. Обратите внимание, что вложенный в него элемент <a> не вырывается из контекста, а остается на том же уровне вложенности.
Результат компиляции будет слеудующий:
.grandchild .parent .child { color: green; } .grandchild .parent .child a { background: blue; } .grandchild.parent .child { color: green; } .grandchild.parent .child a { background: blue; }
Комбинирование селекторами
Заключительная особенность оператора &, которую мы рассмотрим в этой статье это возможность создания групповых селекторов, которые получаются путем перебора всех перечисленных в родительском элементе селекторов. При проведении перебора элементов создаются всевозможные комбинации отдельно по каждому элементу. Рассмотрим на следующем примере:
i, b, em { // групповой селектор & > & { color: blue; } }
Будьте внимательны при использовании этой возможности LESS, это может как сократить Ваш код, так и привести к нежелательным ошибкам. Результат компиляции будет следующий:
i > i, // групповой селектор i > b, i > em, b > i, b > b, b > em, em > i, em > b, em > em { color: blue; }
Учебник CSS 3. Статья «Селекторы. Часть 2».
В этой статье мы с Вами углубим знания о селекторах CSS, особое внимание мы уделим селекторам потомков, ведь понимание как работают эти селекторы является очень важной темой, требующей обязательного изучения. Кроме того, мы с Вами разберемся в родственных связях HTML элементов, узнаем какие элементы являются родительскими, дочерними и даже сестринскими.
Многие термины, которые вы прочитаете в этой статье, будут использоваться в дальнейших статьях этого учебника, прошу Вас внимательно их изучить и понять. Понимание древовидной структуры документа Вам понадобится не только при изучении CSS, но и при изучении, например, клиентского JavaScript.
Древовидная структура HTML документа
Рассмотрим следующее изображение:
Рис. 8 Пример древовидной структуры HTML.
Любой HTML код имеет древовидную структуру, в которой первый используемый тег — <html> выступает предком (прародителем) всех остальных элементов, из него выходят такие элементы как <head> и <body>:
Рис. 8а Предок в HTML документе.
HTML элемент, расположенный внутри другого элемента является его потомком. Элемент <title> потомок <head>, а элемент <h3> и <p> на изображении потомки <body>.
Рис. 8б Потомки в HTML документе.
Обратите внимание на важный момент, что элемент <i> является потомком одновременно для элемента <p>, <body> и для <html>.
Рис. 8в Потомок для нескольких элементов.
Родительский элемент связан с другими элементами более низкого уровня и находится на один уровень выше их. Например, <html> элемент является родительский элементом для <head> и <body>, а элемент <p> является родительским для элемента <i>.
Рис. 8г Родительские элементы в HTML документе.
Элемент, подчиненный другому элементу более высокого уровня, является дочерним. На изображении ниже оба элемента <h3> и <p> являются дочерними по отношению к <body>, но элемент <i> при этом не является дочерним для элемента <body>, так как он расположен внутри тега <p>, и является дочерним именно для него.
Рис. 8д Дочерние элементы в HTML документе.
Дочерние элементы для одного и того же родительского элемента, называются элементами одного уровня (соседними элементами, или сестринскими элементами). Например, такие элементы как <head> и <body>, или <h3> и <p>.
Еще раз акцентирую ваше внимание на том, что сестринские элементы расположены на одном уровне в пределах одного родителя. К примеру, элементы <h3> и <title> являются просто элементами одного уровня, а не сестринскими элементами.
Рис. 8е Сестринские элементы в HTML документе.
И так, с родственными связями мы пока остановимся, у нас же тут не ток шоу с Андреем Малаховым, верно? Вернемся к селекторам потомков, которые, используя древовидную структуру HTML документа, позволяют форматировать вложенные элементы по нашему усмотрению.
Селекторы потомков
В конце предыдущей статьи, мы с Вами уже рассматривали примеры с селекторами потомков, их основное назначение заключается в том, чтобы единообразно отформатировать элементы, которые расположены внутри других элементов (содержатся внутри других элементов).
Например, во всех заголовках <h3>, в которых находится текст, отражённый курсивом (элемент <i>), вы хотите выделить определённым цветом. Решение этого вопроса, надеюсь, для Вас выглядит вполне очевидно, и вы используете для этой задачи селектор потомков:h3 i { color: red; }
Вместо h3 i в нашем случае можно воспользоваться и универсальным селектором h3 *, так как внутри элемента <h3> находится только один элемент, но если мы захотим, добавить еще какой-то элемент, то придется изменять стили.
У Вас может возникнуть вопрос: почему мы просто не создали селектор класса для i? Благодаря селектору потомка у нас отсутствует необходимость с использованием глобального атрибута class назначать каждому элементу <i> свой класс, что может значительно сэкономить наше время.
Рассмотрим этот пример:
<!DOCTYPE html> <html> <head> <meta charset = "UTF-8"> <title>Cелекторы потомков</title> <style> .test { background-color: lime; /* задаём цвет заднего фона */ color: white; /* задаём цвет шрифта*/ font-size: 30px; /*Указываем размер шрифта*/ height: 40px; /* указываем высоту элемента*/ text-align: center; /* горизонтальное выравнивание текста по центру */ } h3 i { color:red; /* задаём цвет шрифта*/ } </style> </head> <body> <h3 class = "test">Заголовок <i>второго</i> уровня</h3> <h3>Заголовок <i>второго</i> уровня</h3> <h3>Заголовок <i>второго</i> уровня</h3> </body> </html>
В этом примере мы использовали селектор потомков, чтобы выделить определенным цветом все элементы <i>, размещенные внутри элементов <h3>. Кроме того, для первого элемента <h3> мы создали с помощью селектора класса определенный стиль.
Результат нашего примера:
Рис. 9 Пример использования селектора потомков.Думаю, Вы уже начали осознавать какие возможности даёт CSS в оформлении веб страниц, но это только начало нашего пути в изучении, давайте рассмотрим другие примеры, постепенно все более углубляясь в тонкости использования таблиц стилей на ваших страницах.
В следующем примере я разместили три ссылки (элементы <a>) внутри элемента маркированного списка (элемент <li>), и разместил еще одну ссылку внутри абзаца:
Рис. 10 Древовидная структура страницы.
При создании селектора потомков вы объединяете селекторы вместе согласно «ветви дерева» документа, помещая самого старшего родителя слева, а форматируемый элемент располагаете справа.
Селекторы, которые будут работать аналогично и выбирать элементы <a> внутри элементов <li>:
html body ul li a {блок объявлений} html ul li a {блок объявлений} html li a {блок объявлений} body ul li a {блок объявлений} body li a {блок объявлений} ul li a {блок объявлений} li a {блок объявлений}
Обратите внимание, что селекторы потомков могут включать более двух элементов, то есть содержать весь путь по дереву страницы, или наоборот могут не включать какие-то элементы, которые вложены по пути к форматируемому элементу и это тоже будет работать. Старайтесь без необходимости не включать «лишние» селекторы по пути к форматируемому элементу и использовать короткие селекторы.
Используя селектор потомков, давайте отформатируем ссылки, которые находятся только внутри элементов маркированного списка:
li a { text-decoration: none; /* убираем декорирование текста (нижнее подчеркивание под ссылкой) */ font-size: 20px; /* устанавливаем размер шрифта */ }
Как вы понимаете, ссылка, помещённая внутри элемента <p> не будет отформатирована, для неё мы создадим свой стиль:
p a { color: #000; /* устанавливаем черный цвет текста */ background-color: yellow; /* устанавливаем цвет заднего фона */ }
Теперь соберем это в одном примере и посмотрим результат:
<!DOCTYPE html> <html> <head> <meta charset = "UTF-8"> <title> Декорирование ссылок с использованием селекторов потомков</title> <style> li a { text-decoration: none; /* убираем декорирование текста (нижнее подчеркивание под ссылкой) */ font-size: 20px; /* устанавливаем размер шрифта */ } p a { color: #000; /* устанавливаем черный цвет текста */ background-color: yellow; /* устанавливаем цвет заднего фона */ } </style> </head> <body> <p> Нажмите для перехода к поиску <a href = "http://yandex.ru"> Яндекс</a></p> <ul> <li><a href = "http://yandex.ru">Яндекс</a></li> <li><a href = "http://yandex.ru">Яндекс</a></li> <li><a href = "http://yandex.ru">Яндекс</a></li> </ul> </body> </html>
Результат нашего примера:
Рис. 11 Пример декорирования ссылок с использованием селекторов потомков.Продвинутое использование селекторов потомка
Рассмотрим пример, который более приближен к текущим реалиям, а именно комбинирование селекторов класса, а не селекторов типа, как мы рассматривали в примерах выше.
Предположим, что вы создаете страницу о сотрудниках Вашей организации. Вам необходимо разместить следующую информацию о каждом сотруднике: его фото, фамилия и имя, телефон и адрес электронной почты.
Предлагаю каждого сотрудника поместить в отдельный контейнер (элемент <div>) и внутри контейнера отдельно стилизовать контактные данные о сотруднике:
<div class = "top-card"> /* создаем контейнер с классом top-card */ <img src = "nich.jpg"> /* добавляем фото сотрудника */ <p class = "name">Boris Britva</p> /* добавляем абзац с классом name (фамилия имя сотрудника) */ <p class = "phone">88005553535</p> /* добавляем абзац с классом phone (телефон сотрудника) */ <p>[email protected]</p> /* добавляем абзац с адресом электронной почты сотрудника */ </div>
Затем мы создаем стили для контейнера и селекторов потомков:
.top-card { /* выбирает контейнер с классом top-card */ border: 5px solid orange; /* создаем сплошную границу оранжевого цвета размером 5 пикселей */ width: 100px; /* задаем ширину элемента */ } .top-card img { /* выбирает все изображения (элемент <img>) внутри контейнера с классом top-card */ width: 100px; /* задаем ширину изображения */ height: 100px; /* задаем высоту изображения */ border-bottom: 1px solid; /* устанавливаем сплошную границу снизу размером 1 пиксель (черный цвет по умолчанию) */ } .top-card .name { /* выбирает элементы с классом name внутри контейнера с классом top-card */ color: blue; /* устанавливаем цвет текста */ } .top-card .phone { /* выбирает элементы с классом phone внутри контейнера с классом top-card */ color: red; /* устанавливаем цвет текста */ } .top-card p { /* выбирает все абзацы (элемент <p>) внутри контейнера с классом top-card */ text-align: center; /* горизонтальное выравнивание текста по центру */ }
Теперь соберем это в одном примере и посмотрим результат:
<!DOCTYPE html> <html> <head> <meta charset = "UTF-8"> <title> Стилизация карточки сотрудника</title> <style> .top-card { /* выбирает контейнер с классом top-card */ border: 5px solid orange; /* создаем сплошную границу оранжевого цвета размером 5 пикселей */ width: 100px; /* задаем ширину элемента */ } .top-card img { /* выбирает все изображения (элемент <img>) внутри контейнера с классом top-card */ width: 100px; /* задаем ширину изображения */ height: 100px; /* задаем высоту изображения */ border-bottom: 1px solid; /* устанавливаем сплошную границу снизу размером 1 пиксель (черный цвет по умолчанию) */ } .top-card .name { /* выбирает элементы с классом name внутри контейнера с классом top-card */ color: blue; /* устанавливаем цвет текста */ } .top-card .phone { /* выбирает элементы с классом name внутри контейнера с классом top-card */ color: red; /* устанавливаем цвет текста */ } .top-card p { /* выбирает все абзацы (элемент <p>) внутри контейнера с классом top-card */ text-align: center; /* горизонтальное выравнивание текста по центру */ } </style> </head> <body> <div class = "top-card"> /* создаем контейнер с классом top-card */ <img src = "nich.jpg"> /* добавляем фото сотрудника */ <p class = "name">Boris Britva</p> /* добавляем абзац с классом name (фамилия имя сотрудника) */ <p class = "phone">88005553535</p> /* добавляем абзац с классом phone (телефон сотрудника) */ <p>[email protected]</p> /* добавляем абзац с адресом электронной почты сотрудника */ </div> </body> </html>
Результат нашего примера:
Рис. 12 Пример стилизации карточки сотрудников с использованием селекторов потомков.Вопросы и задачи по теме
Перед тем как перейти к изучению следующей темы пройдите практическое задание:
- Для выполнения задания вам понадобится скачать архив и скопировать содержимое архива (HTML файл с изображениями) в любую папку на вашем жестком диске:
- Составьте следующую HTML страницу:
Практическое задание № 3.
После того как вы выполните упражнение проинспектируйте код страницы, открыв пример в отдельном окне, чтобы убедиться, что вы все выполнили правильно.
Css селектор: Родительский и дочерний элемент
Мне трудно поверить, что это никому не ясно, но вот идет.
Предки -это элементы, которые являются родителями или прародителями (или great-grand-parents и так далее). Это означает, что они находятся выше в структуре HTML. Сравните это с вашей семьей. Ваш отец-это ваш родитель, его отец-это его родитель и ваш дедушка, и так далее. Ты-дитя своего отца.
<div>
<div></div>
</div>
При рассмотрении первого элемента набора дочерних элементов, который называется first-child
и может быть выбран как таковой с помощью CSS3. Например, в этом HTML:
<ul>
<li>First list item</li>
<li>Second list item</li>
<li>Third list item</li>
</ul>
в сочетании с этим CSS:
li:first-child {color: red;}
первый элемент списка «First list item» будет иметь красный цвет, но другие элементы списка не будут. все li
являются дочерними элементами (или «дочерними элементами») одного и того же родителя, который является ul
с ID «parent». Элементы списка-это братья и сестры друг друга , они братья и сестры, если хотите.
С той же логикой :last-child
выбирает последний дочерний элемент в наборе. Так что с этим CSS
li:last-child {color: blue;}
последний элемент в списке, т. е. «третий элемент списка», будет иметь синий цвет. Вы можете увидеть :first-child
и :last-child
в действии здесь .
БУДЬТЕ ОСТОРОЖНЫ, ХОТЯ!
В некоторых случаях может потребоваться использовать :first-of-type
вместо :first-child
! Видите ли, первый ребенок выбирает первого ребенка независимо от того, какой это тип, тогда как first-of-type, как следует из названия, выбирает первый элемент этого типа.
Следующий HTML объясняет это.
<div>
<span>I am the first child and also the first of type "span"!</span>
<span>I am neither the first child, but second, nor first of type "span" :(</span>
<span>I am neither the first child, but third, nor first of type "span" :(</span>
<blockquote>I might not be the first child, but fourth, but I am the first of my type "blockquote!" Funny enough, I am also the last of my type!</blockquote>
<span>And I am just sitting here, being the last-child and the last of my type "span"</span>
</div>
Смотрите его в действии в этом Fiddle !
CSS Родительский и дочерний селектор правильный синтаксис
В последнее время я вижу CSS вот так:
1.
.header {
position: relative;
max-height: 1000px;
z-index: 1;
.sidebar{
padding: 25px 25px;
}
.menu{
border-radius:0;
min-height: 30px;
height:100px;
i{
color:#CCC !important;
width:40px;
}
}
}
Я думаю, что header
-это родительский класс, а sidebar
и menu
-дочерние классы header
.
Является ли это допустимым синтаксисом CSS или хорошей практикой?
Обычно я ожидал бы CSS вот так:
2.
.header { ... }
.header .sidebar { ... }
.header .menu { ... }
или даже больше
3.
.header { ... }
.header > .sidebar { ... }
.header > .menu { ... }
В чем разница между этими 3 случаями?
css css3 css-selectors parent-child Поделиться Источник user2456977 07 ноября 2017 в 15:022 Ответа
2
Первый выглядит так, как будто это SCSS или LESS (или какой-то другой препроцессор CSS), а не CSS, который отображается как #2., чтобы дать вам представление о разнице между использованием >
и не является:
.header .sidebar { ... }
.header .menu { ... }
Выбирает .sidebar
и .menu
в любом месте внутри .header
.
<div>
<div></div>
<div></div>
</div>
<div>
<div>
<div></div>
<div></div>
</div>
</div>
Код работает в обоих случаях, описанных выше. В то время как, если вы используете:
.header > .sidebar { ... }
.header > .menu { ... }
Приведенный выше код не будет вторым, который завернут в .wrap
. Второй код является прямым потомком или прямым дочерним селектором .
Поделиться Praveen Kumar Purushothaman 07 ноября 2017 в 15:06
0
Первая структура-это SCSS (препроцессор css). Вот в чем разница между первым и 2&3.
SCSS-это специальный тип файла для SASS, программы, написанной на языке Ruby, которая собирает таблицы стилей CSS для браузера. SASS добавляет множество дополнительных функций к CSS, таких как переменные, вложенность и многое другое, что может сделать написание CSS проще и быстрее. SCSS файлы обрабатываются сервером, на котором запущено веб-приложение, чтобы вывести традиционный CSS, который ваш браузер может понять.
Разница между 2&3 заключается в использовании >
, что означает «прямой дочерний селектор». Например, .header .sidebar
выберет все .sidebar
, которые находятся внутри .parent
, независимо от того, являются ли они детьми или внуками и т. д.
<parent>
<child></child>
<child>
<grandchild></grandchild>
</child>
</parent>
Так что он выберет ребенка и внука и дальше вниз по дереву.
При использовании >
будет выбран только child
, а не grandchild
Поделиться Mihai T 07 ноября 2017 в 15:08
Похожие вопросы:
CSS дочерний селектор, но есть тег a
Не удается получить синтаксис для: nth (3) селектор на этом теге, в 3-м теге li. Какой полный рот. Это вообще возможно? На этом сайте www.cutlassandcane.com/shopping / Я пытаюсь изменить цвет 3-го…
CSS Родительский селектор?
Возможный Дубликат : Есть ли CSS Родительский селектор? Рассмотреть этот markup: <div> <div> <p id=my_paragraph>Squirrels!</p> </div> <div>…
Родительский селектор в css?
Как я могу получить родительский элемент по ссылке с их дочерним элементом, используя pure css? #checkbox{ width: 24px; height: 24px; vertical-align: middle; } #checkbox:checked (parentName){ color:…
«этот» родительский селектор не работает
http://jsfiddle.net/raduv118 / У меня есть две функции jQuery, соответственно отображающие или скрывающие div, вложенные в div, вложенные в список. Первая функция применяет CSS display: block , а…
Есть ли селектор CSS «haschildren»?
Возможный Дубликат : Есть ли Родительский селектор CSS? Есть ли селектор css, который я могу использовать только в том случае, если существует дочерний элемент? Считать: <div> <ul>…
Селектор Css «parent» или «this»
Возможный Дубликат : Есть ли CSS Родительский селектор? Есть ли какой-то селектор .this в css? Или, может быть, родительский селектор? Спасибо
Как скрыть Родительский div, сохраняя дочерний div видимым в HTML, CSS?
Во время работы на моей странице HTML я столкнулся со сценарием, в котором у меня есть два элемента div (скажем, родитель и ребенок). Теперь дело в том, что я хочу скрыть Родительский div, но…
CSS множественный Родительский селектор
Я бы изменил правило CSS для фона на li.li-class, если бы оно содержало h4 . У меня есть HTML, как это: <div class=div-class> <ul> <li class=li-class> <span…
Less Непосредственный Родительский Селектор
Less позволяет выбрать Родительский селектор ( http://lesscss.org/features/#parent-selectors-feature ) Как получить непосредственный Родительский селектор, а не корневой Родительский селектор?
Css селектор: Родительский и дочерний элемент
Pls кто-то должен направить меня, кратко объяснив, что подразумевается под родительским элементом или дочерним элементом в css. Я прочитал много учебника по селектору css, где эти термины всегда…
Последний на CSS Родительский селектор
Исследование завершилось тем, что селектор субъекта (собственное имя для так называемого «родительского селектора») был заменен на гораздо более универсальный псевдокласс :has()
, который задокументирован здесь (с интересным именем якоря, #relational
, интересно, будет ли это придерживаться).
Реализации, вероятно, появятся только тогда, когда спецификация для этой функции будет более стабильной. В настоящее время, с такими разрушительными изменениями, как полная замена селектора субъекта псевдоклассом, я не рассчитываю на то, что это произойдет в ближайшее время. Тем не менее, вполне вероятно, что псевдокласс :has()
будет придерживаться, но может ли он быть реализован в CSS, остается неясным из-за самой его природы. См. Этот раздел того же проекта , чтобы узнать о профилях реализации.
Причина, по которой :has()
является более универсальным, заключается в том, что с помощью селектора субъекта никогда не было ясно, может ли один комплексный селектор иметь более одного селектора субъекта (поскольку один комплексный селектор может иметь только один субъект) и/или если функциональные псевдоклассы, такие как :matches()
, принимают селектор субъекта. Но поскольку псевдокласс-это простой селектор, вы знаете, что :has()
может быть принят везде, где принят псевдокласс.
Например, это делает вполне теоретически возможными такие селекторы, как следующие:
/*
* Select any p
* that is a sibling of a ul
* that has more than one li child.
*/
ul:has(> li:nth-of-type(2)) ~ p, /* p follows ul */
p:has(~ ul:has(> li:nth-of-type(2))) /* p precedes ul */
В то же время, используя селектор субъекта, это было бы возможно только в том случае, если бы :matches()
принял селектор субъекта, который никогда не был указан непосредственно в спецификации:
ul:matches(! > li:nth-of-type(2)) ~ p, /* p follows ul */
!p ~ ul:matches(! > li:nth-of-type(2)) /* p precedes ul */
Вы также можете увидеть здесь, почему мне не нравится имя «parent selector» для любой формы селектора — его можно использовать для гораздо большего .