Rompere le scatole con la frammentazione CSS
Pubblicato: 2022-03-10In questo articolo, ti presenterò la specifica della frammentazione CSS. Potresti non averne mai sentito parlare, tuttavia, se hai mai creato un foglio di stile di stampa e volevi controllare dove si interrompe il contenuto tra le pagine o il layout a più colonne e volevi fermare una figura che si interrompe tra le colonne, l'hai incontrato.
Trovo che molto spesso i problemi che le persone segnalano con multicol siano in realtà problemi con il supporto della frammentazione del browser. Dopo una rapida carrellata delle proprietà contenute in questa specifica, spiegherò lo stato attuale del supporto del browser e alcune delle cose che puoi fare per farlo funzionare al meglio nei tuoi progetti multicol e di stampa.
Cos'è la frammentazione?
La frammentazione nei CSS descrive il processo mediante il quale il contenuto viene suddiviso in diverse caselle. Attualmente, abbiamo due punti in cui potremmo imbatterci in una frammentazione sul Web: quando stampiamo un documento e se utilizziamo il layout a più colonne. Queste due cose sono essenzialmente le stesse. Quando si stampa (o si salva in PDF) una pagina Web, il contenuto viene frammentato in tante pagine quante sono necessarie per stampare il contenuto.
Quando usi multicol, il contenuto viene frammentato in colonne. Ogni casella di colonna è come una pagina nel contesto della pagina. Se pensi che un insieme di colonne sia molto simile a un insieme di pagine, può essere un modo utile per pensare al multicolo e al modo in cui funziona la frammentazione in esso.
Se dai un'occhiata alla specifica di frammentazione CSS, vedrai menzionato un terzo contesto frammentato: quel contesto è Regions. Poiché non ci sono attualmente implementazioni utilizzabili di Regioni, non ne tratteremo in questo articolo, ma esamineremo invece i due contesti che potresti incontrare nel tuo lavoro.
Block E Scatole Inline
In questo articolo menzionerò molto le scatole a blocchi. Ogni elemento della tua pagina ha una casella. Alcune di queste caselle sono disposte come blocchi: paragrafi, voci di elenco, intestazioni. Si dice che partecipino a un contesto di formattazione a blocchi. Altri sono in linea come le parole in un paragrafo, le campate e gli elementi di ancoraggio. Questi partecipano a un contesto di formattazione in linea. In parole povere, quando mi riferisco a un riquadro a blocchi, sto parlando di riquadri attorno a cose come i paragrafi. Quando si ha a che fare con la frammentazione, è importante sapere con quale tipo di scatola si ha a che fare.
Per ulteriori informazioni sul layout a blocchi e inline, vedere l'articolo MDN "Layout a blocchi e inline nel flusso normale". È una di quelle cose che probabilmente tutti comprendiamo a un certo livello, ma potremmo non aver incontrato la terminologia di prima.
Controllo delle pause
Sia che tu stia creando un foglio di stile di stampa, utilizzando un programma utente di stampa specifico per creare un PDF o utilizzando multicol, a volte ti imbatterai in problemi simili a questo.
Nell'esempio multicolo di seguito, ho alcuni contenuti che sto visualizzando come tre colonne. Nel mezzo del contenuto c'è un'area inscatolata, che viene suddivisa su due colonne. Non voglio questo comportamento, vorrei che la scatola rimanesse unita.
Per risolvere questo problema, aggiungo la proprietà break-inside: avoid
alla casella. I controlli della proprietà break-inside
interrompono gli elementi all'interno quando si trovano in un contesto frammentato. In un browser che supporta questa proprietà, la casella ora rimarrà in una delle colonne. Le colonne sembreranno meno ben bilanciate, tuttavia, in genere è una cosa migliore che finire con il riquadro diviso tra le colonne.
La proprietà break-inside
è una delle proprietà dettagliate nelle specifiche di frammentazione. L'elenco completo degli immobili è il seguente:
-
break-before
-
break-after
-
break-inside
-
orphans
-
widows
-
box-decoration-break
Diamo un'occhiata a come dovrebbero funzionare prima di passare a ciò che accade effettivamente nei browser.
Le proprietà break-before
e break-after
Esistono due proprietà che controllano le interruzioni tra le caselle a livello di blocco: break-before
e break-after
. Se hai un h2
seguito da due paragrafi <p>
hai tre caselle di blocco e useresti queste proprietà per controllare le interruzioni tra l'intestazione e il primo paragrafo, o tra i due paragrafi.
Le proprietà vengono utilizzate sui selettori che prendono di mira l'elemento che si desidera interrompere prima o dopo.
Ad esempio, potresti voler inserire il foglio di stile di stampa su una nuova pagina ogni volta che è presente un'intestazione di livello 2. In questo caso, useresti break-before: page
sull'elemento h2
. Questo controlla la frammentazione e assicura che ci sia sempre un'interruzione prima della casella dell'elemento h2
.
h2 { break-before: page; }
Un altro requisito comune è evitare che le intestazioni finiscano come l'ultima cosa in una pagina o in una colonna. In questo caso, potresti usare break-after
con un valore di avoid
. Ciò dovrebbe impedire un'interruzione direttamente dopo la casella dell'elemento:
h1, h2, h3, h4 { break-after: avoid; }
Frammenti all'interno di frammenti
È possibile che un elemento frammentato sia annidato all'interno di un altro. Ad esempio, avere un multicolo all'interno di qualcosa che viene impaginato. In tal caso, potresti voler controllare le interruzioni per le pagine ma non per le colonne, o viceversa. Questo è il motivo per cui abbiamo valori come page
che forzerebbero sempre un'interruzione prima o dopo l'elemento ma solo quando il frammento è una pagina. O avoid-page
che eviterebbe un'interruzione prima o dopo l'elemento solo per i contesti paginati.
Lo stesso vale per le colonne. Se utilizzi il valore column
, questo forzerebbe sempre un'interruzione prima o dopo quell'elemento, ma solo per contesti multicolonna. Il valore avoid-column
impedirebbe un'interruzione nei contesti multicolonna.
C'è un valore always
nella specifica di livello 4 che indica che vuoi sfondare tutto: pagina o colonna. Tuttavia, in quanto aggiunta recente alle specifiche, al momento non ci è utile.
Valori aggiuntivi per i media paginati
Se stai creando un libro o una rivista, hai le pagine sinistra e destra. Potresti voler controllare l'interruzione per forzare qualcosa sulla pagina sinistra o destra di uno spread. Pertanto, l'utilizzo di quanto segue inserirebbe interruzioni di una o due pagine prima di h2
per assicurarsi che fosse formattato come pagina corretta.
h2 { break-before: right; }
Esistono anche valori recto e verso che si riferiscono alla progressione di pagina poiché i libri scritti in una lingua verticale o da destra a sinistra hanno una progressione di pagina diversa rispetto ai libri scritti in inglese. Non tratterò ulteriormente questi valori in questo articolo poiché sono principalmente interessato a ciò che è possibile dal browser questa volta.
break-inside
Abbiamo già visto un esempio della proprietà break-inside
. Questa proprietà controlla l'interruzione all'interno di riquadri di blocco, ad esempio all'interno di un paragrafo, un'intestazione o un div.
Le cose che potresti non voler rompere possono includere un riquadro come descritto sopra: figure in cui non vuoi che la didascalia si stacchi dall'immagine, tabelle, elenchi e così via. Aggiungi break-inside: avoid
qualsiasi contenitore che non desideri interrompere in alcun contesto di frammentazione. Se desideri solo evitare interruzioni tra le colonne, usa break-inside: avoid-column
e tra le pagine break-inside: avoid-page
.
Gli orphans
e widows
Proprietà
Le proprietà orphans
e widows
si occupano di quante righe devono essere lasciate prima o dopo un'interruzione (causata da una colonna o da una nuova pagina). Ad esempio, se voglio evitare che una singola riga venga lasciata alla fine di una colonna, userei la proprietà orphans
, poiché in tipografia, un orphan è la prima riga di un paragrafo che appare da sola in fondo a una pagina con il resto del paragrafo spezzato su un'altra pagina. La proprietà deve essere aggiunta allo stesso elemento che sta frammentando (nel nostro caso, il contenitore multicol).
.container { column-count: 3; orphans: 2; }
Per controllare quante righe devono essere presenti nella parte superiore di una colonna o di una pagina dopo un'interruzione, utilizzare widows
:
.container { column-count: 3; widows: 2; }
Queste proprietà gestiscono le interruzioni tra le caselle inline come le righe di parole all'interno di un paragrafo. Pertanto, non aiutano nella situazione in cui un'intestazione o un altro elemento di blocco è solo nella parte inferiore di una colonna o di una pagina, per questo sono necessarie le proprietà di interruzione discusse sopra.
Decorazione della scatola
Un'ultima proprietà che potrebbe interessare è la proprietà box-decoration-break
. Questo controlla la situazione in cui hai una casella con un bordo interrotto tra due caselle o pagine di colonne. Vuoi che il bordo sia essenzialmente tagliato a metà? O vuoi che ciascuna delle due metà della scatola sia completamente avvolta in un bordo?
Il primo scenario è l'impostazione predefinita ed è come se si impostasse la proprietà box-decoration-break
per slice
la scatola.
.box { box-decoration-break: slice; }
Per ottenere il secondo comportamento, imposta box-decoration-break
su clona.
.box { box-decoration-break: clone; }
Supporto del browser per la frammentazione
Ora veniamo al motivo per cui non ho un sacco di esempi di CodePen sopra per dimostrarti tutto questo e il motivo principale per cui scrivo questo articolo. Il supporto del browser per queste proprietà non è eccezionale.
Se stai lavorando in Paged Media con uno specifico user agent come Prince, allora puoi godere di un ottimo supporto per la frammentazione e probabilmente troverai queste proprietà molto utili. Se stai lavorando con un browser web, in multicol, creando fogli di stile di stampa o utilizzando qualcosa come Chrome senza testa per generare PDF, il supporto è alquanto irregolare. Scoprirai che il browser con il miglior supporto è Edge, fino a quando non si sposta comunque su Chromium!
Posso usare non è particolarmente utile per spiegare il supporto a causa della combinazione delle proprietà di frammentazione con multicol, quindi della disponibilità di alcuni dati separati per le proprietà legacy. Quindi, come parte del lavoro che ho svolto per MDN per documentare le proprietà e il loro supporto, ho iniziato a testare l'effettivo supporto del browser. Quello che segue è un consiglio basato su quel test.
Proprietà con prefisso legacy e fornitore
Non posso andare molto oltre senza una lezione di storia. Se trovi che hai davvero bisogno di supporto per la frammentazione, potresti trovare qualche sollievo nelle proprietà legacy che originariamente facevano parte di CSS2 (o in alcune proprietà prefissate che esistono).
In CSS2 c'erano proprietà per controllare l'interruzione di pagina. Multicol non esisteva a quel punto, quindi l'unico contesto frammentato era quello paginato. Ciò significava che sono state introdotte tre proprietà di interruzione di pagina specifiche:
-
page-break-before
-
page-break-after
-
page-break-inside
Funzionano in modo simile alle proprietà più generiche senza il prefisso di page-
, controllando le interruzioni prima, dopo e all'interno delle caselle. Per i fogli di stile di stampa, scoprirai che alcuni browser meno recenti che non supportano le nuove proprietà di break-
supportano queste proprietà con prefisso di pagina. Le proprietà vengono trattate come alias per le nuove proprietà.
In una bozza di lavoro del 2005 della specifica multicol sono i dettagli delle proprietà di interruzione per multicol, utilizzando le proprietà con il prefisso column-
(cioè column-break-before
, column-break-after
e column-break-inside
). Nel 2009, questi erano scomparsi e nella specifica multicol c'era una bozza per le proprietà di interruzione senza prefisso che alla fine si sono fatte strada nella specifica di frammentazione CSS.
Tuttavia, alcune proprietà specifiche della colonna con prefisso del fornitore sono state implementate in base a queste proprietà. Questi sono:
-
-webkit-column-break-before
-
-webkit-column-break-after
-
-webkit-column-break-inside
Supporto per la frammentazione in Multicol
Quanto segue si basa sul test di queste funzionalità in contesti multicolonna. Ho provato a spiegare cosa è possibile, ma dai un'occhiata a CodePens in qualsiasi browser tu abbia a disposizione.
Multicolor e break-inside
Il supporto in multicol è il migliore per la proprietà break-inside
. Le versioni aggiornate di Chrome, Firefox, Edge e Safari supportano tutte il break-inside: avoid
. Quindi dovresti scoprire che puoi impedire che le caselle si interrompano tra le colonne quando usi multicol.
Diversi browser, ad eccezione di Firefox, supportano la -webkit-column-break-inside
, che può essere utilizzata con un valore di avoid
e può impedire che le caselle si interrompano tra le colonne che non supportano break-inside
.
Firefox supporta page-break-inside: avoid
in multicol. Pertanto, l'utilizzo di questa proprietà eviterà interruzioni all'interno delle caselle nei browser Firefox precedenti a Firefox 65.
Ciò significa che se vuoi evitare interruzioni tra le caselle in multicol, l'utilizzo del seguente CSS coprirà il maggior numero possibile di browser, tornando il più indietro possibile.
.box { -webkit-column-break-inside: avoid; page-break-inside: avoid; break-inside: avoid; }
Per quanto riguarda il valore della column
, affermando esplicitamente che si desidera evitare solo interruzioni tra le colonne e non le pagine, funziona in tutti i browser tranne Firefox.
Il CodePen di seguito arrotonda alcuni di questi test in multicol in modo che tu possa provarli tu stesso.
Multicol E break-before
Per prevenire interruzioni prima di un elemento, dovresti essere in grado di utilizzare break-before: avoid
o break-before: avoid-column
. La proprietà evita non ha il supporto del browser.
Edge supporta break-before: column
per forzare sempre un'interruzione prima del riquadro dell'elemento.
Safari, Chrome ed Edge supportano anche -webkit-column-break-before: always
che forzerà un'interruzione prima della casella dell'elemento. Pertanto, se vuoi forzare un'interruzione prima del riquadro di un elemento, dovresti usare:
.box { -webkit-column-break-before: always; break-before: column; }
Prevenire una pausa prima della scatola è attualmente un compito impossibile. Puoi giocare con alcuni esempi di queste proprietà di seguito:
Multicol E break-after
Per evitare interruzioni dopo un elemento, per evitare che diventi l'ultima cosa in fondo a una colonna, dovresti essere in grado di usare break-after: avoid
e break-after: avoid-column
. L'unico browser con supporto per questi è Edge.
Edge supporta anche la forzatura delle interruzioni dopo un elemento utilizzando break-after: column
, Chrome supporta break-after: column
e anche -webkit-column-break-after: always
.
Firefox non supporta break-after
o alcuna delle proprietà prefissate per forzare o consentire interruzioni dopo una casella.
Pertanto, a parte Edge, non puoi davvero evitare le interruzioni dopo una scatola. Se vuoi forzarli, otterrai risultati in alcuni browser utilizzando il seguente CSS:
.box { -webkit-break-after: always; break-after: column; }
Supporto durante la stampa dal browser
Se stampi direttamente dal tuo browser desktop o generi file PDF utilizzando Chrome senza testa o qualche altra soluzione basata sulla tecnologia del browser non fa alcuna differenza. Fai affidamento sul supporto del browser per le proprietà di frammentazione.
Se crei un foglio di stile di stampa, troverai un supporto simile per le proprietà di interruzione come per multicol; tuttavia, per supportare i browser meno recenti è necessario raddoppiare le proprietà per utilizzare le proprietà con prefisso di page-
.
Stampa fogli di stile e break-inside
Nei browser moderni, la proprietà break-inside
può essere utilizzata per prevenire interruzioni all'interno delle caselle, aggiungere la proprietà page-break-inside
per aggiungere il supporto per i browser meno recenti.
.box { page-break-inside: avoid; break-inside: avoid; }
Stampa fogli di stile e break-before
Per forzare le interruzioni prima di una casella, utilizzare break-before:page
insieme a page-break-before: always
.
.box { page-break-before: always; break-before: page; }
Per evitare interruzioni prima di una casella, utilizzare break-before: avoid-page
insieme a page-break-before: avoid
.
.box { page-break-before: avoid; break-before: avoid-page; }
C'è un supporto migliore per i valori di page
ed avoid-page
rispetto a quello che vediamo per i valori multicol equivalenti. La maggior parte dei browser moderni ha il supporto.
Stampa fogli di stile e break-before
Per forzare le interruzioni dopo una casella, utilizzare break-after: page
insieme a page-break-after: always
.
.box { page-break-after: always; break-after: page; }
Per evitare interruzioni dopo una casella, utilizzare break-after: avoid-page
insieme a page-break-after: avoid
.
.box { page-break-after: avoid; break-after: avoid-page; }
Vedove e orfani
Le proprietà widows
e orphans
godono di un buon supporto cross-browser: l'unico browser senza un'implementazione è Firefox. Suggerirei di usarli quando crei un layout multicolo o un foglio di stile di stampa. Se non funzionano per qualche motivo, otterrai vedove e orfani, il che non è l'ideale ma non è nemmeno un disastro. Se funzionano, la tua tipografia avrà un aspetto migliore.
scatola-decorazione-pausa
La proprietà finale di box-decoration-break
ha il supporto per multicol e print in Firefox. Safari, Chrome e altri browser basati su Chromium supportano -webkit-box-decoration-break
, ma solo su elementi inline. Quindi puoi clonare i bordi attorno alle righe di una frase, ad esempio; non hanno supporto nel contesto che stiamo guardando.
Nella CodePen di seguito, puoi vedere che il test per -webkit-box-decoration-break: clone
with Feature Query restituisce true; tuttavia la proprietà non ha effetto sul bordo del box nel contesto multicol.
Usando la frammentazione
Come puoi vedere, l'attuale stato di frammentazione nei browser è alquanto frammentato! Detto questo, c'è una quantità ragionevole che puoi ottenere e dove fallisce, il risultato tende a essere non ottimale ma non un disastro. Il che significa che vale la pena provare.
Vale la pena notare che essere troppo gravosi con queste proprietà potrebbe comportare qualcosa di diverso da quello che speravi. Se stai lavorando sul Web invece di stampare e forzare le interruzioni di colonna dopo ogni paragrafo, quindi finisci con più paragrafi che spazio per le colonne, multicol finirà per traboccare nella direzione inline. Esaurirà le colonne per posizionare i tuoi paragrafi aggiuntivi. Pertanto, anche dove c'è supporto, è comunque necessario testare attentamente e ricordare che in molti casi meno è di più.
Più risorse
Per saperne di più sulle proprietà, vai su MDN, ho recentemente aggiornato le pagine lì e sto anche cercando di mantenere aggiornati i dati di compatibilità del browser. La pagina principale per la frammentazione CSS si collega alle singole pagine delle proprietà che contengono ulteriori esempi, dati di compatibilità del browser e altre informazioni sull'utilizzo di queste proprietà.