Списки CSS, маркеры и счетчики
Опубликовано: 2022-03-10 Списки в CSS имеют определенные свойства, которые дают нам стандартный стиль списка, который мы ожидаем. Неупорядоченный список получает маркер списка типа disc
, а упорядоченные списки нумеруются. Мой интерес к более подробному изучению списков возник после того, как я проделал некоторую работу по документированию ::marker
для MDN. Этот псевдоэлемент поставляется в Firefox 68 и выпускается сегодня . Имея доступный нам ::marker
, мы можем начать делать некоторые интересные вещи со списками, и в этой статье я объясню больше.
Деконструкция списка
Возможно, вы не особо задумывались о списках, хотя мы часто используем их в нашей разметке. Многие вещи вполне логично можно разметить в виде списка. В то время как пошаговые инструкции или ранжированные элементы могут быть естественным образом описаны упорядоченным списком <ol>
, многие элементы дизайна могут быть описаны с помощью неупорядоченного списка <ul>
. Например, очень часто этот элемент используется для разметки навигации, так как это список пунктов назначения на сайте. Для нашего исследования давайте начнем с выяснения того, что такое список в CSS.
Как и многие вещи в CSS, к спискам применяются некоторые начальные значения. Эти значения делают их похожими на список. Эти специальные значения начинаются с информации о том, что элемент списка имеет свойство display
со значением list-item
. Это создает поле уровня блока с дополнительным полем маркера. В поле маркера добавляется маркер списка или номер.
Списки были определены в CSS на раннем этапе, и большая часть определения списков в том виде, в каком мы их используем сегодня, взята из CSS2. Спецификация CSS2 описывает элемент списка следующим образом:
«Элемент сdisplay: list-item
генерирует основное блок-бокс для содержимого элемента и, в зависимости от значенийlist-style-type
иlist-style-image
, возможно, также блок-маркер в качестве визуальной индикации того, что элемент элемент списка».
Блок основного блока является основным блоком элемента и содержит все дочерние элементы, поскольку элемент списка может содержать другую разметку. Затем поле маркера помещается относительно этого основного поля. Далее в спецификации подробно описывается тот факт, что любой цвет фона будет находиться только за этим основным полем, а не за маркером. Кроме того, для маркера можно установить одно из ряда предопределенных значений:
-
disc
-
circle
-
square
-
decimal
-
decimal-leading-zero
-
lower-roman
-
upper-roman
-
lower-greek
-
lower-latin
-
upper-latin
-
armenian
-
georgian
-
lower-alpha
-
upper-alpha
-
none
-
inherit
Спецификация дисплея уровня 3 определяет display: list-item
вместе с другими возможными значениями свойства display
. Он ссылается на CSS 2.1 — как и многие свойства и значения CSS, происходящие из CSS2 — но описывает ключевое слово list-item
как «заставляющее элемент генерировать ::marker
».
Спецификация уровня 3 также вводит возможность создания встроенного элемента списка с использованием синтаксиса с двумя значениями display: inline list-item
. Это еще не реализовано браузерами.
Создание полей маркеров на элементах, не входящих в список
Как и в случае с другими значениями display
, абсолютно допустимо присвоить любому элементу HTML тип отображения элемента list-item
(если вы хотите сгенерировать ::marker
для элемента). Это не приведет к тому, что элемент семантически станет элементом списка, но вместо этого он будет отображаться только визуально как элемент списка и, следовательно, сможет иметь ::marker
. Когда мы обсудим ::marker
ниже, вы обнаружите несколько случаев, когда предоставление другим элементам display: list-item
может быть полезным.
Спецификация списков CSS уровня 3: ::marker
And Counters
Спецификация display
расширяет и уточняет определение списков, которое мы находим в CSS2, однако есть также спецификация, которая подробно определяет поведение списка: Спецификация списков CSS, уровень 3. Поскольку основное поведение элементов списка определено в display
, это Спецификация детализирует поле маркера, сгенерированное, когда что-то имеет display: list-item
вместе со счетчиками, которые используются по умолчанию всякий раз, когда вы создаете упорядоченный список. Через эти функции можно получить доступ к некоторым потенциально полезным функциям.
::marker
::marker
позволяет настроить таргетинг на маркер списка — отдельно от содержимого элемента списка. Это было невозможно в предыдущих версиях CSS, поэтому, если вы изменили цвет или размер шрифта ul
или li
, это также изменило бы цвет и размер шрифта маркеров. Чтобы сделать что-то, казалось бы, простое, например, иметь маркеры списка другого цвета, чем текст, потребуется либо обернуть содержимое элемента списка в диапазон (или использовать изображение для маркера).
ul { color: #00b7a8; } ul span { color #333; }
Самое простое, что вы можете попробовать с ::marker
, — это изменить цвет маркера на цвет текста, что означает, что вместо кода в приведенном выше примере вы можете использовать:
ul { color: #333; } ul ::marker { color: #00b7a8; }
Вы также можете использовать другой размер и font-family
для нумерации в упорядоченном списке.
ol ::marker { font-size: 200%; color: #00b7a8; font-family: "Comic Sans MS", cursive, sans-serif; }
Вы можете увидеть все это в поддерживающем браузере, используя мой пример CodePen:
Вы можете использовать ::marker
для элементов, не входящих в список. В приведенном ниже коде я установил заголовок для display: list-item
. Это дает ему пулю и, следовательно, поле ::marker
для цели.
Я изменил пулю, чтобы использовать смайлик:
h1 { display: list-item; } h1::marker { content: ""; }
В приведенном выше примере я использовал сгенерированный контент в правилах для маркера. Только небольшое подмножество свойств CSS доступно для использования в ::marker
. К ним относятся свойства шрифта и цвет, однако они также включают свойство content
для включения сгенерированного содержимого.
Добавление content
в качестве разрешенного свойства для ::marker
произошло недавно, однако оно включено в реализацию Firefox. Включение означает, что вы можете делать такие вещи, как включение строки текста в ::marker
. Это также открывает дополнительные возможности для форматирования маркеров, когда вы комбинируете использование счетчиков с ::marker
.
Поддержка браузера и запасные варианты
Для браузеров, не поддерживающих ::marker
, запасной вариант — это обычный маркер, который все равно отображался бы. К сожалению, в настоящее время мы не можем использовать Feature Queries для обнаружения поддержки таких селекторов, как этот псевдоэлемент, хотя возникла проблема с добавлением этого в спецификацию. Это означает, что вы не можете разветвить свой код, чтобы делать что-то одно, когда у вас есть поддержка, и что-то еще, если у вас ее нет. В большинстве случаев возврат к обычному маркеру будет разумным решением.
Счетчики
Упорядоченные списки имеют нумерацию списков — это достигается с помощью счетчика CSS. Поэтому спецификация списков CSS также описывает эти счетчики. Мы можем сами получать доступ к счетчикам и создавать их, что в сочетании с ::marker
может дать нам некоторую полезную функциональность. Эти счетчики также можно использовать в обычном (не ::marker
) сгенерированном контенте.
Если у меня есть пронумерованный список шагов (и я хотел бы написать «Шаг 1», «Шаг 2» и т. д.), я могу сделать это, используя сгенерированное содержимое в своем маркере и добавив счетчик list-item
, это представляет встроенный счетчик:
::marker { content: "Step " counter(list-item) ": "; }
Вложенные счетчики
Если у вас есть вложенные списки, общий способ их нумерации состоит в том, чтобы иметь элемент верхнего уровня целым числом (1), затем дочерние элементы как (1.1, 1.2) и их дочерние элементы (1.1.1, 1.1.2), и так далее. Вы можете добиться этого, используя больше функциональных возможностей счетчиков.
Когда вы вкладываете HTML-списки, вы получаете несколько счетчиков с одним и тем же именем, вложенных друг в друга. Доступ к вложению счетчиков можно получить с помощью функции counters()
.
В приведенном ниже коде я использую counters()
для форматирования маркеров списка, как описано выше. Первым аргументом counters()
является имя используемого счетчика. Я использую встроенный счетчик list-item
. Второй аргумент — это строка — это то, что будет конкатенировано между выходными счетчиками (я использую .
). Наконец, я добавляю :
вне функции счетчика, но внутри значения content
, чтобы вывод моего счетчика отделялся от содержимого двоеточием.
::marker { content: counters(list-item,'.') ':'; color: #00b7a8; font-weight: bold; }
Это дает мне вывод, как на изображении. Если вы используете браузер, который поддерживает ::marker
и счетчики, вы можете увидеть, как это работает в примере CodePen — попробуйте изменить строку из файла .
на что-то еще, чтобы увидеть, как это меняет вывод.
В чем разница между counter()
и counters()
?
Функция counter()
, которую мы использовали в первом примере для записи наших шагов, использует только самый внутренний счетчик. Поэтому в ситуации, когда у вас есть набор вложенных списков, вы будете записывать счетчик, относящийся к уровню, на котором вы сейчас находитесь.
Функция counters()
, по сути, записывает всю эту ветвь и дает вам возможность конкатенировать строку между счетчиками в ветви. Итак, если у вас есть элемент списка со счетчиком 2
(который является частью списка, вложенного в элемент списка со счетчиком 4
), то ветвь содержит:
-
4
-
2
Вы можете вывести это как 4.2
в маркере, используя:
::marker { content: counters(list-item,'.'); }
Счетчики на других элементах
Счетчики можно использовать для вещей, которые не являются списками — либо для вывода маркера — в этом случае элемент должен иметь display: list-item
— либо для вывода обычного сгенерированного контента. Счетчики широко используются в книжном производстве, чтобы обеспечить нумерацию глав и рисунков и многое другое. Нет причин не использовать аналогичный подход в Интернете, особенно для более длинных статей.
Свойства CSS, определенные в спецификации списков CSS, которые имеют дело с этими счетчиками:
-
counter-set
-
counter-reset
-
counter-increment
Чтобы увидеть, как они работают вне списков, мы можем рассмотреть пример использования счетчиков для нумерации заголовков в документе.
Первое, что мне нужно сделать, это создать счетчик заголовков в элементе body — и он готов к использованию. Для этого я использую свойство counter-reset
. Свойства counter-reset
и counter-set
очень похожи. Свойство counter-reset
создаст новый счетчик, если счетчик с указанным именем еще не существует, но также создаст вложенные счетчики, как описано выше, если счетчик с таким именем существует. Свойство counter-set
создаст новый счетчик только в том случае, если нет счетчика с таким именем. Для этого использование любого свойства будет работать нормально, однако counter-set
не имеет такой хорошей поддержки браузера, как counter-reset
, поэтому я выбираю практичный путь:
body { counter-reset: heading-counter; }
Теперь, когда у меня есть счетчик, я могу использовать свойство counter-increment
в селекторе для заголовков; это должно увеличивать счетчик каждый раз, когда селектор совпадает.
h2 { counter-increment: heading-counter; }
Чтобы увидеть значение, мне нужно вывести его в документ. Я могу сделать это, используя сгенерированный контент и добавив его before
заголовком, как показано в следующем примере CodePen:
h2::before { content: counter(heading-counter) ": "; color: #00b7a8; font-weight: bold; }
В качестве альтернативы я мог бы превратить элемент h2
в элемент list-item
а затем использовать ::marker
, как показано ниже. Как уже было сказано, использование элемента ::marker
имеет ограниченную поддержку браузера. В Firefox вы должны увидеть счетчик, используемый в качестве маркера для заголовка, в то время как другие браузеры будут отображать маркер по умолчанию.
h2 { display: list-item; } h2::marker { content: counter(heading-counter) ": "; color: #00b7a8; font-weight: bold; }
Счетчики на элементах формы
Существует также небольшая интерактивность, которую вы можете достичь с помощью счетчиков CSS — то, что вы можете подумать, что вам нужен JavaScript.
У меня есть форма, в которой есть несколько обязательных полей. Необходимый статус можно выбрать в CSS с помощью псевдокласса :required
, а тот факт, что поле не заполнено, можно определить с помощью псевдокласса :invalid
. Это означает, что мы можем проверять поля, которые являются обязательными и недействительными, и увеличивать счетчик. Затем выведите это как сгенерированный контент.
Насколько это полезно на самом деле, спорно, учитывая, что мы ничего не можем сделать с этим значением, кроме как вставить его в сгенерированный контент. Есть также опасения, что сгенерированный контент будет недоступен для определенных программ чтения с экрана, поэтому любое использование, выходящее за рамки декоративного, должно обеспечить другие способы доступа к этой информации. Прочтите «Поддержка специальных возможностей для содержимого, созданного с помощью CSS» и более свежую информацию «Совместимость средства чтения с экрана свойств содержимого CSS», чтобы получить дополнительные сведения о доступности и сгенерированном содержимом.
Однако он демонстрирует, что счетчики могут выполнять более полезные функции, чем просто нумерация списков. Возможно, однажды эти знания пригодятся для решения какой-то проблемы, над которой вы работаете.
Узнать больше
Эта статья оказалась довольно далекой от списков стилей, несмотря на то, что все, что я описал, находится в спецификации списков CSS. Вы можете найти больше информации о вещах, описанных по ссылкам ниже. Если вы нашли интересное применение счетчикам CSS или можете придумать, для чего можно использовать ::marker
, добавьте примечание в комментариях.
-
::marker
-
counter-set
-
counter-reset
-
counter-increment
- «Использование счетчиков CSS», веб-документы MDN
- «Подсчет с помощью счетчиков CSS и сетки CSS», CSS-Tricks