CSS Masking

HTML5 Rocks

Due operazioni spesso utilizzate nella computer grafica sono il ritaglio (clipping) e il mascheramento (masking). Entrambe nascondono porzioni visuali di un elemento. Se hai già lavorato con SVG o con i Canvas HTML prima d'ora, molto probabilmente queste pratiche non ti sono nuove. Il ritaglio stabilisce quale sia la regione visibile di un elemento. Tutto quello che si trova al di fuori questa regione non viene renderizzato - viene "ritagliato". L'operazione di mascheramento consiste nella combinazione tra una immagine, la maschera, e un contenuto, che subisce una variazione del canale alfa. Alcune parti di un elemento mascherato possono diventare parzialmente o completamente trasparenti. La nuova specifica Masking CSS mira a introdurre queste due operazioni nel mondo dell'HTML.

Il ritaglio in CSS 2.1

In CSS 2.1 era già specificata la proprietà clip. Questa è tuttavia limitata a ritagli rettangolari tramite la funzione rect(), la quale riceve in ingresso quattro argomenti per le distanze degli spigoli superiore, inferiore, destro e sinistro. La parte fastidiosa: la proprietà clip si applica solo a elementi con posizione assoluta, mentre viene ignorata per gli altri elementi.

CSS:

img {
  position: absolute;
  clip: rect(10px, 290px, 190px, 10px);
}

HTML:

<img src="image.jpg" width="568">

original unclipped image
'clip' property applied to an image

Anche per gli elementi in SVG la proprietà clip è limitata. Questo è uno dei motivi per cui la specifica SVG ha aggiunto la proprietà clip-path che attualmente è stata adattata dal CSS Masking.

La proprietà clip-path

la proprietà clip-path può essere applicata a tutti gli elementi HTML, agli elementi grafici SVG e agli elementi contenitori contenitori di SVG. Tale proprietà può fare riferimento sia all'elemento <clipPath> che ad una delle forme base introdotte con CSS Exclusions.

L'elemento <clipPath> prende qualsiasi oggetto grafico da SVG e lo utilizza come regione di ritaglio. Gli elementi grafici in SVG sono <rect>, <circle>, <ellipse>, <path>, <polygon>, <image> e <text>. <clipPath> consente inoltre di combinare più elementi grafici. In tal caso, viene utilizzata come regione di ritaglio l'unione di tutte le forme. L'esempio che segue mostra come usare <clipPath>:

CSS:

img {
  clip-path: url(#clipping);
}

HTML:

<svg>
  <defs>
    <clipPath id="clipping">
      <circle cx="284" cy="213" r="213" />
    </clipPath>
  </defs>
</svg>

<img src="image.jpg" width="568">

clip-path può essere valorizzato anche con delle forme base, che non richiedono alcun markup SVG associato. Il loro scopo all'interno di clip-path è quello di fornire delle funzioni scorciatoia per le operazioni di ritaglio basilari.

  • rectangle(<top>, <left>, <width>, <height>, <rx>, <ry>) definisce un rettangolo, in maniera simile alla funzione rect() di clip, e aggiunge due parametri opzionali per i bordi arrotondati.
  • circle(<cx>, <cy>, <r>) definisce una semplice circonferenza con un centro e un raggio.
  • ellipse(<cx>, <cy>, <rx>, <ry>) definisce un'ellisse con un centro e due raggi, uno verticale e uno orizzontale.
  • polygon(<x1> <y1>, <x2> <y2>, ..., <xn> <yn>) definisce un poligono in base alla lista di punti fornita.

Il markup del CSS ha quindi l'aspetto dell'esempio che segue:

img {
  clip-path: polygon(0px 208px, 146.5px 207px, 147px 141.2px, ...);
}

Il ritaglio può essere molto utile per la presentazione di contenuti visuali. Nell'esempio che segue sono applicati diversi ritagli ad un'immagine.

Il ritaglio può servire anche per il design di interfacce. Nell'esempio che segue una lisca di pesce indica una lista in prosecuzione.

Se si scrolla la lista si può osservare l'effetto risultante.

Si deve considerare che clip-path, così come clip, taglia fuori ogni aspetto di un elemento, compreso lo sfondo, i bordi e eventuali scrollbar.

Animazione di clip-path

Sia le forme base che il contenuto di un elemento <mask> possono essere animati. Il prossimo esempio ha un'animazione a forma di stella:

Animation of clipping

Ecco il codice sorgente per l'animazione di una forma base:

img:hover {
  clip-path: polygon(0px 208px, 146.5px 207px, 147px 141.2px, ...);
  animate: star 3s;
}

@keyframes star {
  0% {
    clip-path: polygon(0px 208px, 146.5px 207px, 147px 141.2px, ...);
  },
  100% {
    clip-path: polygon(0px 208px, 146.5px 207px, 147px 141.2px, ...);
  }
}

Mascheramento

La seconda operazione oltre al ritaglio è il mascheramento. Un'immagine maschera viene utilizzata come una sorta di "maglia colorata" per filtrare le aree visuali di un elemento. Nei paragrafi successivi spiegherò le differenze tra due tipi di maschera: la maschera di luminanza e la maschera alfa.

Maschera di Luminanza

Utilizzando le maschere di luminanza, l'immagine maschera è inizialmente trasformata in un'immagine rasterizzata in scala di grigi (se non è già in scala di grigi). Tanto più "chiara" è la porzione di un'immagine maschera, tanto più visibile sarà l'elemento mascherato in quella stessa porzione. Ad esempio, per un elemento il nero indica trasparenza completa, il bianco opacità completa e il grigio trasparenza parziale.

Maschera Alfa

Le maschere alfa usano lo stesso principio delle maschere di luminanza. Differenza rispetto al mascheramento di luminanza: qui conta solo il canale alfa dell'immagine. Tanto meno opaca è una porzione dell'immagine maschera, tanto meno visibile sarà l'elemento in quella stessa porzione.

In sintesi: entrambi i metodi di mascheramento modificano il livello di trasparenza di un elemento. L'immagine qui sotto è il risultato di entrambe le operazioni descritte sopra.

La specifica CSS per il mascheramento definisce due proprietà scorciatoie: mask e mask-box-image.

La proprietà mask

La proprietà mask combina il mascheramento di un'immagine con tutti i riferimenti alla maschera come segue.

Il primo modo è utilizzare le proprietà mask-image, mask-repeat, mask-position, mask-clip, mask-origin e mask-size, specificate in maniera simile alla loro controparte background con background-image. Così come per background-image, è possibile definire diverse sorgenti per le immagini maschera. Ogni sorgente di una maschera è un'immagine definita dalla specifica CSS3 Images. Tutte le sorgenti di maschera vengono combinate per formare una singola immagine maschera. Questa immagine viene usata per mascherare l'elemento e il suo contenuto, come descritto in precedenza. Valori possibili per le immagini sono tutti i formati immagine rasterizzati come JPG o PNG, elementi SVG o elementi predefiniti come i gradienti CSS.

Il primo esempio di mascheramento mostrato sopra può essere realizzato in maniera semplice tramite il codice che segue:

img {
  mask-image: url(mask.svg);
}

Se la sorgente della maschera dovesse essere estesa alla dimensione del suo contenuto, basta usare la proprietà scorciatoia mask, così come si farebbe per il background con la proprietà scorciatoia background:

img {
  mask: url(mask.svg) top left / cover;
}

Il secondo modo fa riferimento a un elemento <mask> come definito da SVG 1.1. Un elemento <mask> può ricevere qualsiasi elemento grafico, così come elementi SVG raggruppati, e lo utilizza per creare l'immagine maschera.

CSS:

img {
  mask: url(#masking);
}

HTML:

<svg>
  <defs>
    <linearGradient id="gradient" x1="0" y1="00%" x2 ="0" y2="100%">
      <stop stop-color="black" offset="0"/>
      <stop stop-color="white" offset="1"/>
    </linearGradient>

    <mask id="masking" maskUnits="objectBoundingBox" maskContentUnits="objectBoundingBox">
      <rect y="0.3" width="1" height=".7" fill="url(#gradient)" />
      <circle cx=".5" cy=".5" r=".35" fill="white" />
    </mask>
  </defs>
</svg>

<img src="image.jpg" width="568">

Questo avrà l'aspetto della seguente immagine:

La proprietà mask-box-image

La proprietà mask-box-image consente di dividere un'immagine maschera in 9 tasselli: quattro angoli, quattro spigoli e il tassello centrale. Questi tasselli possono essere divisi ulteriormente, scalati e ridimensionati in diversi modi per rientrare nella dimensione dell'area dell'immagine maschera. La proprietà prende in prestito questa funzionalità da border-image e consente un mascheramento notevole su spigoli e angoli del contenuto. L'esempio che segue illustra il comportamento di tale proprietà:

img {
  mask-box-image: url("stamp.svg") 35 repeat;
}

Come maschera è usata la seguente immagine, suddivisa inoltre in 9 parti:

Pattern of a stamp to be used as mask

Queste parti sono utilizzate per mascherare angoli e spigoli del contenuto, e il risultato è mostrato qui di seguito:

Image masked with mask-box-image

Supporto del browser

La tematica del supporto nei diversi browsers rappresenta sempre un aspetto di sfida. In questo caso anche il rilevamento delle funzionalità (o feature detection) può essere piuttosto confuso.

Tutti i browser supportano clip come specificato. Tutti i browser supportano le proprietà mask e clip-path come specificato in SVG 1.1 per gli elementi SVG. Comunque solo un browser consente di applicare queste proprietà agli elementi HTML: Firefox (più o meno). Vediamo qualche dettaglio.

Le proprietà clip-path e mask, con riferimento agli elementi <clipPath> e <mask> funzionano in Firefox nativamente; entrambe le proprietà sono prive di prefisso. D'altro canto, mask-image, mask-box-image e proprietà correlate non sono per niente supportate. Nemmeno le forme base per il ritaglio sono supportate.

I browser basati su WebKit, come Safari e Chrome, hanno il supporto per mask-image, mask-box-image e le proprietà correlate. Tutte queste sono con prefisso e possono essere applicate solo a elementi HTML. Le versioni nightly di entrambi i browser supportano -webkit-clip-path quando valorizzato con forme base o con un riferimento all'interno dell'HTML.

Se vuoi provare il ritaglio e il mascheramento, assicurati di usare le proprietà con prefisso e senza prefisso. Quelle senza prefisso devono essere valorizzate con un riferimento a <mask> o <clipPath>.

<style>
  #image {
    mask: url(#mask);
    -webkit-mask: url(mask.svg) top left / cover;
    -o-mask: url(mask.svg) top left / cover;
    -ms-mask: url(mask.svg) top left / cover;
  }
</style>

<img id="image" src="coolImage.jpg" width="400">

<svg width="0" height="0">
  <mask id="mask">
    ...
  </mask>
</svg>

Presta attenzione, gli altri browser non hanno ancora nessun supporto a funzionalità di mascheramento o di ritaglio quando applicate ad elementi HTML.

Riconoscimenti

Davvero molte grazie a Arno Gourdol per aver fornito l'immagine da Humayun's Tomb.

Comments

0