Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11
Перетяжка, Премия ТПрогер, 13.11

CSS counters в подходе Atomic CSS - часть 1

CSS Counters - отличный инструмент для работы с кастомными счётчиками. Но применение его не ограничивается только рукописным CSS - его легко и эффективно можно (и нужно!) использовать в рамках Atomic CSS подхода! Давайте же посмотрим, как это сделать!

31 открытий964 показов
CSS counters в подходе Atomic CSS - часть 1

Всем привет, друзья!

Меня зовут Рамазан, и в этой статье мы поговорим о применении CSS counters в подходе Atomic CSS. Статей про сами CSS счётчики довольно много в сети, и на MDN есть очень хороший обзор этого функционала, а также существуют спецификации, на которые я буду опираться. Но мало кто рассказывал про использование кастомных счётчиков в Atomic CSS подходе, поэтому в данной серии статей мы поговорим именно об этом. Работать мы будем на фреймворке mlut - одном из немногих, поддерживающих CSS counters и многие другие возможности прямо из коробки.

В первой статье я расскажу вам про основные вещи: как устроены кастомные счётчики, как их инициализировать, менять и отображать их значения. Кроме того, мы рассмотрим пару несложных примеров для закрепления.

К слову, этот пост является переводом моей оригинальной статьи на Medium — вы можете почитать и её.

Основы

Зачем вообще нужны кастомные CSS счётчики, если у нас есть <ol>? Именно этот вопрос возник у меня, когда я впервые узнал об этом функционале. А применений у него много: вложенные списки, гибкость без потери индексации сайта и даже игры на CSS! Поэтому нам определённо стоит присмотреться к кастомным счётчикам внимательнее.

Работать с кастомными счётчиками мы можем посредством:

- CSS свойств counter-*;

- функций counter() и counters();

- at-правила counter-style.

Жизненный цикл счётчика

Давайте начнём с самой основы. Через что приходится проходить счётчикам прежде, чем их значения украсят элементы нашего интерфейса? В каком порядке применяются упомянутые выше свойства под капотом? Знать это довольно важно - это поможет избежать многих ошибок в будущем.

Так вот:

1) Сначала элемент наследует счётчики от элементов предшественников (это может быть родитель или предшествующий сосед элемента);

2) Потом срабатывает counter-reset и создаётся новый либо вложенный счётчик;

3) Затем работает counter-increment, позволяющий менять значения счётчиков элемента;

4) Потом наступает очередь counter-set, который позволяет вручную задать значение счётчиков элемента;

5) А затем уже вызываются функции counter() и counters().

Далее подробнее поговорим про то, как работают все эти свойства и функции.

counter-reset

Это свойство позволяет создать новый счётчик с указанным именем и начальным значением. А если во множестве счётчиков нашего элемента уже будет счётчик с тем же именем, то будет создан вложенный счётчик. Такое может быть при наследовании счётчиков, но об этом мы поговорим подробно в следующей статье.

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

- элемент, в котором был создан этот счётчик;

- строку с именем счётчика;

- целое число.

Именно с этим набором свойств счётчик затем передаётся потомкам и последующим соседям в процессе наследования.

Давайте инициализируем новый счётчик с помощью утилиты Сor, которой mlut сопоставляет свойство counter-reset:

			<div class="Cor-paragraphs;5 Pl5u">
  <p>Point 1</p>
  <p>Point 2</p>
  <p>Point 3</p>
</div>
		

CSS, сгенерированный движком mlut, будет таким:

			.Cor-paragraphs\;5 {
  counter-reset: paragraphs 5;
}
.Pl5u {
  padding-left: 1.25rem;
}
		

Здесь мы задали счётчик с указанием имени paragraphs и начального значения 5. Вообще говоря, мы можем инициализировать сразу несколько счётчиков. Для этого свойство counter-reset может принимать множество аргументов: строки и целые числа. Числа указывать не обязательно - тогда для соответствующего счётчика будет установлено значение по умолчанию 0. А вот так это делается:

			<div class="Cor-first;second;2"></div>
		
			.Cor-first\;second\;2 {
  counter-reset: first second 2;
}
		

Тут будет создано два счётчика: first с начальным значением 0 и second со значением 2. А вот указывать утилиту Cor несколько раз подряд (или в CSS несколько раз использовать counter-reset в одном элементе) для создания нескольких счётчиков нельзя. Тогда сработают каскады CSS и из всех счётчиков выживет только последний указанный.

Функции counter() и counters()

Отлично, мы создали наш первый кастомный счётчик, а его значение теперь можно использовать в дочерних <p>. Но как нам его отобразить в разметке? Как раз для этого и нужны функции counter() и counters(). Чтобы отобразить значения имеющихся у элемента счётчиков, нам достаточно создать псевдо-элемент ::before и передать в его содержимое данную функцию.

У counter() и counters() разное количество возможных аргументов. У первого их всего два: имя счётчика и стиль, который можно взять из значений list-style-type или задать самостоятельно с помощью @counter-style. У counters() их три: имя счётчика, разделитель между вложенными счётчиками (о них в следующей статье) и стиль.

Попробуем применить первую функцию в простейшем примере:

			 <div class="Pl5u Cor-paragraphs;5">
  <p class="Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 1</p>
  <p class="Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 2</p>
  <p class="Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 3</p>
 </div>
		

CSS:

			.Ct-counter\(paragraphs\,lower-roman\)\;\'\.\'\;\'\;\'_b::before {
  content: counter(paragraphs,lower-roman) '.' ' ';
}

		

Выглядеть это будет примерно вот так:

CSS counters в подходе Atomic CSS - часть 1 1
Шаг 1. Создание счётчика и отобразили значения

Здесь мы использовали утилиту Ct-counter(paragraphs,lower-roman);'.';';'_b, чтобы задать содержимое псевдо-элемента. Часть утилиты ;';' здесь нужна для отображения пробела после точки - тут дело в том, как работает движок mlut. Поставить пробел ' ' прямо в утилиту мы не можем, так как пробелами в CSS разделяются классы, и движок воспримет этот символ как конец текущей утилиты. Поэтому для обозначения пробела в этом случае используется символ ;.

В качестве альтернативы мы можем воспользоваться атрибутом data-ml-ct вот так:

			 <p class="Ct-counter(paragraphs,lower-roman);mAtt_b" data-ml-ct=". ">Point 1</p>
		

CSS:

			.Ct-counter\(paragraphs\,lower-roman\)\;mAtt_b::before {
  content: counter(paragraphs,lower-roman) attr(data-ml-ct);
}
		

Тогда mlut возьмёт значение, указанное в атрибуте data-ml-ct и вставит на место mAtt в утилите. Это тоже хорошее решение, но оно лучше подойдёт для более сложных ситуаций. В данном же случае оно будет избыточным, поэтому в дальнейшем мы будем пользоваться первым способом.

counter-increment

Теперь настало время пронумеровать параграфы разными числами! И для этого нам нужно воспользоваться свойством `counter-increment` посредством утилиты `Coi`. Если же счётчика с указанным в аргументе именем нет, то он будет создан автоматически. Конечно, это кажется удобным, но лучше явно задавать создаваемые счётчики.

Синтаксис у этого свойства точно такой же, как у свойства counter-reset. В простейшем случае оно принимает два аргумента: имя счётчика и целое число (и отрицательное тоже), на которое следует изменить значение счётчика. А множественные аргументы могут включать чередующиеся имена счётчиков и числа, на которые эти счётчики нужно изменить. Причём указывать числа необязательно - если число после имени счётчика отсутствует, то его значение изменится на единицу по умолчанию. Применим это к нашему списку:

			 <div class="Cor-paragraphs;5 Pl5u">
   <p class="Coi-paragraphs;-1 Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 1</p>
   <p class="Coi-paragraphs;2 Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 2</p>
   <p class="Coi-paragraphs Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 3</p>
 </div>
		

CSS:

			.Coi-paragraphs\;-1 {
  counter-increment: paragraphs -1;
}

.Coi-paragraphs\;2 {
  counter-increment: paragraphs 2;
}

.Coi-paragraphs {
  counter-increment: paragraphs;
}
		

Результат будет выглядеть вот так:

CSS counters в подходе Atomic CSS - часть 1 2
Шаг 2. Включаем инкрементацию

Кстати, если вы укажете одно и то же имя счётчика несколько раз в аргументе утилиты Coi, то этот счётчик соответствующее количество раз проинкрементируется. Если же есть вложенные счётчики с таким именем, несколько раз изменится счётчик на самом глубоком уровне вложенности из видимых данным элементом. А вот так можно проинкрементировать счётчик несколько раз:

			<p class="Coi-paragraphs;2;paragraphs Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 2</p>
		

CSS:

			.Coi-paragraphs\;2\;paragraphs {
  counter-increment: paragraphs 2 paragraphs;
}
		

В итоге на таком элементе наш счётчик увеличится сначала на 2, а затем на единицу прежде, чем значение отобразится на экране.

counter-set

Далее рассмотрим свойство counter-set - для него в mlut есть утилита Cos. Это свойство позволяет нам самим задать, какое будет значение у уже существующих счётчиков в обход нормального хода их инкрементирования. Это CSS свойство умеет вызывать создание нового счётчика, если счётчика с нужным именем нет. Но всегда лучше явно задавать новый счётчик, чтобы избежать неожиданных сайд-эффектов.

Данное свойство может также поддерживать и множественные аргументы: имена счётчиков и значения, которые мы для них устанавливаем. Если же мы не укажем число после имени счётчика, то его значение автоматически установится равным нулю.

Давайте применим эту утилиту к последнему параграфу:

			<div class="Pl5u Cor-paragraphs;5">
  <p class="Coi-paragraphs;-1 Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 1</p>
  <p class="Coi-paragraphs;2 Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 2</p>
  <p class="Cos-paragraphs;10 Ct-counter(paragraphs,lower-roman);'.';';'_b">Point 3</p>
</div>
		

CSS:

			.Cos-paragraphs\;10 {
  counter-set: paragraphs 10;
}
		

И вот такой вот кастомный список у нас получится в итоге:

CSS counters в подходе Atomic CSS - часть 1 3
Шаг 3. Применяем задание значения счётчика вручную

Итоги

Спасибо, что дочитали эту статью до конца! В ней мы разобрали основные и наиболее важные моменты в работе с CSS counters в подходе Atomic CSS. Мы проиллюстрировали работу кастомных счётчиков на простом примере и теперь можем пользоваться ими в своих проектах!

В дальнейшем я планирую написать ещё пару статей, глубже раскрывающих принципы работы CSS counters. В частности, я подробнее опишу механизм наследования счётчиков и попробую раскрыть одну особенность их поведения в разных браузерах. Так что оставайтесь на связи!

Успехов вам в увлекательном пути Frontend-разработки!

Следите за новыми постами
Следите за новыми постами по любимым темам
31 открытий964 показов