Listas, marcadores e contadores CSS

Publicados: 2022-03-10
Resumo rápido ↬ Há mais em listas de estilo em CSS do que você imagina. Neste artigo, Rachel começa examinando listas em CSS e avançando para alguns recursos interessantes definidos na especificação CSS Lists — marcadores e contadores.

Listas em CSS têm propriedades particulares que nos dão o estilo de lista padrão que esperamos. Uma lista não ordenada ganha um marcador de lista, do tipo disc , e as listas ordenadas são numeradas. Meu interesse em explorar listas com mais detalhes veio de alguns trabalhos que fiz para documentar o pseudo-elemento ::marker para MDN. Este pseudo-elemento vem no Firefox 68 e está sendo lançado hoje . Com o pseudo elemento ::marker disponível para nós, podemos começar a fazer algumas coisas interessantes com listas e, neste artigo, explicarei mais.

Desconstruindo uma lista

Você pode não ter pensado muito sobre listas, embora as usemos frequentemente em nossa marcação. Muitas coisas podem ser marcadas logicamente como uma lista. Enquanto instruções passo a passo ou elementos classificados podem naturalmente ser descritos por uma lista ordenada <ol> , muitas coisas em um projeto podem ser descritas usando uma lista não ordenada <ul> . Um uso muito comum do elemento, por exemplo, é para marcar a navegação, pois é uma lista de destinos no site. Para nossa exploração, vamos começar descobrindo exatamente o que é uma lista em CSS.

Tal como acontece com muitas coisas em CSS, as listas têm alguns valores iniciais aplicados a elas. Esses valores fazem com que pareçam uma lista. Esses valores especiais começam com a informação de que um item de lista tem a propriedade display com um valor de list-item . Isso cria uma caixa de nível de bloco, com uma caixa de marcador adicional. A caixa do marcador é onde o marcador ou número da lista é adicionado.

Mais depois do salto! Continue lendo abaixo ↓

As listas foram definidas no início em CSS, e grande parte da definição de listas como as usamos hoje é de CSS2. A especificação CSS2 descreve um item de lista da seguinte forma:

“Um elemento com display: list-item gera uma caixa de bloco principal para o conteúdo do elemento e, dependendo dos valores de list-style-type e list-style-image , possivelmente também uma caixa de marcador como uma indicação visual de que o elemento é um item de lista.”

A caixa de bloco principal é a caixa principal do elemento e contém todos os filhos, pois um item de lista pode conter outra marcação. A caixa marcadora é então colocada em relação a esta caixa principal. A especificação continua detalhando o fato de que qualquer cor de fundo estará apenas atrás dessa caixa principal, e não do marcador. Além disso, o marcador pode ser definido para um intervalo de valores predefinidos:

  • 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

A especificação de exibição de Nível 3 define display: list-item juntamente com os outros valores possíveis para a propriedade display . Ele se refere ao CSS 2.1 — assim como muitas propriedades e valores CSS que vêm do CSS2 — mas descreve a palavra-chave list-item como “fazendo com que o elemento gere um pseudoelemento ::marker ”.

A especificação de Nível 3 também apresenta a capacidade de criar um item de lista inline com a sintaxe de dois valores sendo usada display: inline list-item . Isso ainda não foi implementado pelos navegadores.

Criando caixas de marcador em itens não listados

Tal como acontece com outros valores de display , é perfeitamente válido dar a qualquer elemento HTML um tipo de display de list-item (se você desejar gerar um pseudo-elemento ::marker no item). Isso não fará com que o elemento se torne um item de lista semanticamente, mas, em vez disso, ele será exibido apenas visualmente como um item de lista e, portanto, poderá ter um ::marker . Quando discutirmos o pseudo-elemento ::marker abaixo, você descobrirá alguns casos em que fornecer outros elementos display: list-item pode ser útil.

A especificação de nível 3 das listas CSS: ::marker e contadores

A especificação display expande e esclarece a definição de listas que encontramos no CSS2, porém, há também uma especificação que define o comportamento da lista em detalhes: o CSS Lists Specification Level 3. Como o comportamento básico dos itens da lista é definido em display , este especificação detalha a caixa de marcador gerada quando algo tem display: list-item junto com os contadores que são usados ​​por padrão sempre que você cria uma lista ordenada. Há algumas funcionalidades potencialmente úteis acessadas por meio desses recursos.

O Pseudo-Elemento ::marker

O pseudoelemento ::marker permite que você direcione o marcador de lista — separadamente do conteúdo do item de lista. Isso não era possível nas versões anteriores do CSS, portanto, se você alterasse a cor ou o tamanho da fonte do ul ou li , isso também alteraria a cor e o tamanho da fonte dos marcadores. Para fazer algo aparentemente tão simples quanto ter marcadores de lista de cores diferentes do texto, envolveria envolver o conteúdo do item da lista em um intervalo (ou usar uma imagem para o marcador).

 ul { color: #00b7a8; } ul span { color #333; }

Com o pseudo elemento ::marker , a coisa mais simples que você pode tentar é ter um marcador diferente para a cor do texto, o que significa que, em vez do código no exemplo acima, você pode usar:

 ul { color: #333; } ul ::marker { color: #00b7a8; }

Você também pode usar um tamanho e font-family diferentes para a numeração em uma lista ordenada.

 ol ::marker { font-size: 200%; color: #00b7a8; font-family: "Comic Sans MS", cursive, sans-serif; }

Você pode ver tudo isso em um navegador compatível usando meu exemplo do CodePen:

Veja a Caneta [Marcas coloridas com e sem marcador](https://codepen.io/rachelandrew/penVJQyoR) de Rachel Andrew.

Veja as balas Pen Colored com e sem marcador de Rachel Andrew.

Você pode usar o pseudo-elemento ::marker em itens não listados. No código abaixo, defini um título para display: list-item . Isso dá a ele um marcador e, portanto, uma caixa ::marker para direcionar.

Eu mudei o marcador para usar um emoji:

 h1 { display: list-item; } h1::marker { content: ""; } 
Dirigindo com um emoji de gato à esquerda dele
No Firefox, você pode ver o emoji usado como marcador.

Veja a Caneta [Cabeçalho e marcador](https://codepen.io/rachelandrew/pen/wLyyMG) de Rachel Andrew.

Veja o cabeçalho da caneta e o marcador de Rachel Andrew.

No exemplo acima, usei o conteúdo gerado nas regras para o marcador. Apenas um pequeno subconjunto de propriedades CSS está disponível para uso em ::marker . Elas incluem propriedades de fonte e cor, porém, também incluem a propriedade de content , para incluir o conteúdo gerado.

A adição de content como propriedade permitida para ::marker é recente, porém está incluída na implementação do Firefox. A inclusão significa que você pode fazer coisas como incluir uma string de texto em um ::marker . Também aumenta as possibilidades de formatação de marcadores quando você combina o uso de contadores com ::marker .

Suporte e fallbacks do navegador

Para navegadores que não suportam o pseudoelemento ::marker , o fallback é o marcador regular que teria sido exibido de qualquer maneira. Infelizmente, no momento, não podemos usar Consultas de recursos para detectar suporte para seletores como esse pseudoelemento no momento, embora tenha havido um problema levantado sobre a adição disso à especificação. Isso significa que você não pode bifurcar seu código para fazer uma coisa quando tiver suporte e outra coisa se não tiver. Na maioria dos casos, voltar ao marcador regular será uma solução razoável.

Contadores

Listas ordenadas têm numeração de listas — algo que é alcançado por meio de um contador CSS. A especificação CSS Lists, portanto, também descreve esses contadores. Podemos acessar e criar contadores nós mesmos que, combinados com o pseudo-elemento ::marker , podem nos dar algumas funcionalidades úteis. Esses contadores também podem ser usados ​​em conteúdo gerado regular (não ::marker ).

Se eu tiver uma lista numerada de etapas (e gostaria de escrever “Etapa 1”, “Etapa 2” e assim por diante), posso fazer isso usando o conteúdo gerado no meu marcador e anexando o contador list-item , isso representa o contador embutido:

 ::marker { content: "Step " counter(list-item) ": "; } 
Uma lista ordenada com Etapa 1, Etapa 2 e assim por diante, antes de cada item da lista
No Firefox, você verá o contador prefixado com a palavra “Step”.

Veja a Caneta [Contadores e marcador](https://codepen.io/rachelandrew/pen/BgRaoz) de Rachel Andrew.

Veja os contadores de canetas e marcadores de Rachel Andrew.

Contadores aninhados

Se você tiver listas aninhadas, uma maneira comum de numerá-las é fazer com que o item de nível superior seja um número inteiro, (1), depois os itens filhos como (1.1, 1.2) e seus filhos (1.1.1, 1.1.2), e assim por diante. Você pode conseguir isso usando mais funcionalidades de contadores.

Ao aninhar listas HTML, você terá vários contadores com o mesmo nome — aninhados um dentro do outro. O ninho de contadores pode ser acessado usando a função counters() .

No código abaixo, estou usando counters() para formatar meus marcadores de lista conforme descrito acima. O primeiro argumento para counters() é o nome do contador a ser usado. Estou usando o contador list-item . O segundo argumento é uma string — é isso que será concatenado entre os contadores de saída (estou usando um . ). Por fim, adiciono um : fora da função counter, mas dentro do valor do content para que a saída do meu contador seja separada do conteúdo por dois pontos.

 ::marker { content: counters(list-item,'.') ':'; color: #00b7a8; font-weight: bold; }

Isso me dá a saída como na imagem. Se você estiver usando um navegador que suporte ::marker e counters, poderá vê-lo funcionando no exemplo do CodePen - tente alterar a string de um arquivo . para outra coisa para ver como isso altera a saída.

Um conjunto de listas aninhadas
No Firefox, você verá a numeração da lista aninhada separada por pontos.

Veja a caneta [contadores aninhados](https://codepen.io/rachelandrew/pen/VJbwxL) de Rachel Andrew.

Veja os contadores Pen Nested de Rachel Andrew.

Qual é a diferença entre counter() e counters() ?

A função counter() que usamos no primeiro exemplo para escrever nossos passos usa apenas o contador mais interno. Portanto, na situação em que você tem um conjunto de listas aninhadas, você escreverá o contador relacionado ao nível em que está atualmente.

A função counters() essencialmente escreve todo o branch e lhe dá a oportunidade de concatenar uma string entre os contadores no branch. Portanto, se você tiver um item de lista com um contador de 2 (que faz parte de uma lista aninhada dentro de um item de lista com um contador de 4 ), a ramificação conterá:

  • 4
  • 2

Você pode produzir isso como 4.2 no marcador usando:

 ::marker { content: counters(list-item,'.'); }

Contadores em outros elementos

Os contadores podem ser usados ​​em coisas que não são listas — seja para gerar um marcador — nesse caso o elemento precisará ter display: list-item — ou para gerar conteúdo gerado regularmente. Contadores são usados ​​extensivamente na produção de livros, a fim de permitir a numeração de capítulos e figuras entre outras coisas. Não há razão para não adotar uma abordagem semelhante na web, em particular para artigos mais longos.

As propriedades CSS definidas na especificação CSS Lists que lidam com esses contadores são:

  • counter-set
  • counter-reset
  • counter-increment

Para ver como eles funcionam fora das listas, podemos ver um exemplo de uso de contadores para numerar os títulos em um documento.

A primeira coisa que preciso fazer é criar um contador para cabeçalhos no elemento body — pronto para uso. Estou usando a propriedade counter-reset para fazer isso. As propriedades counter-reset e counter-set são muito semelhantes. A propriedade counter-reset criará um novo contador se ainda não existir um contador com o nome especificado, mas também criará contadores aninhados conforme descrito acima se existir um contador com esse nome. A propriedade counter-set só criará um novo contador se não houver nenhum contador com esse nome. Para isso, usar qualquer uma das propriedades funcionaria bem, no entanto, counter-set não tem um suporte tão bom ao navegador quanto counter-reset , então estou seguindo o caminho prático:

 body { counter-reset: heading-counter; }

Agora que tenho um contador, posso usar a propriedade counter-increment no seletor para os cabeçalhos; isso deve incrementar o contador toda vez que o seletor corresponder.

 h2 { counter-increment: heading-counter; }

Para ver o valor, preciso enviá-lo para o documento. Eu posso fazer isso usando o conteúdo gerado e adicionando-o before do título, conforme mostrado no seguinte exemplo do CodePen:

 h2::before { content: counter(heading-counter) ": "; color: #00b7a8; font-weight: bold; } 

Veja a caneta [Headings and counters](https://codepen.io/rachelandrew/pen/gNGjxq) de Rachel Andrew.

Veja os Pen Headings e contadores de Rachel Andrew.

Como alternativa, eu poderia transformar o elemento h2 em um list-item e usar ::marker , conforme demonstrado abaixo. Conforme já detalhado, o uso do elemento ::marker tem suporte limitado ao navegador. No Firefox, você deve ver o contador usado como marcador para o título, enquanto outros navegadores mostrarão o marcador padrão.

 h2 { display: list-item; } h2::marker { content: counter(heading-counter) ": "; color: #00b7a8; font-weight: bold; } 

Veja a caneta [títulos, marcadores e contadores](https://codepen.io/rachelandrew/pen/pXWZay) de Rachel Andrew.

Veja os Pen Headings, marcadores e contadores de Rachel Andrew.

Contadores em elementos de formulário

Há também um pouco de interatividade que você pode obter usando CSS Counters – algo que você pode achar que precisa de JavaScript para fazer.

Tenho um formulário que tem vários campos obrigatórios. O status obrigatório pode ser selecionado em CSS com uma pseudoclasse :required , e o fato de um campo não ter sido preenchido pode ser detectado por meio da :invalid . Isso significa que podemos verificar os campos obrigatórios e inválidos e incrementar um contador. Em seguida, produza isso como conteúdo gerado.

Veja a caneta [Contando campos de formulário obrigatórios](https://codepen.io/rachelandrew/pen/vqpJdM) de Rachel Andrew.

Consulte os campos obrigatórios do formulário Contagem de canetas de Rachel Andrew.

Quão útil isso é na realidade é discutível - dado que não podemos fazer nada com esse valor além de colocá-lo no conteúdo gerado. Há também preocupações em relação ao conteúdo gerado ser inacessível a determinados leitores de tela, portanto, qualquer uso que seja mais do que decorativo precisaria garantir outras formas de acesso a essa informação. Leia “Suporte de acessibilidade para conteúdo gerado por CSS” e as informações mais recentes, “Compatibilidade do leitor de tela de propriedade de conteúdo CSS” para obter mais detalhes sobre acessibilidade e conteúdo gerado.

No entanto, demonstra que os contadores podem alcançar coisas mais úteis do que simplesmente numerar listas. Pode ser que um dia esse conhecimento venha a ser útil para resolver algum problema em que você está trabalhando.

Descubra mais

Este artigo acabou muito longe das listas de estilo, apesar do fato de que tudo o que descrevi é encontrado na especificação CSS Lists. Você pode encontrar mais informações sobre as coisas descritas nos links abaixo. Se você encontrou um uso interessante para CSS Counters, ou pode pensar em coisas que você poderia usar ::marker para, adicione uma nota nos comentários.

  • ::marker
  • counter-set
  • counter-reset
  • counter-increment
  • “Usando contadores CSS”, documentos da web MDN
  • “Contando com contadores CSS e grade CSS”, CSS-Tricks