Родительские селекторы

В этой статье мы с Вами расширим наши знания об использовании различных CSS селекторов в LESS, научимся работать с псевдоэлементами, и рассмотрим использование специального оператора &, который представляет из себя ссылку на родительский элемент внутри вложенного правила. Подробную информацию о правилах вложенности вы можете получить в статье этого учебника «Правила вложенности».

Рис.11 Ссылка на родительский селектор.

До того как вы перейдете к прочтению статьи, рекомендую Вам освежить, или получить знания из актуального учебника 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.
Рис. 12 Пример работы с псевдоклассами в LESS.

Использование методологии БЭМ

Применение оператора родительского элемента можно встретить не только вместе с псевдоклассами, но зачастую и при написании CSS кода по такой методологии веб-разработки как БЭМ (Блок-Элемент-Модификатор). Обязательно ознакомьтесь с ней в свободное время, она предлагает общую семантическую модель для всех технологий, использующихся во фронтэнд разработке (HTML, CSS, JavaScript, шаблоны проектирования и так далее).

Обратите внимание на следующее изображение:

Рис.13 Пример организации CSS кода по БЭМ.

Рис.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;
	}
}

Как вы можете заметить при использовании селекторов потомков, дочерних элементов, следующих элементовcss3 и смежных элементов наличие оператора родительского элемента (для ссылки на родителя) будет носить лишь декоративный характер, так как компиляция даст валидный (одинаковый) результат в обоих случаях:

.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;
}