I contenuti generati in dettaglio

Sommario:

  1. 1. La teoria: introduzione ai contenuti generati
  2. 2. Gli pseudo-elementi :before ed :after
  3. 3. La proprietà 'content'
  4. 4. Virgolette
  5. 4.1 Specificare le virgolette con la proprietà 'quotes'
  6. 4.2 Inserire le virgolette con la proprietà 'content'
  7. 5. Contatori automatici e numerazione
  8. 5.1 Contatori annidati ed àmbito di applicazione
  9. 5.2 Stili dei contatori

Per apprezzare al meglio i contenuti dell'articolo si consiglia l'uso di un browser che supporti i contenuti generati, come Firefox o Opera. È possibile scaricare l'articolo completo di esempi in formato ZIP.

1. La teoria: introduzione ai contenuti generati

Leggiamo nel capitolo 12 della revisione 1 delle specifiche CSS 2 ( http://www.w3.org/TR/CSS21/generate.html):

In alcuni casi gli autori possono volere che i programmi utente rendano il contenuto che non proviene dal modello ad albero del documento. Un esempio comune è un elenco numerato: l'autore (o l'autrice) non vogliono elencare i numeri esplicitamente, ma vogliono che il programma utente li generi automaticamente. Allo stesso modo, gli autori possono volere che il programma utente inserisca la parola "Figura" prima della didascalia di un'immagine, o "Capitolo 7" prima del titolo del settimo capitolo.

In particolare per l'audio o il braille, i programmi utente dovrebbero essere in grado di inserire queste stringhe.

Si legge inoltre nella sezione "Generated text, counters and quotes" del capitolo 6 di Cascading Style Sheets. Designing for the Web (di Bert Bos ed Håkon Wium Lie, edito da Addison Wesley, terza edizione):

A volte vi è l'esigenza di inserire del testo che non si trova nel sorgente originale. Esempi sono testi come "Figura 7" o "Capitolo XI", virgolette inserite automaticamente intorno alle citazioni, ma anche i pallini e i numeri degli elenchi della precedente sezione (quella sugli elenchi, N. d. T.). I pallini e i numeri degli elenchi sono i più comuni e i più semplici da specificare. La numerazione per le voci degli elenchi è implicita: non vi è esplicita menzione di un contatore nel foglio di stile.

Ma a volte le proprietà di 'list-style' non sono sufficienti (per esempio quando gli elenchi devono essere numerati come A1, A2, ecc.). Per questi casi, i CSS forniscono espliciti contatori. Gli stessi contatori espliciti sono usati anche per numerare capitoli, sezioni, figure, tabelle e così via. Testi prestabiliti, come la parola "Figura" in "Figura 7", possono essere inseriti insieme con i contatori, o anche per proprio conto. Un tipico caso è l'inserimento della parola "Nota:" davanti a tutti i paragrafi che costituiscono delle note.

Le virgolette sono un caso speciale. Sebbene sia possibile inserire le virgolette semplicemente come testi prestabiliti, in molti casi è auspicabile usare differenti virgolette, a seconda se esse sono annidate all'interno di altre virgolette oppure no. I CSS hanno una proprietà 'quotes' che tiene automaticamente traccia del livello di annidamento delle citazioni e inserisce le virgolette per quel livello.

Nei CSS i contenuti possono essere generati da due meccanismi:

Esamineremo solo il primo aspetto, rimandando il lettore alla consultazione delle sezioni sugli elenchi nel sopracitato capitolo 12 delle specifiche.

2. Gli pseudo-elementi :before ed :after

Si può specificare lo stile e la posizione dei contenuti generati mediante gli pseudo-elementi :before ed :after. Come indicato dal loro nome, tali pseudo-elementi specificano la posizione dei contenuti prima (:before) o dopo (:after) il contenuto di un elemento del documento. La proprietà 'content', unita a questi pseudo-elementi, specifica quello che va inserito.

Per esempio, le seguenti regole CSS inseriscono la stringa "Nota:" prima del contenuto di ogni elemento p con classe "nota". Il testo sarà in maiuscolo e grassetto:

p.nota:before {
  content: "Nota: ";
  font-weight: bold;
  text-transform: uppercase;
}

Il codice (X)HTML potrebbe essere:

<p>Paragrafo normale. Lorem ipsum dolor sit amet ...</p>
<p class="nota">Questo testo è di Ugo di San Vittore</p>

[ Vedi esempio ]

Dal codice CSS si evince che la stringa inserita tramite la proprietà 'content' è sensibile agli spazi. Dunque è differente scrivere "Nota:" piuttosto che "Nota: ": nel secondo caso, infatti, si creerà uno spazio bianco fra la stringa ed il testo del paragrafo, mentre nel primo caso no. È sempre possibile, inoltre, controllare la spaziatura tramite la più opportuna proprietà 'margin'. (Sulla proprietà 'margin' si vedano le specifiche.)

I riquadrati ( box ) degli elementi includono i contenuti generati. Per esempio, aggiungendo la seguente regola al precedente CSS:

p.nota {border: 2px solid green;}

si otterrà un bordo verde di 2 pixel intorno all'intero paragrafo, inclusa la stringa iniziale.

[ Vedi esempio ]

Gli pseudo-elementi :before ed :after ereditano ogni proprietà ereditabile dall'elemento a cui sono uniti.

Per esempio, le seguenti regole inseriscono delle virgolette prima e dopo ogni elemento blockquote. Il colore delle virgolette sarà rosso, ma il font sarà lo stesso del resto dell'elemento blockquote:

blockquote {font-family: Georgia, serif;}

blockquote:before {
content: open-quote;
color: red;
}
blockquote:after {
content: close-quote;
color: red;
}

Il codice (X)HTML potrebbe essere:

<blockquote>
<p>Lorem ipsum dolor sit amet...</p>
<blockquote>

[ Vedi esempio ]

Poichè il valore iniziale della proprietà 'display' (si vedano le specifiche) per l'elemento blockquote è 'block', le virgolette nel precedente esempio vengono inserite come riquadrato a blocco (block box). L'esempio successivo imposta esplicitamente la proprietà 'display' su 'block', sicchè il testo inserito diventa un blocco:

h1:before {
content: "Descrizione:";
display: block;
margin-top: 2em;
text-align: left;
}

Il codice (X)HTML potrebbe essere:

<h1>La vera vita di Ugo di San Vittore</h1>

[ Vedi esempio ]

Seguendo il filo del discorso delle specifiche, arriviamo all'interazione degli pseudo-elementi :before ed :after con i riquadrati incorporati ( box run-in ). La proprietà 'display' impostata su 'run-in' rende alcuni elementi di blocco come parte in riga (inline) di un elemento successivo. Questo valore è utile per ottenere determinati effetti di intestazione molto comuni nella tipografia tradizionale, come quello di far apparire un titolo come parte integrante di un paragrafo di testo. Come gli elementi 'inline-block', anche gli elementi 'run-in' sono degli ibridi blocco/in riga. Questo esempio ne mostra il funzionamento. La cosa da notare è che 'run-in' funzionerà solo se il riquadrato successivo è di blocco. In caso contrario, il riquadrato run-in sarà reso di blocco e non verrà incorporato nell'elemento successivo (in questo caso un paragrafo). Tuttavia, poichè il valore 'run-in' è attualmente supportato solo da Opera, appare quanto mai di scarsa utilità soffermarsi ancora sull'argomento. L'effetto tipografico descritto può essere ottenuto con altre proprietà CSS, come ad esempio 'float'.

Un'aspetto interessante è anche l'interazione degli pseudo-elementi :before ed :after con gli elementi rimpiazzati, come le immagini. Per ulteriori informazioni si consulti l'articolo Contenuto generato ed immagini.

3. La proprietà 'content'

'content'

Valore: normal | none | [<string> | <uri> | <counter> | attr(<identifier>) | open-quote | close-quote | no-open-quote | no-close-quote] + | inherit
Iniziale: normal
Si applica a: pseudo-elementi :before ed :after
Ereditata: no
Percentuali: N/A
Media: tutti
Valore calcolato: Sugli elementi si calcola sempre in 'normal'. Su :before ed :after, se 'normal' è specificato, si calcola in 'none'. Altrimenti, per valori URI, l'URI assoluto; per i valori attr(), la stringa risultante; per altre parole chiave, come specificato.

Questa proprietà è usata con gli pseudo-elementi :before ed :after per generare contenuti in un documento. I valori hanno i seguenti significati:

none
Lo pseudo-elemento non è generato.
normal
Si calcola in 'none' per gli pseudo-elementi :before ed :after.
<string>
Contenuto testuale (stringa).
<uri>
Il valore è un URI che indica una risorsa esterna (come un'immagine). Secondo le specifiche, se il programma utente non può visualizzare la risorsa, dovrebbe considerarla come se non fosse specificata, o visualizzare un'indicazione che spieghi che la risorsa non può essere visualizzata.
<counter>
I contatori possono essere specificati con due diverse funzioni: 'counter()' o 'counters()'. La prima ha due forme: 'counter(nome)' o 'counter(nome, stile)'. Il testo che viene generato hai il valore del contatore più interno del nome dato nell'àmbito di applicazione dello pseudo-elemento. Viene formattato nello stile indicato, che per impostazione predefinita è 'decimal' (ossia numerazione decimale: 1, 2, ecc.). Anche la seconda funzione ha due forme: 'counters(nome, stringa)' o 'counters(nome, stringa, stile)'. Il testo generato ha il valore di tutti i contatori con il nome dato nell'àmbito di applicazione dello pseudo-elemento, dal più esterno al più interno, separato dalla stringa specificata. I contatori sono resi nello stile indicato, che per impostazione predefinita è 'decimal'.
open-quote e close-quote
Questi valori vengono rimpiazzati dalla stringa appropriata della proprietà 'quotes', ossia dalle opportune virgolette.
no-open-quote e no-close-quote
Non introduce contenuto (virgolette), ma incrementa (decrementa) il livello di annidamento per le virgolette.
attr(x)
Questa funzione restituisce come stringa il valore dell'attributo x dell'elemento cui sono legati gli pseudo-elementi :before ed :after. La stringa non è interpretata dal processore CSS. Se l'elemento selezionato non ha un attributo x, viene restituita una stringa vuota. La sensibilità alle maiuscole e alle minuscole dipende dal linguaggio in cui è scritto il codice sorgente del documento (HTML, XHTML, ecc.). Si può far riferimento solo all'attributo dell'elemento a cui sono legati gli pseudo-elementi :before ed :after.

La proprietà 'display' controlla se i contenuti sono posizionati in un riquadrato a blocco o in riga.

La seguente regola CSS fa si che la stringa "Capitolo:" sia generata prima di ogni elemento h1:

h1:before {
content: "Capitolo:";
display: inline;
}

Si noti come la dichiarazione 'display: inline' faccia in modo che la stringa si trovi sulla stessa riga dell'elemento h1.

Si possono inoltre includere nuove righe nei contenuti generati inserendo il carattere di escape "\A" in una delle stringhe dopo la proprietà 'content'. Questa interruzione di riga è ancora soggetta alla proprietà 'white-space'. Esempio:

h1:before {
display: block;
text-align: left;
white-space: pre;
content: "Considerazioni\A finali: ";
}

Il codice (X)HTML potrebbe essere:

<h1>L'opera di Ugo di San Vittore</h1>

[ Vedi esempio ]

I contenuti generati non alterano il modello ad albero del documento e la gerarchia tra gli elementi. Nello specifico, i contenuti generati non vengono restituiti al processore del linguaggio del documento (per essere resi una seconda volta).

4. Virgolette

Grazie ai CSS gli autori possono specificare come i programmi utente debbano rendere le virgolette. La proprietà 'quotes' specifica le coppie di virgolette per ogni livello di citazioni annidate. La proprietà 'content' da accesso alle virgolette e fa si che esse vengano inserite prima e dopo una citazione.

4.1 Specificare le virgolette con la proprietà 'quotes'

'quotes'

Valore: [<string> <string>] + | none | inherit
Iniziale: dipende dal programma utente
Si applica a: tutti gli elementi
Ereditata: si
Percentuali: N/A
Media: visuale
Valore calcolato: come specificato

Questa proprietà specifica le virgolette per ogni numero di citazioni annidate. I valori hanno i seguenti significati:

none
I valori 'open-quote' e 'close-quote' della proprietà 'content' non producono virgolette.
[<string> <string>]
I valori di 'open-quote' e 'close-quote' della proprietà 'content' sono presi da questo elenco di coppie di virgolette (di apertura e di chiusura). La prima coppia (quella a sinistra) rappresenta il livello più esterno di citazione, mentre la seconda il primo livello di annidamento e così via.

Per esempio, applicando il seguente foglio di stile:

q {
quotes: '"' '"';
}

q:before {
content: open-quote;
}
q:after {
content: close-quote;
}

al seguente codice (X)HTML:

<p><q>Citami!</q></p>

si otterrà:

"Citami!"

Si noti che con la prima dichiarazione CSS abbiamo specificato la coppia di virgolette, mentre con la seconda e la terza abbiamo inserito le virgolette prima e dopo il contenuto dell'elemento q.

Le virgolette specificate da 'quotes' nel precedente esempio si trovano di norma sulla tastiera di un computer. Se invece volessimo specificare altri caratteri, dovremmo ricorrere a differenti codici ISO 10646, come quelli della seguente tabella:

Carattere Resa Codice Descrizione
" " 0022 virgolette
' ' 0027 apostrofo
< < 2039 angolare sinistra
> > 203A angolare destra
« « 00AB caporali sinistre
» » 00BB caporali destre
2018 virgoletta singola sinistra
2019 virgoletta singola destra
201C virgolette tipografiche sinistre
201D virgolette tipografiche destre
201E virgolette basse

L'esempio precedente potrebbe essere riscritto come:

q {
quotes: '\00AB' '\00BB';
}

q:before {
content: open-quote;
}
q:after {
content: close-quote;
}

[ Vedi esempio ]

Si noti come siano state specificate delle virgolette che di norma non si trovano sulla tastiera di un computer ('«' e '»') mediante opportuni codici ISO 10646, preceduti da un backslash ('\').

4.2 Inserire le virgolette con la proprietà 'content'

Le virgolette sono inserite nel documento mediante i valori 'open-quote' e 'close-quote' della proprietà 'content'. Ciascuna ricorrenza di 'open-quote' o 'close-quote' è rimpiazzata da una delle stringhe di 'quotes', basandosi sulla profondità dell'annidamento.

Il valore 'open-quote' si riferisce alla prima coppia di virgolette, 'close-quote' alla seconda. Quale coppia venga usata dipende dal livello di annidamento delle virgolette, ossia il numero di volte che ricorre 'open-quote' in tutto il testo generato prima della ricorrenza corrente, meno il numero delle volte che ricorre 'close-quote'. Se la profondità di annidamento è 0, viene usata la prima coppia, se è 1 la seconda e così via. Se la profondità è maggiore del numero di coppie, viene ripetuta l'ultima coppia. Un 'close-quote' che renderebbe la profondità negativa è un errore e viene ignorato: la profondità Ŕ a 0 e non viene resa alcuna virgolettatura.

Si noti che la profondità è indipendente dall'annidamento del documento sorgente o dalla struttura di formattazione.

Inoltre le parole chiave 'no-open-quote' e 'no-close-quote', aumentano e decrementano rispettivamente di uno il livello di virgolettatura, senza tuttavia inserire contenuto.

5. Contatori automatici e numerazione

La numerazione automatica nei CSS è controllata da due proprietà, 'counter-reset' e 'counter-increment'. I contatori definiti da queste proprietà sono usati con le funzioni counter() e counters() della proprietà 'content'.

'counter-reset'

Valore: [<identifier> <integer>?] + | none | inherit
Iniziale: none
Si applica a: tutti gli elementi
Ereditata: no
Percentuali: N/A
Media: tutti
Valore calcolato: come specificato

'counter-increment'

Valore: [<identifier> <integer>?] + | none | inherit
Iniziale: none
Si applica a: tutti gli elementi
Ereditata: no
Percentuali: N/A
Media: tutti
Valore calcolato: come specificato

La proprietà 'counter-increment' accetta uno o più nomi di contatori (identificatori), ciascuno seguito facoltativamente da un numero intero. L'intero indica di quanto il contatore viene incrementato ogni volte che ricorre l'elemento a cui sono legati gli pseudo-elementi :before ed :after. L'incremento predefinito è 1. Sono ammessi anche interi pari a 0 e negativi.

La proprietà 'counter-reset' contiene anch'essa un elenco di uno o più nomi di contatori, ciascuno seguito facoltativamente da un intero. L'intero da il valore su cui il contatore è impostato ogni volta che ricorre l'elemento a cui sono legati gli pseudo-elementi :before ed :after. Il valore predefinito è 0.

L'esempio seguente mostra un modo di numerare capitoli e sezioni con "Capitolo 1", "1.1", "1.2", ecc.

body {
counter-reset: capitolo;
}

h1:before {
content: "Capitolo " counter(capitolo) ". ";
counter-increment: capitolo;
}
h1 {
counter-reset: sezione;
}

h2:before {
content: counter(capitolo) "." counter(sezione) " ";
counter-increment: sezione;
}

I nomi degli identificatori (capitolo e sezione) sono puramente indicativi: l'unico limite nella loro scelta è dato dalla fantasia (e dal buon senso) dell'autore. Si ricordi comunque che una volta scelto il nome per un identificatore, questo non può essere cambiato, pena la mancata applicazione della numerazione.

La prima dichiarazione CSS crea un àmbito di applicazione per "capitolo" e la seconda incrementa di 1 "capitolo", inserendo il numero prima dell'elemento h1, insieme con la stringa "Capitolo", tramite la proprietà 'content'. La terza dichiarazione crea un àmbito di applicazione per "sezione" e la imposta a zero (come la prima dichiarazione aveva fatto per "capitolo"), mentre la quarta e ultima dichiarazione incrementa "sezione" di 1, richiamandola insieme a "capitolo" nell'ordine esatto in cui compaiono nella proprietà 'content' applicata allo pseudo-elemento :before di h2. Quest'ultima dichiarazione renderà possibile la realizzazione della progressione "1.1", "1.2", ecc.

Il codice (X)HTML potrebbe essere:

<h1>Storia della filosofia medievale</h1>
<h2>Origini</h2>
<h2>Ambiti</h2>
<h1>Ugo di San Vittore</h1>
<h2>Biografia</h2>
<h2>Opere</h2>

[ Vedi esempio ]

Se un elemento incrementa/azzera un contatore e al contempo lo usa (nella proprietà 'content' dei suoi pseudo-elementi :before o :after), il contatore viene usato dopo essere stato incrementato/azzerato.

Se un elemento azzera ed incrementa al contempo un contatore, il contatore è prima azzerato e poi incrementato.

Se il medesimo contatore è specificato più di una volta nel valore delle proprietà 'counter-reset' e 'counter-increment', ogni azzeramento/incremento del contatore viene processato nell'ordine specificato.

A queste norme generali si aggiunga un'osservazione sul comportamento dei browser Firefox ed Opera. Riprendendo il precedente esempio alle prime due dichiarazioni:

	
body {
counter-reset: capitolo;
}

h1:before {
content: "Capitolo " counter(capitolo) ". ";
counter-increment: capitolo;
}

noteremo un comportamento uniforme da parte dei due browser, ossia entrambi incrementeranno di 1 "capitolo" ogni volta che ricorre l'elemento h1. Se invece avessimo avuto soltanto:

h1:before {
content: "Capitolo " counter(capitolo) ". ";
counter-reset: capitolo;
counter-increment: capitolo;
}

allora solo Opera avrebbe incrementato di 1 "capitolo" ad ogni ricorrenza di h1, mentre Firefox avrebbe semplicemente ripetuto la stringa "Capitolo 1". Per questo motivo è bene evitare di azzerare/incrementare un contatore sullo stesso elemento.

5.1 Contatori annidati ed àmbito di applicazione

I contatori, secondo le specifiche, sono "autoannidanti", nel senso che azzerare un contatore in un elemento discendente o pseudo-elemento, crea automaticamente una nuova istanza del contatore. Questo è importante in situazioni come gli elenchi in (X)HTML, dove gli elenchi possono essere annidati dentro se stessi con profondità arbitraria. Negli elenchi (come ol) sarebbe infatti impossibile definire univocamente i contatori nominati per ogni livello.

L'esempio CSS che segue è sufficiente a numerare voci di elenco annidate. Il risultato è molto simile all'impostazione 'display: list-item' e 'list-style: inside' sull'elemento li:

ol {
counter-reset: voce;
}

li {display: block;}
li:before {
content: counter(voce) ". ";
counter-increment: voce;
}

L'àmbito di applicazione di un contatore inizia nel primo elemento del documento che ha un 'counter-reset' per questo contatore, ed include i discendenti dell'elemento e i suoi fratelli successivi con i loro discedenti. Nell'esempio CSS di sopra, un ol creerà un contatore, e tutti i suoi figli faranno riferimento a quel contatore.

Se denominiamo con voce[n] la n-istanza del contatore "voce" e con "(" e ")" l'inizio e la fine di un àmbito di applicazione, allora il seguente esempio, basato sul foglio di stile precedente, userà i contatori indicati:

[ Vedi esempio ]

Si possono specificare più nomi di identificatori per 'counter-reset' e 'counter-increment', come nel seguente esempio:

ol {
counter-reset: voce subvoce;
}

li {display: block;}
li:before {
content: counter(voce) ". " counter(subvoce) " ";
counter-increment: voce subvoce;
}

[ Vedi esempio ]

Se vogliamo generare un ulteriore àmbito di applicazione occorre usare la funzione 'counters()', che genera una stringa composta da tutti i contatori con lo stesso nome di quello nell'àmbito di applicazione, separati da una data stringa.

Il seguente CSS numera le voci di elenco annidate come "1", "1.1", "1.1.1", ecc.

ol {counter-reset: voce;}

li {display: block;}
li:before {
content: counters(voce, ".") " ";
counter-increment: voce;
}

[ Vedi esempio ]

Si noti come in tutti gli esempi sia stato dichiarato 'display: block' per l'elemento li, in modo da annullare l'impostazione predefinita 'display: list-item' che avrebbe generato un proprio contatore.

5.2 Stili dei contatori

Per impostazione predefinita i contatori sono formattati con numeri decimali (1, 2, 3, ecc.), ma tutti gli stili disponibili per la proprietà 'list-style-type' lo sono anche per i contatori. La notazione è:

counter(nome)

per lo stile predefinito, oppure:

counter(nome, 'list-style-type')

Esempio:

h1:before {
content: counter(chno, upper-latin)".";
}

h2:before {
content: counter(sezione, upper-roman)"-";
}

[ Vedi esempio ]

Gabriele Romanato