Статьи

Использование Sass для «количественных запросов»

Технически, 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 заголовка должны быть вверху страницы и действовать как переключатели, чтобы показывать / скрывать элементы в своих списках под всеми заголовками. На левой стороне следующего изображения вы можете увидеть макет «рабочего стола»; на правой стороне разделителя вы можете увидеть «мобильную» раскладку:

Скорее всего, здесь можно было бы создать второй контейнер с копиями заголовков и использовать эти элементы для переключения триггеров на маленьких экранах, а затем скрыть его на больших экранах. Но с другой стороны, мы могли бы сохранить хорошую разметку, которую я описал выше, и использовать количественные запросы, чтобы исправить наш макет. Вот как я это сделал:

  1. На маленьких экранах размещайте заголовки абсолютно; позиционируйте их статически после большей точки останова.
  2. Используйте количественные запросы, чтобы определить, как далеко от вершины должен располагаться список на маленьких экранах.

Хотя соревнования начинались с 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 количественных запросов мы смогли сохранить разумную семантическую разметку и создать расширенный адаптивный макет для этого дизайна. Не стесняйтесь брать миксины из этой истории Сассмайстера и делиться своим творческим запросом количества в комментариях!