Guida introduttiva alle forme CSS

Inserire contenuti in percorsi personalizzati

Razvan Caliman
Razvan Caliman

Per molto tempo, i web designer sono stati costretti a creare nel rispetto dei vincoli del rettangolo. La maggior parte dei contenuti sul web è ancora intrappolata in semplici scatole perché la maggior parte delle creatività creative verso un layout non rettangolare finisce in frustrazione. Questo sta per cambiare con l'introduzione delle forme CSS, disponibili a partire da Chrome 37. Le forme CSS consentono ai web designer di avvolgere i contenuti attorno a percorsi personalizzati, come cerchi, ellissi e poligoni, liberandosi così dai vincoli del rettangolo.

Le forme possono essere definite manualmente o dedotte dalle immagini.

Vediamo un esempio molto semplice.

Forse sei stato ingenuo come me la prima volta che hai inserito un'immagine con parti trasparenti aspettandoti che i contenuti si adattassero e riempissero gli spazi vuoti, per poi rimanere deluso dalla forma rettangolare che persisteva intorno all'elemento. Per risolvere questo problema puoi utilizzare le forme CSS.

Estrazione di una forma da un'immagine
<img class="element" src="image.png" />
<p>Lorem ipsum…</p>

<style>
.element{
  shape-outside: url(image.png);
  shape-image-threshold: 0.5;
  float: left;
}
</style>

La dichiarazione CSS shape-outside: url(image.png) indica al browser di estrarre una forma dall'immagine.

La proprietà shape-image-threshold definisce il livello di opacità minimo dei pixel che verranno utilizzati per creare la forma. Il valore deve essere compreso tra 0.0 (completamente trasparente) e 1.0 (completamente opaco). Pertanto, shape-image-threshold: 0.5 significa che per creare la forma verranno utilizzati solo i pixel con un'opacità del 50% o superiore.

La proprietà float è fondamentale in questo caso. Anche se la proprietà shape-outside definisce la forma dell'area attorno alla quale verranno visualizzati i contenuti, senza il valore mobile, non è possibile visualizzare gli effetti della forma.

Gli elementi hanno un'area di galleggiamento sul lato opposto del loro valore float. Ad esempio, se un elemento con l'immagine di una tazza di caffè viene visualizzato a sinistra, l'area di galleggiamento verrà creata a destra della tazza. Anche se puoi creare un'immagine con spazi su entrambi i lati, i contenuti verranno a capo solo sul lato opposto indicato dalla proprietà float, a sinistra o a destra, mai su entrambi.

In futuro, sarà possibile utilizzare shape-outside per gli elementi che non sono in virgola mobile con l'introduzione alle esclusioni CSS.

Creare forme manualmente

Oltre a estrarre le forme dalle immagini, puoi anche codificarle manualmente. Puoi scegliere tra alcuni valori funzionali per creare forme: circle(), ellipse(), inset() e polygon(). Ogni funzione di forma accetta un insieme di coordinate ed è abbinata a una scatola di riferimento che stabilisce il sistema di coordinate. A breve parleremo di più delle caselle di riferimento.

La funzione circle()

Illustrazione del valore della forma circle()

La notazione completa per il valore della forma di un cerchio è circle(r at cx cy), dove r è il raggio del cerchio, mentre cx e cy sono le coordinate del centro del cerchio sugli assi X e Y. Le coordinate del centro del cerchio sono facoltative. Se li ometti, verrà utilizzato per impostazione predefinita il centro dell'elemento (l'intersezione delle sue diagonali).

.element{
  shape-outside: circle(50%);
  width: 300px;
  height: 300px;
  float: left;
}

Nell'esempio precedente, i contenuti vengono visualizzati lungo il perimetro di un percorso circolare. Il singolo argomento 50% specifica il raggio del cerchio, che in questo caso specifico corrisponde alla metà della larghezza o dell'altezza dell'elemento. La modifica delle dimensioni dell'elemento influisce sul raggio della forma circolare. Questo è un esempio di base di come le forme CSS possono essere responsive.

Prima di procedere, una breve digressione: è importante ricordare che le forme CSS influiscono solo sulla forma dell'area di galleggiamento attorno a un elemento. Se l'elemento ha uno sfondo, questo non verrà ritagliato dalla forma. Per ottenere questo effetto, devi utilizzare le proprietà di mascheramento CSS: clip-path o mask-image. La proprietà clip-path è molto utile perché segue la stessa notazione delle forme CSS, quindi puoi riutilizzare i valori.

Illustrazione della forma &quot;circle()` + clip-path

Le illustrazioni in questo documento utilizzano il ritaglio per evidenziare la forma e aiutarti a comprendere gli effetti.

Torna alla forma del cerchio.

Quando si utilizzano le percentuali per il raggio del cerchio, il valore viene effettivamente calcolato con una formula leggermente più complessa: radice quadrata di (larghezza^2 + altezza^2) / radice quadrata di 2. È utile capirlo perché ti consente di immaginare quale sarà la forma del cerchio risultante se le dimensioni dell'elemento non sono uguali.

Tutti i tipi di unità CSS possono essere utilizzati nelle coordinate della funzione di forma: px, em, rem, vw, vh e così via. Puoi scegliere quello più flessibile o rigido per le tue esigenze.

Puoi regolare la posizione del cerchio impostando valori espliciti per le coordinate del centro.

.element{
  shape-outside: circle(50% at 0 0);
}

In questo modo il centro del cerchio si trova all'origine del sistema di coordinate. Che cos'è il sistema di coordinate? È qui che vengono introdotte le caselle di riferimento.

Caselle di riferimento per le forme CSS

La casella di riferimento è una casella virtuale attorno all'elemento che stabilisce il sistema di coordinate utilizzato per disegnare e posizionare la forma. L'origine del sistema di coordinate si trova nell'angolo in alto a sinistra, con l'asse X rivolto verso destra e l'asse Y verso il basso.

Sistema di coordinate per le forme CSS

Ricorda che shape-outside modifica la forma dell'area fluttuante attorno alla quale verranno a capo i contenuti. L'area di galleggiamento si estende ai bordi esterni del riquadro definito dalla proprietà margin. Si tratta del margin-box ed è la casella di riferimento predefinita per una forma se non ne viene menzionata una esplicitamente.

Le due dichiarazioni CSS seguenti hanno risultati identici:

.element{
  shape-outside: circle(50% at 0 0);
  /* identical to: */
  shape-outside: circle(50% at 0 0) margin-box;
}

Non abbiamo ancora impostato un margine per l'elemento. A questo punto è meglio supporre che l'origine del sistema di coordinate e il centro del cerchio si trovino nell'angolo superiore sinistro dell'area dei contenuti dell'elemento. Questo cambia quando imposti un margine:

.element{
  shape-outside: circle(50% at 0 0) margin-box;
  margin: 100px;
}

L'origine del sistema di coordinate ora si trova all'esterno dell'area dei contenuti dell'elemento (100 pixel verso l'alto e 100 pixel a sinistra), così come il centro del cerchio. Anche il valore calcolato del raggio del cerchio aumenta per tenere conto dell'aumento della superficie del sistema di coordinate stabilito dalla casella di riferimento margin-box.

Sistema di coordinate della casella del margine con e senza margine
Esistono alcune opzioni di casella di riferimento tra cui scegliere: "margin-box", "border-box", "padding-box" e "content-box". I nomi implicano i relativi confini. Abbiamo già spiegato il valore "margin-box". Il valore "border-box" è limitato dai bordi esterni dei bordi dell'elemento, il valore "padding-box" è limitato dal padding dell'elemento, mentre il valore "content-box" è identico alla superficie effettiva utilizzata dai contenuti all'interno di un elemento.
Illustrazione di tutte le caselle di riferimento

È possibile utilizzare una sola casella di riferimento alla volta con una dichiarazione shape-outside. Ogni casella di riferimento influisce sulla forma in modo diverso e talvolta impercettibile. Trovi un altro articolo che approfondisce l'argomento e ti aiuta a comprendere le caselle di riferimento per le forme CSS.

La funzione ellipse()

Illustrazione del valore di forma ellipse()

Le ellissi sembrano cerchi schiacciati. Sono definiti come ellipse(rx ry at cx cy), dove rx e ry sono i raggi dell'ellisse sull'asse X e sull'asse Y, mentre cx e cy sono le coordinate del centro dell'ellisse.

.element{
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

I valori percentuali verranno calcolati dalle dimensioni del sistema di coordinate. Non servono calcoli matematici divertenti qui. Puoi omettere le coordinate del centro dell'ellisse, che verranno dedotte dal centro del sistema di coordinate.

I raggi sugli assi X e Y possono essere definiti anche con parole chiave: farthest-side restituisce un raggio pari alla distanza tra il centro dell'ellisse e il lato della casella di riferimento più lontano, mentre closest-side significa esattamente il contrario: utilizza la distanza più breve tra il centro e un lato.

.element{
  shape-outside: ellipse(closest-side farthest-side at 50% 50%);
  /* identical to: */
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

Questa opzione può essere utile quando le dimensioni dell'elemento (o della casella di riferimento) possono cambiare in modi imprevedibili, ma vuoi che la forma dell'ellisse si adatti.

Le stesse parole chiave farthest-side e closest-side possono essere utilizzate anche per il raggio nella funzione della forma circle().

La funzione polygon()

Illustrazione del valore della forma polygon()

Se cerchi qualcosa di più di cerchi ed ellissi, la funzione della forma poligonale ti offre un mondo di opzioni. Il formato è polygon(x1 y1, x2 y2, ...), in cui specifichi le coppie di coordinate x y per ogni vertice (punto) di un poligono. Il numero minimo di coppie per specificare un poligono è tre, un triangolo.

.element{
  shape-outside: polygon(0 0, 0 300px, 300px 600px);
  width: 300px;
  height: 600px;
}

I vertici vengono posizionati sul sistema di coordinate. Per i poligoni reattivi puoi utilizzare i valori percentuali per alcune o tutte le coordinate.

.element{
  /* polygon responsive to font-size*/
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  width: 20em;
  height: 40em;
}

Esiste un parametro facoltativo fill-rule, importato da SVG, che indica al browser come considerare l'appartenenza a un poligono in caso di percorsi autointersecati o forme racchiuse. Joni Trythall spiega molto bene come funziona la proprietà con regola di riempimento in SVG. Se non è definito, il valore predefinito di fill-rule è nonzero.

.element{
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  /* identical to: */
  shape-outside: polygon(nonzero, 0 0, 0 100%, 100% 100%);
}

La funzione inset()

La funzione di forma inset() consente di creare forme rettangolari attorno alle quali avvolgere i contenuti. Ciò potrebbe sembrare controintuitivo, considerando la premessa iniziale che CSS Shapes libera i contenuti web da semplici caselle. Potrebbe benissimo essere così. Non ho ancora trovato un caso d'uso per inset() che non sia già realizzabile con i valori float e margin o con un polygon(). Tuttavia, inset() fornisce un'espressione più leggibile per le forme rettangolari rispetto a polygon().

La notazione completa per una funzione di forma incassata è inset(top right bottom left border-radius). I primi quattro argomenti posizione sono offset verso l'interno rispetto ai bordi dell'elemento. L'ultimo argomento è il raggio del bordo per la forma rettangolare. È facoltativo, quindi puoi ometterlo. Segue la notazione abbreviata border-radius che già utilizzi in CSS.

.element{
  shape-outside: inset(100px 100px 100px 100px);
  /* yields a rectangular shape which is 100px inset on all sides */
  float: left;
}

Creazione di forme da caselle di riferimento

Se non specifichi una funzione di forma per la proprietà shape-outside, puoi consentire al browser di ricavare una forma dalla casella di riferimento dell'elemento. La casella di riferimento predefinita è margin-box. Finora niente di esotico, è così che funzionano già i valori fluttuanti. Tuttavia, applicando questa tecnica, puoi riutilizzare la geometria di un elemento. Diamo un'occhiata alla proprietà border-radius.

Se la utilizzi per arrotondare gli angoli di un elemento fluttuante, si ottiene l'effetto di ritaglio, ma l'area mobile rimane rettangolare. Aggiungi shape-outside: border-box per avvolgere il contorno creato da border-radius.

Estrazione di una forma da border-radius di un elemento utilizzando la casella di riferimento border-box
.element{
  border-radius: 50%;
  shape-outside: border-box;
  float: left;
}

Ovviamente, puoi utilizzare tutte le caselle di riferimento in questo modo. Ecco un altro utilizzo delle forme derivate: le virgolette diritte con spaziatura interna.

Creare una citazione fuori testo utilizzando la casella di riferimento della casella dei contenuti

È possibile ottenere l'effetto di citazione fuori linea utilizzando solo le proprietà float e margin. Tuttavia, devi posizionare l'elemento della citazione nella struttura ad albero HTML nel punto in cui vuoi che venga visualizzato.

Ecco come ottenere lo stesso effetto di citazione offset con una maggiore flessibilità:

.pull-quote{
  shape-outside: content-box;
  margin-top: 200px;
  float: left;
}

Impostiamo esplicitamente la casella di riferimento content-box per il sistema di coordinate della forma. In questo caso, la quantità di contenuti nella citazione definisce la forma attorno alla quale verrà aggregato il contenuto esterno. La proprietà margin-top viene utilizzata qui per posizionare (offset) la citazione, indipendentemente dalla sua posizione nella struttura ad albero HTML.

Margine forma

Tieni presente che l'inserimento di a capo nei contenuti intorno a una forma può farli aderire troppo all'elemento. Puoi aggiungere spaziatura attorno alla forma con la proprietà shape-margin.

.element{
  shape-outside: circle(40%);
  shape-margin: 1em;
  float: left;
}

L'effetto è simile a quello che ottieni utilizzando la proprietà margin normale, ma shape-margin influisce solo sullo spazio attorno al valore shape-outside. Verrà aggiunta spaziatura attorno alla forma solo se è presente spazio nel sistema di coordinate. Ecco perché nell'esempio precedente il raggio del cerchio è impostato sul 40%, non sul 50%. Se il raggio fosse stato impostato sul 50%, il cerchio avrebbe occupato tutto lo spazio nel sistema di coordinate senza lasciare spazio per l'effetto di shape-margin. Ricorda che la forma è limitata al margin-box dell'elemento (l'elemento più il relativo margin-box circostante). Se la forma è più grande e fuoriesce, verrà ritagliata in base al margin-box e otterrai una forma rettangolare.

È importante capire che shape-margin accetta un solo valore positivo. Non ha una notazione a mano lunga. Che cos'è shape-margin-top per un cerchio?

Animazione delle forme

Puoi combinare le forme CSS con molte altre funzionalità CSS, come transizioni e animazioni. Tuttavia, devo sottolineare che gli utenti trovano molto fastidioso quando il layout del testo cambia durante la lettura. Presta particolare attenzione all'esperienza se decidi di animare le forme.

Puoi animare i raggi e i centri delle forme circle() e ellipse() a condizione che siano definiti in valori che il browser può interpolare. È possibile andare da circle(30%) a circle(50%). Tuttavia, l'animazione tra circle(closest-side) e circle(farthest-side) comporta il blocco del browser.

.element{
  shape-outside: circle(30%);
  transition: shape-outside 1s;
  float: left;
}

.element:hover{
  shape-outside: circle(50%);
}
GIF di un cerchio animato

È possibile ottenere effetti più interessanti quando si animano le forme polygon(), ma è importante ricordare che il poligono deve avere lo stesso numero di vertici tra i due stati di animazione. Il browser non può eseguire l'interpolazione se aggiungi o rimuovi vertici.

Un trucco consiste nell'aggiungere la quantità massima di vertici necessari e posizionarli raggruppati nello stato di animazione in cui vuoi che la forma abbia meno bordi percepiti.

.element{
  /* four vertices (looks like rectangle) */
  shape-outside: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  transition: shape-outside 1s;
}

.element:hover{
  /* four vertices, but second and third overlap (looks like triangle) */
  shape-outside: polygon(0 0, 100% 50%, 100% 50%, 0 100%);
}
GIF di un triangolo animato

Aggiungere a capo i contenuti all'interno di una forma

Screenshot della demo di Alice nel paese delle meraviglie che utilizza le forme CSS per il wrapping dei contenuti

La bozza iniziale della specifica delle forme CSS includeva una proprietà shape-inside che consentiva di a capo i contenuti all'interno di una forma. Per un po' di tempo ci sono state persino implementazioni in Chrome e Webkit. Tuttavia, l'inserimento di contenuti posizionati in modo arbitrario all'interno di un percorso personalizzato richiede molto più impegno e ricerca per coprire tutti gli scenari possibili ed evitare bug. Per questo motivo, la proprietà shape-inside è stata posticipata al livello 2 delle forme CSS e le relative implementazioni sono state ritirate.

Tuttavia, con un po' di impegno e qualche compromesso, puoi comunque ottenere l'effetto di a capo dei contenuti all'interno di una forma personalizzata. L'hack consiste nell'utilizzare due elementi con shape-outside in modalità floating, posizionati ai lati opposti di un contenitore. Il compromesso è che devi usare uno o due elementi vuoti che non hanno un significato semantico, ma che fungono da puntoni per creare l'illusione di una forma all'interno.

<div>
  <div class='left-shape'></div>
  <div class='right-shape'></div>

  Lorem ipsum...
</div>

La posizione degli elementi strut .left-shape e .right-shape nella parte superiore del contenitore è importante perché verranno visualizzati a sinistra e a destra per affiancare i contenuti.

.left-shape{
  shape-outside: polygon(0 0, ...);
  float: left;
  width: 50%;
  height: 100%;
}

.right-shape{
  shape-outside: polygon(50% 0, ...);
  float: right;
  width: 50%;
  height: 100%;
}
Illustrazione della soluzione alternativa per shape-inside per la demo di Alice

Questo stile fa sì che i due elementi di supporto con aggiornamento dinamico occupino tutto lo spazio all'interno dell'elemento, ma le proprietà shape-outside ricavano spazio per il resto dei contenuti.

Se le forme CSS non sono supportate dal browser, produrrà brutti effetti spingendo tutti i contenuti verso il basso. Ecco perché è importante utilizzare la funzionalità in modo progressivamente migliorato.

Negli esempi precedenti di animazione delle forme, noterai che lo spostamento del testo può essere fastidioso. Non tutti i casi d'uso garantiscono una forma animata. Tuttavia, puoi animare altre proprietà che interagiscono con le forme CSS per aggiungere effetti dove è opportuno.

Nella dimostrazione di CSS Shapes di Alice nel paese delle meraviglie, abbiamo utilizzato la posizione di scorrimento per modificare il margine superiore dei contenuti. Il testo è compresso tra due elementi con il testo a galleggiare. Quando si sposta verso il basso, deve essere riorganizzato in base al shape-outside dei due elementi con layout flottante. Questo dà l'impressione che il testo stia scendendo nella tana del Bianconiglio e contribuisce all'esperienza di narrazione. Un limite senza costi? Forse. Ma ha un aspetto fantastico.

Poiché il layout del testo viene eseguito in modo nativo dal browser, le prestazioni sono migliori rispetto all'utilizzo di una soluzione JavaScript. Tuttavia, la modifica di margin-top durante lo scorrimento attiva molti eventi di ridisegni e di aggiornamento della visualizzazione, il che può ridurre notevolmente le prestazioni. Da usare con cautela. Tuttavia, l'utilizzo delle forme CSS senza animarle non comporta un calo del rendimento percepibile.

Potenziamento progressivo

Inizia assumendo che il browser non supporti le forme CSS e poi sviluppa questa ipotesi quando rilevi la funzionalità. Modernizr è una buona soluzione per il rilevamento delle funzionalità ed è disponibile un test per le forme CSS nella sezione "Rilevamento non di base".

Alcuni browser forniscono il rilevamento delle funzionalità in CSS tramite la regola @supports senza la necessità di librerie esterne. Google Chrome, che supporta anche le forme CSS, comprende la regola @supports. Ecco come utilizzarlo per migliorare progressivamente:

.element{
  /* styles for all browsers */
}

@supports (shape-outside: circle(50%)){
  /* styles only for browsers which support CSS Shapes */
  .element{
    shape-outside: circle(50%);
  }
}

Lea Verou ha scritto di più su come utilizzare la regola CSS @supports.

Disambiguazione dalle esclusioni CSS

Quello che oggi conosciamo come forme CSS all'inizio della specifica si chiamavano forme ed esclusioni CSS. Il passaggio alla denominazione potrebbe sembrare una sfumatura, ma in realtà è molto importante. Le esclusioni CSS, ora una specifica separata, consentono di avvolgere i contenuti attorno a elementi posizionati in modo arbitrario, senza la necessità di una proprietà float. Immaginate di racchiudere i contenuti attorno a un elemento con una posizione assoluta, questo è un caso d'uso per le esclusioni CSS. Le forme CSS definiscono solo il percorso attorno al quale verranno a capo i contenuti.

Pertanto, le forme e le esclusioni non sono la stessa cosa, ma si completano a vicenda. Le forme CSS sono già disponibili nei browser, mentre le esclusioni CSS non sono ancora implementate con l'interazione delle forme.

Strumenti per lavorare con le forme CSS

Puoi creare percorsi negli strumenti di creazione di immagini classici, ma al momento nessuno di questi esporta la sintassi richiesta per i valori delle forme CSS. Anche se fosse così, lavorare in questo modo non sarebbe molto pratico.

Le forme CSS sono destinate all'utilizzo nel browser, dove reagiscono ad altri elementi della pagina. È molto utile per visualizzare gli effetti della modifica della forma sui contenuti che la circondano. Esistono alcuni strumenti che possono aiutarti in questo flusso di lavoro:

Brackets: l'estensione Editor di forme CSS per Brackets utilizza la modalità di anteprima in tempo reale dell'editor di codice per sovrapporre un editor interattivo per la modifica dei valori delle forme.

Google Chrome: l'estensione Editor di forme CSS per Google Chrome espande gli Strumenti per sviluppatori del browser con controlli per creare e modificare le forme. Inserisce un editor interattivo sopra l'elemento selezionato.

La funzionalità di controllo in Google Chrome ha un supporto integrato per l'evidenziazione delle forme. Passa il mouse sopra un elemento con una proprietà shape-outside e si illuminerà per illustrare la forma.

Forme da immagini: se preferisci generare immagini da cui il browser estraggono forme, Rebecca Hauck ha scritto un buon tutorial per Photoshop.

Polyfill: Google Chrome è il primo browser importante a supportare le forme CSS. È in arrivo il supporto per la funzionalità su Apple iOS 8 e Safari 8. Altri fornitori di browser potrebbero prenderla in considerazione in futuro. Fino ad allora, è disponibile un polyfill delle forme CSS per fornire assistenza di base.

Conclusione

In un web in cui i contenuti sono per lo più intrappolati in semplici riquadri, le forme CSS offrono un modo per creare layout espressivi, colmando il divario di fedeltà tra il design web e quello di stampa. Naturalmente, le forme possono essere abusate e creare distrazioni. Tuttavia, se applicate con gusto e buon giudizio, le forme possono migliorare la presentazione dei contenuti e focalizzare l'attenzione dell'utente in un modo unico per loro.

Ti lascio con una raccolta di opere di altri, principalmente cartacei, che dimostra utilizzi interessanti del layout non rettangolare. Spero che questo ti incoraggi a provare le forme CSS e a sperimentare nuove idee di design.

Ringraziamo Pearl Chen, Alan Stearns e Zoltan Horvath per aver letto questo articolo e aver fornito preziosi spunti.