CSS: liste con contatori, pseudo-elementi e generated content

16 marzo 2015

Assegnare uno stile ai numeratori delle liste ordinate non è un’operazione immediata, in quanto lo standerd CSS non offre al momento un selettore che permetta di isolare i numeri che contrassegnano gli elementi delle liste (markers).

Eppure come abbiamo già visto in un altro articolo è possibile ridisegnare i numeratori grazie ad una funzonalità presente nella specifica di CSS 2.1: i contatori.

I contatori CSS

Si tratta di variabili i cui valori possono essere incrementati grazie a dichiarazioni CSS che permettono di tenere in memoria il numero di volte in cui il contatore stesso è utilizzato all’interno del DOM. Per gestire i contatori, la specifica fornisce le proprietà:

  • counter-reset, dichiara il nome del contatore;
  • counter-increment, incrementa il valore di una unità.

Le due proprietà possono essere assegnate a qualunque elemento del DOM, e quindi i valori dei contatori possono essere modificati arbitrariamente.

Il valore del contatore viene mandato a video grazie alle funzioni counter() e counters() della proprietà content.

I contatori e le liste ordinate

Prendiamo come esempio una semplice lista ordinata:

<ol class="number">
	<li>Lorem ipsum dolor sit amet, ... </li>
	<li>Lorem ipsum dolor sit amet, ... </li>
</ol>

Assegniamo, quindi, all’elemento ol il seguente stile:

ol.number {
	width: 32em;
	margin: 0;
	padding: 0;
	margin-left: 4em;
	list-style-type: none;
	counter-reset: simple-counter;
}

Con la proprietà list-style-type viene annullato lo stile della lista, mentre con counter-reset viene impostato il contatore simple-counter. Il valore predefinito del contatore è 0, ma counter-reset permette anche di assegnare un valore iniziale diverso:

ol.number {
	...
	list-style-type: none;
	counter-reset: simple-counter 4;
}

In questo modo, il primo elemento della lista sarà contrassegnato dal numero 5. Una volta impostato il contatore, bisogna mandare a video i valori che questo assume man mano che viene aggiornato.
Per raggiungere lo scopo, si ricorre alla proprietà content dello pseudo-elemento ::before, come nella dichiarazione che segue:

ol.number li::before {
	position: absolute;
	top: 0;
	left: -0.8em;
	font-size: 2.8em;
	line-height: 1em;
	content: counter(simple-counter);
	counter-increment: simple-counter;
}

La funzione counter() restituisce il valore del contatore, che quindi può essere mandato a video con la proprietà content.

Il codice CSS completo e l’esempio dal vivo.

Le funzioni counter() e counters()

Grazie alla proprietà content, assegnata agli pseudo-elementi ::before e ::after, è possibile generare un contenuto all’interno di un elemento del DOM. Tra i possibili valori della proprietà content, le funzioni counter() e counters() forniscono i valori correnti dei contatori.

Counter

La funzione counter() accetta uno o due argomenti:

ArgomentoDescrizione
nameil nome del contatore
stylelo stile della formattazione. Il valore predefinito è decimal, ma è possibile impostare uno qualunque dei valori della proprietà list-style-type

Così, nell’esempio precedente, la dichiarazione avrebbe potuto essere anche la seguente:

ol.number li::before {
	...
	content: counter(simple-counter, upper-roman);
	counter-increment: simple-counter;
}

Il nome del contatore non deve necessariamente essere univoco. Possono esistere, infatti, più contatori con lo stesso nome, ognuno valido nell’ambito di uno specifico elemento (scope). La funzione counters() permette di visualizzare i valori di tutti i contatori aventi lo stesso nome, dal più esterno al più interno, separandoli con una specifica stringa. Ciò consente, ad esempio, di generare una numerazione alternativa per le liste annidate. Si consideri, ad esempio, la seguente struttura:

<ol class="toc">
	<li>Core JavaScript <!-- Part 1 -->
		<ol>
			<li>Lexical Structure <!-- Chapter -->
				<ol>
					<li>Character Set</li> <!-- Paragraph -->
					<li>Comments</li>
					<li>Literals</li>
					<li>Identifiers and Reserved Words</li>
					<li>Optionals Semicolons</li>
				</ol>				
			</li>
			...
</ol>

Il markup qui sopra genera tre livelli di liste ordinate. Il primo livello individua le parti, il secondo individua i capitoli, il terzo, infine, i paragrafi di un libro. Vediamo, quindi, le dichiarazioni CSS. Come nell’esempio precedente, va impostato il contatore e annullati gli stili predefiniti delle liste:

.toc,
.toc ol {
	counter-reset: listitem;
	list-style-type: none;
}

Trattandosi di più liste annidate, abbiamo selezionato sia la lista principale, sia tutte le liste ordinate da essa discendenti (.toc ol). Subito dopo visualizziamo i valori dei contatori:

.toc li:before {
    counter-increment: listitem;
    content: counters(listitem, ".")" ";
}

Prima di ogni elemento di lista viene aggiunto lo pseudo-elemento ::before, in corrispondenza del quale viene incrementato il contatore listitem; quindi, al suo interno, viene inserito il contenuto generato dal valore della proprietà content. In questo caso, la funzione counters() fornisce i valori di tutti i contatori il cui nome è listitem, a cominciare dal contatore della lista più esterna, separati da un punto; dopo il contatore, viene inserito uno spazio.

Potrebbe essere opportuno dare maggiore enfasi alla prima lista della gerarchia, magari evidenziando gli elementi che individuano una parte principale del libro. Per far questo, bisogna sovrascrivere il blocco precedente con un selettore specifico per gli elementi di lista direttamente discendenti dalla lista principale:

.toc > li::before {
	content: "Part " counter(listitem)". ";
}

Si noterà subito che abbiamo utilizzato la funzione counter() e non la funzione counters(). Ciò in quanto al primo livello non sarà necessario separare i valori dei tre contatori. Al numero progressivo viene premessa la stringa "Part " e aggiunta la stringa ". ".

In questo esempio bisogna stare attenti alla specificità dei selettori, che è esattamente la stessa. Per questo motivo è necessario che i blocchi di dichiarazioni vengano inseriti nello stesso ordine del nostro esempio.

Manca pochissimo. Per distinguere meglio gli elementi delle liste annidate, assegniamo colori e dimensioni diverse agli elementi di lista, in base al livello gerarchico:

.toc li {
	line-height: 1.4em;
	color: #000;
	font-size: .82em;
}

.toc > li {
	color: red;
	font-size: 2em;
}

.toc > li > ol > li {
	color: blue;
}

Anche in questo caso, la specificità dei selettori è la stessa, quindi l’ordine dei blocchi di dichiarazioni è determinante per la corretta visualizzazione degli elementi.

Tre liste ordinate annidate con i rispettivi contatori

Tre liste annidate

Il codice CSS completo e l’esempio dal vivo.

Se vuoi aggiornamenti su CSS: liste con contatori, pseudo-elementi e generated content inserisci la tua e-mail nel box qui sotto:
 
X
Se vuoi aggiornamenti su CSS: liste con contatori, pseudo-elementi e generated content

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento di cui al punto 3 dell'informativa sulla privacy