back to top

Trasformazioni 3D e prospettiva con CSS3

Oltre alle trasformazioni 2D, di cui ci siamo occupati nella lezione precedente, CSS3 permette di gestire spettacolari trasformazioni 3D attraverso proprietà e metodi ad hoc. I metodi per le trasformazioni 3D sono analoghi a quelli che abbiamo visto per le trasformazioni 2D ma, ovviamente, eseguono la trasformazione sulla terza dimensione.

Una semplice rotazione tridimensionale con CSS3

Per prima cosa, vorrei proporvi la rotazione tridimensionale.

CSS3 permette la rotazione su tutti e tre gli assi (X, Y e Z), grazie ai metodi rotateX, rotateY e rotateZ. Tutti questi metodi richiedono come parametro i gradi di cui si vuole effettuare la rotazione.

assi cartesiani

Applicando unicamente una di queste proprietà, tuttavia, l’effetto tridimensionale risulterà pressoche impalpabile. Per ottenere l’effetto di profondità dobbiamo applicare all’elemento contenitore una prospettiva che ci permette di "allontanarci" dall’elemento contenuto e vedere meglio la sua rotazione. Tutto questo avviene tramite la proprietà perspective.

In qualche modo possiamo dire che aumentando il valore della proprietà perspective, aumentiamo l’intensità dell’effetto 3D. Facciamo subito un esempio per rendere tutto più chiaro.

Creiamo, innanzi tutto, due div annidiati:

<div class="contenitore">
  <div class="foglio">ruotato 3D sull'asse Y</div>
</div>

Applichiamo a questi <div> le regole di stile che seguono

.prospettiva {
  width: 300px;
  height: 300px;
  border: 1px solid #000
  perspective: 500;
}
.prospettiva > div {
  width: 200px;
  height: 200px;
  margin: 50px auto;
  transform: rotateY(45deg);
  background: #FF0000;
}

La figura che segue mostra il risultato che si ottiene:

un div ruotato 3D sull'asse Y

Prova il codice

Realizziamo un cubo con CSS3

Vediamo come in pratica quello che abbiamo imparato fin qui sulle trasformazioni 3D: proveremo a realizzare un cubo.

Per prima cosa, scriviamo la porzione HTML:

<div id="contenitore">
  <div id="cubo" >
    <div class="fronte">1</div>
    <div class="retro">2</div>
    <div class="destra">3</div>
    <div class="sinistra">4</div>
    <div class="superiore">5</div>
    <div class="inferiore">6</div>
  </div>
</div>

Per prima cosa vediamo che abbiamo previsto un div contenitore (che utilizzeremo per contenere tutti gli elementi che creano il cubo); questo elemento ci serve per impostare la prospettiva e per posizionare nella pagina il nostro cubo.

Al suo interno abbiamo un div chiamato cubo che a sua volta contiene le sei facce del cubo, realizzate anche queste con dei div. Su ogni faccia scriviamo un numero in modo da riconoscerla quando andremo a visualizzare l’effetto nel browser.

Vediamo ora lo stile da applicare a ogni elemento, cominciando dal contenitore

#contenitore {
  width: 200px;
  height: 200px;
  position: relative;
  margin: 40px auto 40px;
  perspective: 1000px;
}

Il contenitore definisce la posizione del cubo e, grazie alla proprietà margin-auto, lo colloca al centro dello spazio. Il contenitore, inolre, imposta anche le dimensioni globali del cubo (200px) e le sua profondità grazie alla proprietà perspective. Se volete un cubo più profondo aumentate questo valore, altrimenti, diminuitelo.

A questo punto, possiamo passare allo stile per il div "cubo" che imposta le proprietà comuni delle sei facce del cubo:

#cubo {
  width: 100%;
  height: 100%;
  position: absolute;
  transform-style: preserve-3d;
}

Con questo codice, facciamo in modo che il cubo occupi tutto lo spazio del contenitore. Usiamo anche la proprietà transform-style: preserve-3d, in questo modo la trasformazione 3D viene applicata a tutti gli elementi contenuti in questo elemento.

E’ ora di passare alle singole facce del cubo. Cominciamo con lo stile che si applica a tutte le facce:

#cubo > div {
  position: absolute;
  width: 196px;
  height: 196px;
  border: 2px solid black;
  line-height: 196px;
  font-size: 120px;
  font-weight: bold;
  color: white;
  text-align: center;
  opacity: 0.7;
}

Con questo codice definiamo l’aspetto del testo (il numero presente in ogni faccia del cubo), quindi impostiamo un bordo per le facce e ne definiamo le dimensioni: i 196px derivano dai 200px di larghezza complessiva a cui vanno sottratti 4 px utilizzati per il bordo (due pixel per lato). si noti che per poter vedere tutte le facce, anche quelle nascoste, le rendiamo tutte un po’ trasparenti…

Ora passiamo alle singole facce, cominciando da quella frontale

#cubo .fronte {
  transform: rotateY( 0deg ) translateZ( 100px );
  background: red;
}

La faccia frontale non subisce una rotazione (rotateY(0deg)), ma viene sono portata in avanti sull’asse Z, cioè verso l’osservatore di 100 px. I 100 px non sono casuali, ma sono la metà delle dimensioni complessive del cubo. Arretrando di altro 100 px la faccia sul retro creeremo una profondità di 200px che sono esattamente quelli che occorrono alle facce superiore e inferiore per comporre il cubo dopo che le avremo ruotate.

La faccia sul retro va ruotate di 180 gradi e quindi fatta avanzare di 100px sull’asse Z. In realtà, essendo stata anche ruotata di 180 gradi, un avanzamento positivo di 100px la allontana dall’osservatore di 100px e non la avvicina come era successo per la faccia frontale.

#cubo .retro {
  transform: rotateX( 180deg ) translateZ( 100px );
  background: blue;
}

Passiamo alla faccia superiore:

#cubo .superiore {
  transform: rotateX( 90deg ) translateZ( 100px );
  background: pink;
}

La ruotiamo di 90 gradi sull’asse X in modo che si disponga perpendicolare alle facce fronte e retro. La rotazione avviene sul centro della faccia, quindi, per disporla nella parte alta del cubo, la dobbiamo traslare dei soliti 100px.

Lo stesso avviene con la faccia inferiore, solo che la rotazione sull’asse X sarà di -90 gradi.

#cubo .inferiore {
  transform: rotateX( -90deg ) translateZ( 100px );
  background: yellow;
}

Per ottenere la faccia destra del cubo, ci occorre una rotazione di 90 gradi sull’asse Y e poi il solito spostamento di 100px.

#cubo .destra {
  transform: rotateY( 90deg ) translateZ( 100px );
  background: green;
}

La faccia sinistra richiede, invece, una rotazione di -90 grati sull’asse Y.

#cubo .sinistra {
  transform: rotateY( -90deg ) translateZ( 100px );
  background: purple;
}

Questo il risultato finale:

il cubo

Il codice completo che genera il cubo è disponibile qui.

Realizziamo un parallelepipedo con CSS3

Continuiamo a mettere in pratica le trasformazioni 3D costruendo un parallelepipedo. L’operazione è simile a quella vista per il cubo, ma le sei facce non sono tutte uguali, ma hanno le stesse dimensioni a coppie:

  • fronte
  • retro
  • superiore
  • inferiore
  • destra
  • sinistra

Tutti i div che disegniamo vengono tracciati a partire dall’angolo superiore-sinistro del contenitore, dunque oltre a ruotarli e a traslarli sull’asse Y vanno anche spostati in modo da allinearli al centro orizzontale e verticale del contenitore.

Da li sarà poi possibile comporre il parallelepipedo come abbiamo fatto con il cubo.

Ad esempio per la faccia superiore è necessario uno spostamento pari all’altezza complessiva del rettangolo (cioè l’altezza della faccia frontale) meno l’altezza della faccia superiore diviso 2.

Lo stesso vale per la faccia inferiore. A causa della rotazione la spostamento deve essere comunque sempre positivo.

La struttura HTML della pagina, ovviamente, è identica a quella del cubo, abbiamo solo cambiato il nome del div cubo in parallelepipedo.

Lo stile per l’elemento contenitore è il seguente:

#contenitore {
  width: 204px;
  height: 304px;
  position: relative;
  margin: 40px auto 40px;
  perspective: 1000px;
}

Lo stile per il div parallelepipedo che contiene tutte le facce:

#parallelepipedo {
  width: 100%;
  height: 100%;
  position: absolute;
  transform-style: preserve-3d;
}

Quindi lo stile valido per tutte le sei facce:

#parallelepipedo div {
  position: absolute;
  border: 2px solid black;
  line-height: 346px;
  font-size: 120px;
  font-weight: bold;
  color: white;
  text-align: center;
  opacity: 0.7;
}

Per finire quello delle singole facce

#parallelepipedo .fronte {
  transform: rotateY( 0deg ) translateZ( 75px );
  background: red;
  width: 200px;
  height: 300px;
}
#parallelepipedo .retro {
  transform: rotateX( 180deg ) translateZ( 75px );
  background: blue;
  width: 200px;
  height: 300px;
}
#parallelepipedo .destra {
  transform: rotateY( 90deg ) translateZ( 100px );
  background: green;
  width: 150px;
  height: 300px;
  left:25px;
}
#parallelepipedo .sinistra {
  transform: rotateY( -90deg ) translateZ( 100px );
  background: purple;
  width: 150px;
  height: 300px;
  left:25px;
}
#parallelepipedo .superiore {
  transform: rotateX( 90deg ) translateZ( 150px );
  background: pink;
  width: 200px;
  height: 150px;
  top:75px;
}
#parallelepipedo .inferiore {
  transform: rotateX( -90deg ) translateZ( 150px );
  background: yellow;
  width: 200px;
  height: 150px;
  top:75px;
}

Ed ecco il parallelepipedo finito:

un parallelepipedo con CSS3

Il codice completo che genera il parallelepipedo è disponibile qui.

Modificare il punto di origine dell’effetto prospettico

Per concludere questa lezione voglio riprendere le figure che abbiamo appena realizzato per apportare una semplice modifica. Entrambe le figure, infatti, ci appaiono frontali, come se il punto di fuga della loro prospettiva si trovasse esattamente al centro della figura. Un po’ grossolanamente potremmo rappresentarlo in questo modo

il punto di fuga del parallelepipedo

Possiamo dire che questo è il punto di origine della nostra prospettiva. Così come abbiamo visto che è possibile spostare il punto di origine di una trasformazione 2D, allo stesso modo, possiamo cambiare il punto di origine della prospettiva. Questo cambiamento modifica sensibilmente il risultato delle nostre trasformazioni 3D.

La proprietà da usare in questo caso è perspective-origin. Questa proprietà richiede due valori cioè lo spostamento sull’asse X e Y.

I valori accettati sono gli stessi che abbiamo incontrato per la proprietà trasformation-origin. Questa proprietà ha effetto solo se è definito un valore per la proprietà perspective.

Proviamo allora a cambiare l’origine della prospettiva per il parallelepipedo (il resto del codice non cambia)

#contenitore {
  width: 204px;
  height: 304px;
  position: relative;
  margin: 40px auto 40px;
  perspective: 1000px;
  perspective-origin: 75% 75%;
}

La figura che otteniamo è molto diversa e la possiamo vedere qui sotto:

il nuovo punto di fuga del parallelepipedo

La griglia sovrapposta alla figura (ogni rettangolo della griglia corrisponde ad 1 centesimo della figura) ci aiuta a capire cosa è avvenuto.

Pubblicitร 
Massimiliano Bossi
Massimiliano Bossi
Stregato dalla rete sin dai tempi delle BBS e dei modem a 2.400 baud, ho avuto la fortuna di poter trasformare la mia passione in un lavoro (nonostante una Laurea in Giurisprudenza). Adoro scrivere codice e mi occupo quotidianamente di comunicazione, design e nuovi media digitali. Orgogliosamente "nerd" sono il fondatore di MRW.it (per il quale ho scritto centinaia di articoli) e di una nota Web-Agency (dove seguo in prima persona progetti digitali per numerosi clienti sia in Italia che all'estero).