Guida introduttiva alle forme CSS

Aggregazione di contenuti intorno a percorsi personalizzati

Razvan Caliman
Razvan Caliman

Per molto tempo i web designer sono stati costretti a creare contenuti all'interno dei vincoli del rettangolo. La maggior parte dei contenuti sul web è ancora intrappolata in semplici caselle, perché la maggior parte dei creativi si avventura in un layout non rettangolare finisce con la 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 aggregare i contenuti intorno a percorsi personalizzati, come cerchi, ellissi e poligoni, liberandosi 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 quando hai sospeso per la prima volta un'immagine con parti trasparenti aspettandoti che i contenuti si riempissero e riempissero gli spazi, solo per rimanere delusi dalla forma rettangolare a capo che persiste intorno all'elemento. Le forme CSS possono essere utilizzate per risolvere questo problema.

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 minimo di opacità dei pixel che verranno utilizzati per creare la forma. Il suo 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% e superiore.

La proprietà float è fondamentale qui. Anche se la proprietà shape-outside definisce la forma dell'area attorno alla quale verrà eseguito il wrapping dei contenuti, senza il floating non vedrai gli effetti della forma.

Gli elementi hanno un'area mobile sul lato opposto del valore float. Ad esempio, se un elemento con l'immagine di una tazza di caffè viene fatto scorrere verso sinistra, l'area mobile viene creata a destra della tazza. Anche se puoi progettare un'immagine con intervalli vuoti su entrambi i lati, i contenuti verranno a capo solo intorno alla forma sul lato opposto indicato dalla proprietà floating, a sinistra o a destra, mai entrambi.

In futuro, sarà possibile utilizzare shape-outside su elementi che non vengono visualizzati in formato 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 casella di riferimento che stabilisce il sistema di coordinate. A breve potrai saperne di più sulle caselle di riferimento.

La funzione cerchia()

Illustrazione del valore della forma cerchia()

La notazione completa per un valore di 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 per il centro del cerchio sono facoltative. Se ometti queste parole, per impostazione predefinita viene utilizzato il centro dell'elemento (l'intersezione delle diagonali).

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

Nell'esempio precedente, i contenuti verranno visualizzati all'esterno di un percorso circolare. L'argomento singolo 50% specifica il raggio del cerchio che, in questo caso specifico, equivale alla metà della larghezza o dell'altezza dell'elemento. La modifica delle dimensioni dell'elemento influirà sul raggio della forma del cerchio. Questo è un esempio base di come le forme CSS possono essere adattabili.

Prima di andare avanti, una breve nota: è importante ricordare che le forme CSS influenzano solo la forma dell'area mobile intorno a un elemento. Se l'elemento ha uno sfondo, non verrà tagliato 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()&quot; + clip-path

Le illustrazioni di questo documento usano i ritagli per evidenziare la forma e aiutarti a comprendere gli effetti.

Torna alla forma del cerchio.

Quando utilizzi le percentuali per il raggio del cerchio, il valore viene effettivamente calcolato con una formula leggermente più complessa: mq(larghezza^2 + altezza^2) / quadrato(2). È utile comprenderlo perché ti aiuterà a immaginare come 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 delle funzioni di forma: px, em, rem, vw, vh e così via. Puoi scegliere quello più flessibile o abbastanza rigido per soddisfare 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 posiziona il cerchio all'origine del sistema di coordinate. Qual è il sistema di coordinate? È qui che introduciamo 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 tracciare e posizionare la forma. L'origine del sistema di coordinate si trova nell'angolo superiore sinistro con l'asse X rivolto a destra e l'asse Y verso il basso.

Sistema di coordinate per le forme CSS

Ricorda che shape-outside modifica la forma dell'area mobile intorno a cui verranno visualizzati i contenuti. L'area mobile si estende fino ai bordi esterni della casella definiti dalla proprietà margin. È denominato margin-box ed è la casella di riferimento predefinita per una forma se nessuna è menzionata 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 sull'elemento. A questo punto è possibile 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 valore 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 al di fuori dell'area di contenuto dell'elemento (100 px in alto e 100 px a sinistra), così come il centro del cerchio. Il valore calcolato del raggio del cerchio cresce anche per tenere conto della maggiore superficie del sistema di coordinate stabilite dalla casella di riferimento margin-box.

Sistema di coordinate della casella del margine con e senza margine
Puoi scegliere tra alcune opzioni di casella di riferimento: "margin-box", "Border-box", "padding-box" e "content-box". I nomi ne implicano i limiti. Abbiamo spiegato in precedenza il cosiddetto "margin-box". Il campo "Border-box" è vincolato dai bordi esterni dei bordi dell'elemento, la "padding-box" è vincolato dalla spaziatura interna dell'elemento, mentre "content-box" è identico all'area della superficie effettiva utilizzata dal contenuto 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 influirà sulla forma in modo diverso e a volte sottile. C'è un altro articolo che approfondisce 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 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 per il 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. Qui non servono calcoli divertenti. Puoi omettere le coordinate per il centro dell'ellisse e 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 uguale alla distanza tra il centro dell'ellisse e il lato della casella di riferimento più lontana dall'asse, mentre closest-side indica l'esatto opposto: 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;
}

Ciò può risultare utile quando le dimensioni dell'elemento (o la casella di riferimento) possono cambiare in modi imprevedibili, ma vuoi adattare la forma dell'ellisse.

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

La funzione poligoni()

Illustrazione del valore di forma skyscraper()

Se cerchi ed ellissi sono troppo limitati, la funzione di forma poligonale apre una serie di opzioni. Il formato è polygon(x1 y1, x2 y2, ...), dove specifichi 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 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;
}

È presente un parametro fill-rule facoltativo, importato da SVG, che indica al browser come considerare l'"interno" di un poligono in caso di percorsi che si intersecano o forme racchiuse. Joni Provathall spiega molto bene come funziona la proprietà della regola di riempimento in SVG. Se non viene 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 intorno alle quali aggregare i contenuti. Questo potrebbe sembrare controintuitivo se si considera la premessa iniziale secondo cui CSS Shapes libera contenuti web da semplici caselle. Potrebbe benissimo esserlo. Devo ancora trovare un caso d'uso per inset() che non sia già possibile con valori in virgola mobile e margini o con un polygon(). inset() fornisce un'espressione più leggibile per le forme rettangolari rispetto a polygon().

La notazione completa per una funzione di forma inserita è inset(top right bottom left border-radius). I primi quattro argomenti della posizione sono offset verso l'interno dai bordi dell'elemento. L'ultimo argomento è il raggio del bordo per la forma rettangolare. È facoltativa, quindi puoi lasciarla vuota. È seguita dalla notazione breve 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 dalle 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. Niente di esotico finora, è così che i galleggianti funzionano già. 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, ottieni l'effetto di ritaglio, ma l'area mobile rimane rettangolare. Aggiungi shape-outside: border-box per disporre il contorno creato da border-radius.

Estrazione di una forma dal raggio del bordo di un elemento utilizzando la casella di riferimento della casella di riferimento dei bordi
.element{
  border-radius: 50%;
  shape-outside: border-box;
  float: left;
}

Naturalmente, puoi utilizzare tutte le caselle di riferimento in questo modo. Ecco un altro impiego delle forme derivate: le virgolette inclinate su offset.

Creazione di una citazione in modalità pull utilizzando la casella di riferimento della casella di riferimento

È possibile ottenere l'effetto pull-quote di offset utilizzando solo le proprietà float e margine. Tuttavia, è necessario posizionare le virgolette nella struttura ad albero HTML nel punto in cui si vuole che venga visualizzato.

Ecco come ottenere lo stesso effetto di offset tra virgolette 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 nelle virgolette in modalità pull definisce la forma attorno alla quale verrà eseguito il wrapping dei contenuti esterni. La proprietà margin-top viene utilizzata qui per posizionare (offset) il virgolette indipendentemente dalla sua posizione nell'albero HTML.

Margine forma

Noterai che l'avvolgimento dei contenuti intorno a una forma può far sì che quest'ultima aderisca troppo all'elemento. Puoi aggiungere spazi intorno alla forma con la proprietà shape-margin.

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

L'effetto è simile a quello che solitamente viene utilizzato nella proprietà margin standard, ma shape-margin influisce solo sullo spazio intorno al valore shape-outside. Verrà aggiunto uno spazio intorno alla forma solo se c'è spazio nel sistema di coordinate. Ecco perché nell'esempio sopra il raggio del cerchio è impostato sul 40% e non sul 50%. Se il raggio fosse stato impostato al 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 è vincolata al valore margin-box dell'elemento (l'elemento più margin circostante). Se la forma è più grande e traboccanti, verrà agganciata a margin-box e il risultato sarà una forma rettangolare.

È importante capire che shape-margin accetta solo un singolo valore positivo. Non ha una notazione a mano lunga. In ogni caso, cos'è un margine di forma in alto per un cerchio?

Animazione delle forme

Puoi combinare le forme CSS con molte altre funzionalità CSS, ad esempio 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 scegli di utilizzare forme animata.

Puoi animare i raggi e i centri di forme circle() e ellipse(), purché siano definiti in valori che il browser può interpolare. È possibile passare da circle(30%) a circle(50%). Tuttavia, l'impostazione di un'animazione tra circle(closest-side) e circle(farthest-side) strozza il browser.

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

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

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

Un trucco è aggiungere il numero massimo di vertici di cui hai bisogno e posizionarli raggruppati nello stato di animazione, dove 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 del triangolo animato

Aggregazione di contenuti all'interno di una forma

Screenshot della demo di Alice nel Paese delle Meraviglie che utilizza le forme CSS per aggregare i contenuti

La bozza iniziale della specifica per le forme CSS includeva una proprietà shape-inside che consentiva di aggregare i contenuti all'interno di una forma. Per un certo periodo ci sono state anche implementazioni in Chrome e Webkit. Tuttavia, l'aggregazione di contenuti posizionati in modo arbitrario all'interno di un percorso personalizzato richiede molto più impegno e ricerche per coprire tutti gli scenari possibili ed evitare bug. Ecco perché la proprietà shape-inside è stata differita al livello 2 delle forme CSS e le relative implementazioni sono state ritirate.

Tuttavia, con un po' di impegno e un po' di compromesso, puoi comunque ottenere l'effetto di disporre i contenuti all'interno di una forma personalizzata. Questo tipo di trucco prevede l'utilizzo di due elementi mobili con shape-outside, posizionati ai lati opposti di un container. Il compromesso è che devi usare uno o due elementi vuoti che non hanno un significato semantico, ma che fungono da puntine 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 montanti .left-shape e .right-shape nella parte superiore del container è importante perché verranno fatti scorrere verso sinistra e verso 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 montanti fluttuanti occupino tutto lo spazio all'interno dell'elemento, ma le proprietà shape-outside occupano spazio per il resto dei contenuti.

Se le forme CSS non sono supportate dal browser, otterrai brutti effetti quando verranno spinti verso il basso tutti i contenuti. Ecco perché è importante utilizzare questa funzionalità in modo progressivo.

Nei precedenti esempi di animazione forma, noterai che lo spostamento del testo può essere fastidioso. Non tutti i casi d'uso garantiscono una forma animata. Puoi però animare altre proprietà che interagiscono con le forme CSS per aggiungere un effetto pertinente.

Nella dimostrazione di Alice nel Paese delle Meraviglie delle forme CSS, abbiamo utilizzato la posizione di scorrimento per modificare il margine superiore dei contenuti. Il testo viene compresso tra due elementi fluttuanti. Quando si sposta verso il basso, deve essere ridimensionato in base al shape-outside dei due elementi mobili. Questo dà l'impressione che il testo scenda nella tana del coniglio e si aggiunge all'esperienza di storytelling. Uno sguardo ingiustificato? Forse. Ma ha un aspetto interessante.

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 del margine superiore dello scorrimento attiva molti eventi di relayout e colorazione, il che potrebbe ridurre notevolmente le prestazioni. Da usare con cautela. Tuttavia, l'utilizzo di forme CSS senza animarle non genera un hit di rendimento percepibile.

Miglioramento progressivo

Inizia supponendo che il browser non supporti le forme CSS, e inizia a utilizzarlo quando rilevi questa funzionalità. Modernizr è una buona soluzione per il rilevamento delle funzionalità ed è disponibile un test per le forme CSS nella sezione "Rilevazioni non principali".

Alcuni browser forniscono il rilevamento delle funzionalità in CSS tramite la regola @supports, senza bisogno di librerie esterne. Google Chrome, che supporta anche le forme CSS, comprende la regola @supports. Ecco come lo utilizzi 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 ulteriori informazioni su come utilizzare la regola CSS @supports.

Disambiguazione dalle esclusioni CSS

Quello che oggi conosciamo come forme CSS in passato si chiamava Forme e esclusioni CSS agli inizi delle specifiche. Il passaggio nella denominazione potrebbe sembrare una sfumatura, ma in realtà è molto importante. Le esclusioni CSS, che ora sono una specifica separata, consentono di eseguire il wrapping dei contenuti intorno a elementi posizionati in modo arbitrario, senza bisogno di una proprietà float. Immagina di includere contenuti intorno a un elemento in posizione assoluta: si tratta di un caso d'uso per le esclusioni CSS. Le forme CSS definiscono semplicemente il percorso intorno al quale verranno aggregati i contenuti.

Quindi, forme ed esclusioni non sono la stessa cosa, ma sono complementari. Le forme CSS sono attualmente 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 nei classici strumenti di creazione di immagini, ma nessuno di questi, al momento della stesura di questo articolo, esporta la sintassi richiesta per i valori delle forme CSS. Anche se lo fosse, lavorare in questo modo non sarebbe molto pratico.

Le forme CSS sono destinate a essere utilizzate nel browser, dove reagiscono ad altri elementi sulla pagina. È molto utile visualizzare gli effetti dell'editing della forma sui contenuti che lo circondano. Esistono alcuni strumenti utili per questo flusso di lavoro:

Parentesi: l'estensione CSS Shapes Editor per le parentesi quadre 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 CSS Shapes Editor per Google Chrome estende gli strumenti per sviluppatori del browser con controlli per creare e modificare forme. Posiziona un editor interattivo sopra l'elemento selezionato.

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

Forme dalle immagini: se preferisci generare immagini da cui il browser estrae le forme, Rebecca Hauck ha realizzato un buon tutorial per Photoshop.

Polyfill: Google Chrome è il primo browser principale a distribuire forme CSS. Presto sarà disponibile il supporto per questa funzionalità su Apple iOS 8 e Safari 8. Altri fornitori di browser potrebbero prenderlo in considerazione in futuro. Fino ad allora, sarà disponibile un polyfill delle forme CSS per fornire l'assistenza di base.

Conclusione

In un web dove i contenuti sono per lo più intrappolati in semplici scatole, CSS Shapes offre un modo per creare un layout espressivo, colmando il divario di fedeltà tra il web design e quello di stampa. Naturalmente, è possibile abusare delle forme e creare distrazioni. Tuttavia, se applicate con gusto e buon senso, le forme possono migliorare la presentazione dei contenuti e concentrare l'attenzione degli utenti in un modo unico per loro.

Ti lascio una raccolta di lavori di altri, principalmente provenienti dalla versione cartacea, che dimostra utilizzi interessanti per il layout non rettangolare. Mi auguro che queste informazioni ti siano di ispirazione per provare le forme CSS e sperimentare nuove idee di design.

Grazie mille a Pearl Chen, Alan Stearns e Zoltan Horvath per aver letto questo articolo e per averci fornito informazioni preziose.