Стилизация путем подсчета смежных элементов

Оцените материал
(0 голосов)

Проблема

Можно назвать много ситуаций, когда возникает необходимость определять для элементов разные стили в зависимости от того, сколько у них всего смежных элементов. Главный сценарий использования здесь — улучшение восприятия пользователем и экономия экранного пространства в раскрывающемся списке за счет скрывания элементов управления или уменьшения их в размере по мере увеличения списка. Вот несколько примеров: ‰ список сообщений электронной почты или схожих текстовых элементов. Если их всего лишь несколько штук, то для предварительного просмотра элементов мы можем отображать большие текстовые отрывки.

По мере того как список растет, мы сокращаем количество строк в области предварительного просмотра. Когда длина списка становится больше высоты окна просмотра, мы можем даже полностью скрыть текстовые отрывки и уменьшить размер кнопок, для того чтобы минимизировать необходимость прокрутки; ‰ приложение с напоминаниями о предстоящих делах, в котором каждый элемент отображается крупным шрифтом, пока элементов не много. Чем больше элементов создает пользователь, тем меньше мы делаем размер шрифта (для всех элементов);
‰ приложение с цветовой палитрой, в котором элементы управления отображаются на каждом образце цвета. Эти элементы управления можно делать более компактными по мере того, как количество цветов растет, а место, занимаемое каждым образом, соответственно уменьшается;
‰ приложение с несколькими элементами  <textarea> , в котором все их приходится уменьшать с добавлением каждого нового элемента.


Однако с помощью селекторов CSS решить задачу по выбору элементов в зависимости от общего количества «братьев» не так-то просто. Предположим, мы хотели бы применить определенные стили к элементам списка в случае, когда общее количество элементов равно 4. Мы могли бы использовать  li:nth-child(4) для выбора четвертого элемента в списке, но это не то, что нам нужно;нам необходимо выбрать все элементы, но только в том случае, когда их общее число равно четырем.

Следующей идеей могло бы быть использование обобщенного комбинатора «братьев» ( ~ ) совместно с  :nth-child() , как в  li:nth-child(4) ,  li:nthchild(4) ~ li. Однако при этом в выборку попадают только четвертый потомок и элементы после него, независимо от общего количества. Так как не существует комбинатора, который мог бы «оглянуться назад» и выбрать предыдущих «братьев», следует ли вовсе отказаться от попыток добиться нужного результата с помощью CSS?  Нет, давайте не терять надежды.

Решение

Для особого случая, когда элемент ровно один, существует очевидное решение: селектор  :only-child, созданный специально для этого. Он не только удобен в качестве отправной точки; существуют несколько сценариев использования, требующих именно этого селектора, и поэтому он был добавлен в спецификацию. Например, обратите внимание, что на рисунке мы скрываем кнопку удаления, когда на экране остается только один цвет. Это можно реализовать с помощью селектора CSS  :only-child:

li:only-child {
/* Стили для ситуации, когда элемент только один */
}

Но селектор  :only-child эквивалентен  :first-child:last-child . Причина очевидна: если первый элемент также является последним элементом, то отсюда логически вытекает, что он единственный элемент. Кроме того,  :last-child — это сокращение для  :nthlast-child(1) :

li:first-child:nth-last-child(1) {
/* То же самое, что и li:only-child */
}

Теперь у нас есть параметр — в данном случае это 1, — и мы можем настраивать его по своему усмотрению. Попробуйте угадать, какие элементы выбирает селектор  li:first-child:nth-last-child(4) . Если ваш ответ заключается в том, что это обобщение  :only-child для выбора элементов списка, когда их общее количество равно четырем, то вы слишком оптимистичны. Мы еще не достигли желаемой цели, хотя уже находимся на правильном пути.

Попробуйте думать об этих псевдоклассах по отдельности: мы ищем элементы, которые подходят под оба условия: и  :first-child , и  :nth-last-child(4) . Следовательно, нас интересуют элементы, одновременно являющиеся первым потомком своего родителя, если считать от начала, и четвертым потомком, если считать от конца. Какие элементы удовлетворяют этим критериям? Ответ прост: первый элемент в списке, состоящем в точности из четырех элементов. Это не совсем то, чего мы хотели, но очень близко: поскольку теперь мы знаем, как выделить первого потомка в таком списке, мы можем использовать общий комбинатор потомков ( ~ ) для выбора каждого потомка, следующего за таким первым потомком.

По сути, мы выберем все элементы в списке в том и только том случае, когда список состоит из четырех элементов, а это как раз то, чего мы пытаемся добиться:

li:first-child:nth-last-child(4),
li:first-child:nth-last-child(4) ~ li {
/* Выбор всех элементов списка, если список
содержит ровно четыре элемента */
}

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

SCSS
/* Определение примеси */
@mixin n-items($n) {
&:first-child:nth-last-child(#{$n}),
&:first-child:nth-last-child(#{$n}) ~ & {
@content;
}
}
/* Использовать так: */
li {
@include n-items(4) {
/* Свойства и значения */
}
}


Выбор по диапазону количества смежных элементов

В самых практичных приложениях мы хотели бы задавать не конкретные количества элементов, а некие диапазоны. Есть удобный трюк, позволяющий заставлять селекторы  :nth-child() выбирать диапазоны, например: «все после четвертого потомка». Помимо обычных чисел, в качестве параметров для них можно также указывать выражения в формате an+b (скажем,  :nth-child(2n+1) ), где  n — переменная в диапазоне от 0 до +∞ в теории (на практике значения после определенного лимита перестают выбирать что-либо, так как количество элементов у нас конечно). Если мы используем выражение в форме n+b (подразумевается, что  a равно 1), то не существует положительного целого  n , которое могло бы дать нам значение, меньшее  b . Следовательно, выражения в форме  n+b можно использовать для выбора всех потомков, начиная с  b -го и дальше. Например,  :nth-child(n+4) выбирает всех потомков, за исключением первого, второго и третьего.


Мы можем использовать это полезное качество для выбора элементов списка в ситуации, когда общее количество элементов составляет четыре или больше. В данном случае в качестве выражения, передаваемого  :nth-last-child() , следует использовать  n+4: li:first-child:nth-last-child(n+4),

li:first-child:nth-last-child(n+4) ~ li {
/* Выбор всех элементов списка, если список содержит
по меньшей мере четыре элемента */
}

Схожим образом, выражения в форме  -n+b можно использовать для выбора первых  b элементов. То есть для выбора всех элементов списка в том и только том случае, если общее количество элементов в одном и том же списке равно четырем или менее, мы бы написали:

li:first-child:nth-last-child(-n+4),
li:first-child:nth-last-child(-n+4) ~ li {
/* Выбор всех элементов списка, если список
содержит максимум четыре элемента */
}

Разумеется, мы бы могли объединить два решения, но код при этом станет еще более тяжеловесным. Предположим, что мы хотим выбрать все элементы списка, когда в списке содержится от 2 до 6 элементов:

li:first-child:nth-last-child(n+2):nth-last-child(-n+6),
li:first-child:nth-last-child(n+2):nth-last-child(-n+6) ~ li {
/* Выбор всех элементов списка, если список содержит
от 2 до 6 элементов */
}


ПОПРОБУЙТЕ САМИ!

http://play.csssecrets.io/styling-sibling-count

Десерт на сегодня - забавное видео о том, как ест собака

Прочитано 330 раз Последнее изменение Воскресенье, 28 мая 2017 12:56
Другие материалы в этой категории:
Понравилась запись? Подпишитесь на обновления по почте:

Нетология

TemplateMonster

geekbrains.ru/

Поиск по сайту

Google+