Un sommario perfetto con HTML + CSS PlatoBlockchain Data Intelligence. Ricerca verticale. Ai.

Un sommario perfetto con HTML + CSS

All'inizio di quest'anno, ho autopubblicato un ebook chiamato Comprendere le promesse JavaScript (gratuito per il download). Anche se non avevo alcuna intenzione di trasformarlo in un libro cartaceo, abbastanza persone mi hanno contattato chiedendo informazioni su una versione cartacea che ho deciso di autopubblicare anche quella. Ho pensato che sarebbe stato un esercizio facile usare HTML e CSS per generare un PDF e quindi inviarlo alla stampante. Quello che non mi rendevo conto era che non avevo una risposta per una parte importante di un libro cartaceo: il sommario.

La composizione di un sommario

Al suo interno, un sommario è abbastanza semplice. Ogni riga rappresenta una parte di un libro o di una pagina web e indica dove puoi trovare quel contenuto. Tipicamente, le righe contengono tre parti:

  1. Il titolo del capitolo o della sezione
  2. Leader (cioè quei punti, trattini o linee) che collegano visivamente il titolo al numero di pagina
  3. Il numero di pagina

È facile generare un sommario all'interno di strumenti di elaborazione testi come Microsoft Word o Google Docs, ma poiché il mio contenuto era in Markdown e poi trasformato in HTML, non era una buona opzione per me. Volevo qualcosa di automatizzato che funzionasse con HTML per generare il sommario in un formato adatto alla stampa. Volevo anche che ogni riga fosse un collegamento in modo che potesse essere utilizzata nelle pagine Web e nei PDF per navigare nel documento. Volevo anche dei punti di riferimento tra il titolo e il numero di pagina.

E così ho iniziato a fare ricerche.

Mi sono imbattuto in due eccellenti post sul blog sulla creazione di un sommario con HTML e CSS. Il primo è stato "Costruisci un sommario dal tuo HTML" di Julie Blanc. Julie ha lavorato PagedJS, un polyfill per le funzioni dei media impaginati mancanti nei browser Web che formatta correttamente i documenti per la stampa. Ho iniziato con l'esempio di Julie, ma ho scoperto che non funzionava per me. Poi ho trovato Christoph Grabo's "Linee guida TOC reattive con CSS" post, che ha introdotto il concetto di utilizzare CSS Grid (al contrario dell'approccio basato su float di Julie) per facilitare l'allineamento. Ancora una volta, però, il suo approccio non era del tutto adatto ai miei scopi.

Dopo aver letto questi due post, però, ho sentito di avere una comprensione sufficientemente buona dei problemi di layout per intraprendere da solo. Ho usato pezzi di entrambi i post del blog e ho aggiunto alcuni nuovi concetti HTML e CSS nell'approccio per ottenere un risultato di cui sono soddisfatto.

Scelta del markup corretto

Quando ho deciso il markup corretto per un sommario, ho pensato principalmente alla semantica corretta. Fondamentalmente, un sommario riguarda un titolo (capitolo o sottosezione) legato a un numero di pagina, quasi come una coppia chiave-valore. Questo mi ha portato a due opzioni:

  • Un'opzione è usare una tabella (<table>) con una colonna per il titolo e una colonna per la pagina.
  • Poi c'è l'elenco delle definizioni spesso inutilizzato e dimenticato (<dl>) elemento. Funge anche da mappa valore-chiave. Quindi, ancora una volta, la relazione tra il titolo e il numero di pagina sarebbe ovvia.

Ognuna di queste sembrava una buona opzione fino a quando non mi sono reso conto che funzionano davvero solo per sommari a livello singolo, vale a dire, solo se volevo avere un sommario con solo i nomi dei capitoli. Se volevo mostrare le sottosezioni nel sommario, però, non avevo buone opzioni. Gli elementi della tabella non sono ottimi per i dati gerarchicie mentre gli elenchi di definizioni possono essere tecnicamente nidificati, la semantica non sembrava corretta. Quindi, sono tornato al tavolo da disegno.

Ho deciso di basarmi sull'approccio di Julie e di utilizzare un elenco; tuttavia, ho optato per una lista ordinata (<ol>) invece di un elenco non ordinato (<ul>). Penso che un elenco ordinato sia più appropriato in questo caso. Un sommario rappresenta un elenco di capitoli e sottotitoli nell'ordine in cui appaiono nel contenuto. L'ordine è importante e non dovrebbe perdersi nel markup.

Sfortunatamente, l'utilizzo di un elenco ordinato significa perdere la relazione semantica tra il titolo e il numero di pagina, quindi il mio passaggio successivo è stato ristabilire quella relazione all'interno di ogni elemento dell'elenco. Il modo più semplice per risolvere questo problema è semplicemente inserire la parola "pagina" prima del numero di pagina. In questo modo risulta chiara la relazione del numero rispetto al testo, anche senza altra distinzione visiva.

Ecco un semplice scheletro HTML che ha costituito la base del mio markup:

<ol class="toc-list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page">Page 1</span> </a> <ol> <!-- subsection items --> </ol> </li>
</ol>

Applicazione di stili al sommario

Una volta stabilito il markup che intendevo utilizzare, il passaggio successivo è stato quello di applicare alcuni stili.

Innanzitutto, ho rimosso i numeri generati automaticamente. Puoi scegliere di mantenere i numeri generati automaticamente nel tuo progetto, se lo desideri, ma è comune che i libri abbiano prefazioni e postfazioni non numerate incluse nell'elenco dei capitoli, il che rende i numeri generati automaticamente errati.

Per il mio scopo, compilerei manualmente i numeri dei capitoli, quindi regolerei il layout in modo che l'elenco di livello superiore non abbia alcun riempimento (allineandolo così con i paragrafi) e ogni elenco incorporato sia rientrato di due spazi. Ho scelto di usare a 2ch valore di riempimento perché non ero ancora del tutto sicuro di quale carattere avrei usato. Il ch l'unità di lunghezza consente al riempimento di essere relativo alla larghezza di un carattere, indipendentemente dal tipo di carattere utilizzato, piuttosto che a una dimensione assoluta dei pixel che potrebbe risultare incoerente.

Ecco il CSS con cui sono finito:

.toc-list, .toc-list ol { list-style-type: none;
} .toc-list { padding: 0;
} .toc-list ol { padding-inline-start: 2ch;
}

Sara Sueidan mi ha fatto notare che i browser WebKit rimuovono la semantica dell'elenco quando list-style-type is none, quindi ho dovuto aggiungere role="list" nell'HTML per preservarlo:

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page">Page 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>
CodePen incorpora il fallback

Styling del titolo e del numero di pagina

Con lo stile dell'elenco a mio piacimento, era ora di passare allo stile di un singolo elemento dell'elenco. Per ogni elemento del sommario, il titolo e il numero di pagina devono essere sulla stessa riga, con il titolo a sinistra e il numero di pagina allineato a destra.

Potresti pensare: "Nessun problema, ecco a cosa serve flexbox!" Non hai torto! Flexbox può infatti ottenere il corretto allineamento del frontespizio. Ma ci sono alcuni problemi di allineamento difficili quando vengono aggiunti i leader, quindi ho invece optato per l'approccio di Christoph utilizzando una griglia, che come bonus in quanto aiuta anche con i titoli multilinea. Ecco il CSS per un singolo articolo:

.toc-list li > a { text-decoration: none; display: grid; grid-template-columns: auto max-content; align-items: end;
} .toc-list li > a > .page { text-align: right;
}

La griglia ha due colonne, la prima delle quali è auto-dimensionato per riempire l'intera larghezza del contenitore, meno la seconda colonna, che è dimensionata a max-content. Il numero di pagina è allineato a destra, come di consueto in un sommario.

L'unica altra modifica che ho apportato a questo punto è stata quella di nascondere il testo della "Pagina". Questo è utile per gli screen reader ma visivamente non necessario, quindi ho usato a tradizionale visually-hidden classe per nasconderlo alla vista:

.visually-hidden { clip: rect(0 0 0 0); clip-path: inset(100%); height: 1px; overflow: hidden; position: absolute; width: 1px; white-space: nowrap;
}

E, naturalmente, l'HTML deve essere aggiornato per usare quella classe:

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title</span> <span class="page"><span class="visually-hidden">Page</span> 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>

Con questa base in atto, sono passato a rivolgermi ai leader tra il titolo e la pagina.

CodePen incorpora il fallback

Creazione di capi punto

I leader sono così comuni nella carta stampata che potresti chiederti, perché i CSS non lo supportano già? La risposta è: lo fa. Bene, tipo di

In realtà c'è un leader() funzione definita in Contenuto generato da CSS per la specifica di Paged Media. Tuttavia, come per gran parte delle specifiche dei media paginati, questa funzione non è implementata in nessun browser, quindi escludendola come opzione (almeno nel momento in cui scrivo questo). Non è nemmeno elencato caniuse.com, presumibilmente perché nessuno l'ha implementato e non ci sono piani o segnali che lo faranno.

Fortunatamente, sia Julie che Christoph hanno già affrontato questo problema nei rispettivi post. Per inserire i capi punto, entrambi hanno usato a ::after pseudo-elemento con il suo content proprietà impostata su una stringa di punti molto lunga, come questa:

.toc-list li > a > .title { position: relative; overflow: hidden;
} .toc-list li > a .title::after { position: absolute; padding-left: .25ch; content: " . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . "; text-align: right;
}

I ::after lo pseudo-elemento è impostato su una posizione assoluta per eliminarlo dal flusso della pagina ed evitare di avvolgerlo in altre righe. Il testo è allineato a destra perché vogliamo che gli ultimi punti di ogni riga siano allineati al numero alla fine della riga. (Maggiori informazioni sulle complessità di questo più avanti.) Il .title l'elemento è impostato per avere una posizione relativa in modo che il ::after pseudo-elemento non esce dalla sua scatola. Intanto il overflow è nascosto in modo che tutti quei punti extra siano invisibili. Il risultato è un bel sommario con puntini.

Tuttavia, c'è qualcos'altro che deve essere preso in considerazione.

Sara mi ha anche fatto notare che tutti quei punti contano come testo per gli screen reader. Allora cosa senti? "Introduzione punto punto punto punto punto..." fino a quando non vengono annunciati tutti i punti. È un'esperienza terribile per gli utenti di screen reader.

La soluzione è inserire un elemento aggiuntivo con aria-hidden impostato true e quindi usa quell'elemento per inserire i punti. Quindi l'HTML diventa:

<ol class="toc-list" role="list"> <li> <a href="#link_to_heading"> <span class="title">Chapter or subsection title<span class="leaders" aria-hidden="true"></span></span> <span class="page"><span class="visually-hidden">Page</span> 1</span> </a> <ol role="list"> <!-- subsection items --> </ol> </li>
</ol>

E il CSS diventa:

.toc-list li > a > .title { position: relative; overflow: hidden;
} .toc-list li > a .leaders::after { position: absolute; padding-left: .25ch; content: " . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . "; text-align: right;
}

Ora i lettori di schermo ignoreranno i punti e risparmieranno agli utenti la frustrazione di ascoltare più punti annunciati.

CodePen incorpora il fallback

Finiture

A questo punto, il componente del sommario sembra abbastanza buono, ma potrebbe richiedere un lavoro di dettaglio minore. Per iniziare, la maggior parte dei libri compensa visivamente i titoli dei capitoli dai titoli delle sottosezioni, quindi ho reso gli elementi di primo livello in grassetto e ho introdotto un margine per separare le sottosezioni dai capitoli successivi:

.toc-list > li > a { font-weight: bold; margin-block-start: 1em;
}

Successivamente, volevo ripulire l'allineamento dei numeri di pagina. Tutto sembrava a posto quando stavo usando un carattere a larghezza fissa, ma per i caratteri a larghezza variabile, i punti guida potrebbero finire per formare un motivo a zigzag mentre si adattano alla larghezza di un numero di pagina. Ad esempio, qualsiasi numero di pagina con un 1 sarebbe più stretto di altri, risultando in punti iniziali disallineati con i punti sulle righe precedenti o successive.

Numeri e punti disallineati in un sommario.
Un sommario perfetto con HTML + CSS

Per risolvere questo problema, ho impostato font-variant-numeric a tabular-nums quindi tutti i numeri sono trattati con la stessa larghezza. Impostando anche la larghezza minima su 2ch, mi sono assicurato che tutti i numeri con una o due cifre fossero perfettamente allineati. (Puoi impostarlo su 3ch se il tuo progetto ha più di 100 pagine.) Ecco il CSS finale per il numero di pagina:

.toc-list li > a > .page { min-width: 2ch; font-variant-numeric: tabular-nums; text-align: right;
}
Punti guida allineati in un sommario.
Un sommario perfetto con HTML + CSS

E con questo, il sommario è completo!

CodePen incorpora il fallback

Conclusione

Creare un sommario con nient'altro che HTML e CSS è stata più una sfida di quanto mi aspettassi, ma sono molto contento del risultato. Non solo questo approccio è abbastanza flessibile da ospitare capitoli e sottosezioni, ma gestisce bene le sottosezioni senza aggiornare il CSS. L'approccio generale funziona sulle pagine Web in cui si desidera collegare i vari percorsi di contenuto, nonché sui PDF in cui si desidera che il sommario si colleghi a pagine diverse. E, naturalmente, ha anche un bell'aspetto stampato se sei incline a usarlo in una brochure o in un libro.

Vorrei ringraziare Julie Blanc e Christoph Grabo per i loro eccellenti post sul blog sulla creazione di un sommario, poiché entrambi erano inestimabili quando ho iniziato. Vorrei anche ringraziare Sara Soueidan per il suo feedback sull'accessibilità mentre lavoravo a questo progetto.


Un sommario perfetto con HTML + CSS originariamente pubblicato il CSS-Tricks. Dovresti ricevi la newsletter.

Timestamp:

Di più da Trucchi CSS