Introduzione alle forme CSS

Inserire contenuti in percorsi personalizzati

Razvan Caliman
Razvan Caliman

Per molto tempo, i web designer sono stati costretti a creare contenuti rispettando i vincoli del rettangolo. La maggior parte dei contenuti sul web è ancora intrappolata in semplici caselle perché la maggior parte delle iniziative creative con layout non rettangolari 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 a capo e riempissero gli spazi vuoti, per poi rimanere deluso dalla forma rettangolare del testo a capo che persiste 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 indica che per creare la forma verranno utilizzati solo i pixel con opacità pari o superiore al 50%.

La proprietà float è fondamentale in questo caso. Sebbene la proprietà shape-outside definisca la forma dell'area intorno alla quale i contenuti verranno a capo, senza il parametro float non vedrai 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 non in primo piano con l'introduzione delle 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 è accoppiata a una casella 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 un valore della forma del cerchio è circle(r at cx cy), dove r è il raggio del cerchio, mentre cx e cy sono le coordinate del centro del cerchio sull'asse X e sull'asse 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 comprenderlo perché ti aiuterà a immaginare 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 modificare 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 è possibile presumere che l'origine del sistema di coordinate e il centro del cerchio si trovino nell'angolo in alto a sinistra 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" è vincolato dai bordi esterni dei bordi dell'elemento, il valore "padding-box" è vincolato 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. Esiste 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 della 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 sono richieste operazioni matematiche complicate. 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 coppie di coordinate x e 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 adattabili puoi utilizzare 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'"interno" di un poligono in caso di percorsi autointersecati o forme racchiuse. Joni Trythall spiega molto bene come funziona la proprietà fill-rule 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 utilizzi già 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 lo utilizzi per arrotondare gli angoli di un elemento con il testo a capo, ottieni l'effetto di ritaglio, ma l'area del testo a capo 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 quote 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 della citazione determina la forma attorno alla quale verranno a capo i contenuti esterni. 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.margin

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

Animare le 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 passare da circle(30%) a circle(50%). Tuttavia, l'animazione tra circle(closest-side) e circle(farthest-side) bloccherà il 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 tenere presente 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 inserire a capo i contenuti all'interno di una forma. Per un po' di tempo sono state implementate anche 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 utilizzare uno o due elementi vuoti che non hanno un significato semantico, ma fungono da supporti 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, si verificheranno effetti indesiderati perché tutti i contenuti verranno spostati 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 richiedono 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 a capo. 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. Borderline senza costi? Forse. Ma è bello.

Poiché il layout del testo viene eseguito in modo nativo dal browser, il rendimento è migliore 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

Le forme CSS, come le conosciamo oggi, erano chiamate esclusioni e forme CSS nelle prime versioni della specifica. Il cambio di nome 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. Immagina di avvolgere i contenuti attorno a un elemento con posizionamento assoluto. 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.

L'ispezionatore in Google Chrome supporta l'evidenziazione delle forme. Passa il mouse sopra un elemento con una proprietà shape-outside e si illuminerà per illustrare la forma.

Forme dalle immagini: se preferisci generare immagini e lasciare che il browser ne estragga le forme, Rebecca Hauck ha scritto un buon tutorial per Photoshop.

Polyfill: Google Chrome è il primo browser importante a supportare le forme CSS. La funzionalità sarà presto supportata su iOS 8 e Safari 8 di Apple. Altri fornitori di browser potrebbero prenderlo in considerazione in futuro. Fino ad allora, è disponibile un polyfill di CSS Shapes per fornire un'assistenza di base.

Conclusione

In un web in cui i contenuti sono per lo più racchiusi 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 usate in modo improprio e creare distrazioni. Tuttavia, se applicate con gusto e buon senso, le forme possono migliorare la presentazione dei contenuti e attirare l'attenzione dell'utente in un modo unico.

Ti lascio con una raccolta di lavori di altri, per lo più stampati, che dimostrano usi interessanti per il layout non rettangolare. Spero che questo ti incoraggi a provare le forme CSS e a sperimentare nuove idee di design.

Un grazie a Pearl Chen, Alan Stearns e Zoltan Horvath per aver esaminato questo articolo e fornito informazioni preziose.