Технически, CSS не имеет возможности считать родных элементов. Тем не менее, Хейдон недавно показал нам то, что он называет количественными запросами : умная комбинация элементов :nth-last-child() :first-child и ~ для элементов стиля, основанных на количестве элементов в одном родителе. Взгляните на эту статью A List Apart и мою интерактивную демонстрацию по CodePen, чтобы понять, что происходит.
Как работают количественные запросы
Вот основная суть количественных запросов: используя вместе :nth-last-child($n) и :first-child , вы можете идентифицировать элемент, который является определенным числом от конца его братьев и сестер и первого потомка его родителя. , Число с конца говорит нам количество братьев и сестер. Например, селектор :nth-last-child(6):first-child выберет только первый элемент в группе из 6 элементов. Если вы выберете этот элемент и все последующие элементы, используя ~ , вы можете написать собственный CSS для группы элементов в зависимости от их количества.
:nth-last-child(6):first-child, :nth-last-child(6):first-child ~ * { // unique CSS for elements when there are 6 of these }
Этот код позволяет вам ориентироваться на конкретное количество, но, скажем, вы хотите изменить стили, когда есть «по крайней мере» или «меньше» определенного числа. Вы можете сделать это, изменив значение :nth-last-child() . Чтобы нацелить группы по крайней мере из 6 элементов, используйте :nth-last-child(n + 6):first-child и для групп менее 6, используйте :nth-last-child(-n + 6):first-child ,
Написание количественных запросов с помощью Sass
Приведенный выше код великолепен, но давайте используем Sass, чтобы сделать его более сухим: нам не нужно переписывать весь синтаксис везде, где мы хотим использовать эту технику. Мы начнем с одного миксина, который принимает два параметра: число и сравнение:
@mixin quantity-query( $number, $comparison: 'equal' ) { // generate code in here }
Здесь $number будет целым числом: то, что вы хотите, чтобы CSS считал. $comparison будет одним из трех значений: greater , less или equal . Мы определим equal как значение $comparison по умолчанию, если ничего не указано.
Первое, что мы сделаем внутри нашего миксина, это установим значение :nth-last-child() на основе $number и $comparison :
@if index( ('greater' 'more' '>'), $comparison ) { $nth: 'n + #{$number}'; } @else if index( ('less' 'fewer' '<'), $comparison ) { $nth: '-n + #{$number}'; } @else if index( ('equal' 'same' '='), $comparison ) { $nth: $number; } @else { @warn "Sorry, that's an invalid $comparison value." }
У нас есть небольшая свобода: вы можете указать « greater , « more или '>' для $comparison превышающего $comparison . Вы можете указать less , fewer или '< ' для $comparison меньше чем $comparison . Вы можете указать equal , same или '=' для $comparison с равным $comparison . Примечание: если вы используете символы, обязательно заключите их в кавычки.
На основе значения $comparison значение :nth-last-child() устанавливается в виде строки. Мы используем интерполяцию Sass внутри этой строки ( #{$variable} ), потому что мы хотим, чтобы число было частью строки, а не частью уравнения.
После того, как мы получим правильное значение для :nth-last-child() , мы выведем наши селекторы:
&:nth-last-child(#{$nth}):first-child { &, & ~ * { @content; } }
Символ & в передней части означает, что мы прикрепляем псевдоселекторы к селектору, в котором вы используете этот миксин. Если вы поместите его в блок .item {} , вы получите .item:nth-last-child… . Внутри селектора для первого элемента есть еще один & за которым следует & ~ * : это применяет стили к первому элементу группы и всем ее родным элементам. Примечание: я знаю, что не всем нравятся * селекторы, но для защиты вложенности Sass это самый безопасный вариант для нас здесь.
@content; Директива просто повторяет любой CSS, который вы пишете в миксине, когда вы его используете.
Бонус Mixins для скорости!
Мы можем использовать этот миксин просто так, как он есть:
.menu-item { @include quantity-query(5, greater) { color: blue; } }
… и мы получим:
.menu-item:nth-last-child(n+5):first-child, .menu-item:nth-last-child(n+5):first-child ~ * { color: blue; }
Но мы можем сделать это лучше с помощью псевдонимов:
@mixin qq-equal( $number ) { @include quantity-query( $number, equal ) { @content; } } @mixin qq-greater( $number ) { @include quantity-query( $number, greater ) { @content; } } @mixin qq-less( $number ) { @include quantity-query( $number, less ) { @content; } }
Теперь вы можете использовать уникальный миксин для каждого значения сравнения, если это улучшит ваш рабочий процесс.
Помимо меню
Пока что большинство демонстраций этой функции — меню. Но эта техника может сделать намного больше! Вот пример реального использования, которое мне удалось решить с помощью количественных запросов.
Недавно дизайнер дал мне комп для страницы, которая отображала четыре категории контента: каждая категория имела заголовок и список ссылок на отдельные части контента. Наиболее разумная разметка для этого контента:
<div class="content-category"> <h3 class="content-category-title">Title</h3> <ul class="content-category-list"> <li class="content-category-list-item">Item</li> </ul> </div> [*4]
На рабочих столах эти категории размещены в столбцах. Это достаточно просто. Тем не менее, дизайнер увидел другой макет для небольших экранов: все 4 заголовка должны быть вверху страницы и действовать как переключатели, чтобы показывать / скрывать элементы в своих списках под всеми заголовками. На левой стороне следующего изображения вы можете увидеть макет «рабочего стола»; на правой стороне разделителя вы можете увидеть «мобильную» раскладку:
Скорее всего, здесь можно было бы создать второй контейнер с копиями заголовков и использовать эти элементы для переключения триггеров на маленьких экранах, а затем скрыть его на больших экранах. Но с другой стороны, мы могли бы сохранить хорошую разметку, которую я описал выше, и использовать количественные запросы, чтобы исправить наш макет. Вот как я это сделал:
- На маленьких экранах размещайте заголовки абсолютно; позиционируйте их статически после большей точки останова.
- Используйте количественные запросы, чтобы определить, как далеко от вершины должен располагаться список на маленьких экранах.
Хотя соревнования начинались с 4 категорий, я всегда подозреваю, что в будущем клиент может захотеть 3, 5 или 7 категорий. Чтобы подготовиться к этим случаям, я дважды использовал цикл @for в этом коде. Во-первых, я перебрал от 1 до $max ( $max в настоящее время установлено на 7, но может быть изменено для учета более высоких пределов в будущем). Цикл внутри .content-category (строка 55) вызывает mixin qq-equal() и создает необходимые отступы в верхней части каждого списка на основе количества категорий. Цикл внутри .content-category-title (строка 93) не использует количественный запрос; он просто устанавливает top позицию каждого заголовка в зависимости от того, к какой категории он относится ( :nth-child() ).
Вот демоверсия из CodePen:
Вывод
С парой циклов @for и нашими @for количественных запросов мы смогли сохранить разумную семантическую разметку и создать расширенный адаптивный макет для этого дизайна. Не стесняйтесь брать миксины из этой истории Сассмайстера и делиться своим творческим запросом количества в комментариях!