Pubblicato il 16/08/2015
Son sicuro che molti di voi, soprattutto quelli con qualche anno in più, conoscano Casablanca Casablanca. Per chi invece non sa di cosa stiamo parlando, qui trovate la scena clou, oggetto dell'articolo di oggi: un colpo indiretto di 8 sponde per chiudere in gloria il torneo.
Bene, oggi, quel colpo, lo riprodurremo con i soli CSS, senza l'uso di immagini, video né tantomeno di javascript.
Partiamo?
Il tavolo
Costruiremo un tavolo, per questo esempio, di una dimensione inferiore ai 360 pixel per rendere l'articolo fruibile ai più. Ovviamente nessuno ci vieta di costruirlo con dimensioni maggiori.
Rispetto al film originale, per una maggiore semplicità, visto lo scopo dell'articolo, creeremo un tavolo senza buche, con panno verde e sponde in legno.
codice HTML tavolo
codice CSS tavolo
#biliardo {
width:310px;
height:160px;
padding:10px;
background:#009727;
border:15px solid #9B3107;
}
Come vedete è un biliardo un po' grezzo, al quale applicheremo le sponde respingenti e a cui aggiungeremo un po' di tridimensionalità con le ombre css
codice HTML tavolo + panno
codice CSS panno del biliardo
#panno {
width:310px;
height:160px;
background:#01b12f;
position:relative;
box-shadow:0 0 10px #333 inset;
}
Come abbiamo ottenuto ciò?
La sponda in legno arriva dal bordo, spesso 15 pixel, la sponda respingente dal padding di #biliardo, di 10 pixel, e l'effetto profondità dall'ombra di 10pixel, centrata e interna. Cosa manca? Ah, sì i birilli al centro...
Ne inseriremo, per semplicità, solo 5 del gioco all'italiana invece dei 9 della goriziana del film. Li definiremo con una classe birillo comune e assegneremo a ognuno di loro un id diverso. Ogni birillo sarà semplicemente un blocco di 2px*2px, arrotondato, di colore blu, a parte quello centrale, e con una piccola ombra dovuta alle luci al neon.
codice HTML tavolo completo di birilli
codice CSS dei birilli
.birillo {
width:2px;
height:2px;
border-radius:2px;
position:absolute;
box-shadow:1px 2px 3px #333;
z-index:10;
background:blue;
}
#birillo1 {
background:red;
top:80px;
left:155px;
}
#birillo2 {
top:70px;
left:155px;
}
#birillo3 {
top:90px;
left:155px;
}
#birillo4 {
top:80px;
left:145px;
}
#birillo5 {
top:80px;
left:165px;
}
Et voilà! Il biliardo è completo. Spero non ci nulla di strano e/o di poco chiaro finora, perché passeremo alle
Palle da biliardo
Qui il discorso è molto più semplice: per creare una palla da biliardo ci basta fare:
- Un blocco quadrato
- al quale applicheremo un border-radius pari al lato in modo da arrotondarli
- e un po' d'ombra che lasci la parte centrale piena e quelle esterne in ombra, in modo da simulare le luci dei neon.
Le faremo in proporzione di 10 pixel di diametro.. per capire come farle in questo punto le faremo più grandi (100 pixel) per poi riadattare la dimensione sul tavolo successivamente
codice HTML palla da biliardo
codice CSS della palla da biliardo
.palla {
width:100px;
height:100px;
border-radius:100px;
box-shadow:0 0 30px #333 inset;
background:red;
}
Posizioni delle palle sul biliardo e traiettorie
Passiamo alla parte più complicata del tutorial. Guardiamo un'immagine con la posizione iniziale del tiro
e una in cui abbiamo disegnato le traiettorie della palla rossa
il problema sorge nel calcolare i punti di contatto sulle sponde, le coordinate (iniziali e finali) delle palle e la lunghezza delle traiettorie.
Ci sono varie possibilità per ottenere tali valori, da quelli un po' più empirici (ad esempio utilizzando le griglie e il righello di Photoshop), a metodi più analitici (carta e penna e basi di trigonometria) o usando programmi ad hoc (Matlab o Octave, alternativa open source). Inutile dire che quest'ultima è la soluzione ideale, a costo di considerare la complessità d'uso del software.
Il risultato dei calcoli è quello espresso nell'immagine, con in nero i punti di contatto delle traiettorie sulle sponde, in rosso le lunghezze delle traiettorie e in rosso quelle iniziali delle palle:
Come utilizzare questi dati?
Iniziamo con le posizioni iniziali delle palle: useremo tali dati, e in particolare quelli in blu, per posizionarle sul tappeto, assegnandole ai valori top e left
codice HTML finale
codice CSS con le posizioni iniziali
.palla {
width:10px;
height:10px;
border-radius:10px;
position:absolute;
z-index:20;
box-shadow:0 0 3px #333 inset;
}
#pallaRossa {
background:red;
left:154px;
top:150px;
}
#pallaGialla {
background:yellow;
left:144px;
top:88px;
}
#pallaBianca {
background:white;
left:146px;
top:100px;
}
L'animazione
Ci manca ora solo una cosa: animare i vari elementi e in particolare:
- la palla rossa che farà le 8 sponde
- la palla gialla che abbatterà i birillo centrale e si fermerà subito dopo
- il birillo che verrà abbattuto
Palla rossa
Indubbiamente il movimento più complesso è quello della palla rossa, che dovrà girare sul tavolo fino ad arrivare sulla gialla e fermarsi. Per far ciò utilizzeremo le lunghezze (in rosso sull'immagine di prima) e i punti di contatto con le sponde (in nero.)
Che logica utilizzeremo?
Con due basi di fisica sappiamo che, a velocità costante (cosa che supporremmo per non appesantire ulteriormente la trattazione), spazi e tempi sono direttamente proporzionali.. in pratica quindi possiamo usare le lunghezze (lo spazio) per ottenere il tempo. Come fare allora?
Calcoliamo la distanza totale delle lunghezze (1350 pixel). Se vogliamo ottenere un'animazione che entri nel 100% del valore utilizzabile in @keyframes, potremmo dividere per 13.5 (1350/100). Dato che vogliamo lasciare del tempo per fare anche le altre animazioni (palla gialla e birillo), dividiamo le lunghezze per 20 e otterremo i seguenti valori:
codice CSS: animazione palla rossa
@keyframes pallaRossa {
0% {left:154px; top:150px;}
8.65% {left:305px; top:64px;}
15.2% {left:188px; top:5px;}
25.7% {left:5px; top:109px;}
30.8% {left:95px; top:155px;}
42.85% {left:305px; top:36px;}
46.25% {left:244px; top:5px;}
60.05% {left:5px; top:141px;}
61.55% {left:33px; top:155px;}
68.25% {left:144px; top:88px;}
100% {left:144px; top:88px;}
}
Se avete seguito ogni valore rappresenta la lunghezza percorsa dalla palla rossa fino a ogni sponda, diviso per 20, a cui abbiamo assegnato il valore di contatto sulla sponda. La palla rossa si ferma al 68.25% dell'animazione. Aggiungiamo il valore 100% per far sì che da quel momento, fino alla fine, resti allo stesso punto in cui è arrivata
La palla gialla
Qui il discorso è molto più semplice: dobbiamo aspettare che la rossa faccia il suo giro. Partirà un attimo prima del suo arrivo, intorno al 68% dell'animazione e si fermerà al 75% nella nuova posizione, dove resterà fino alla fine
codice CSS: animazione palla gialla
@keyframes pallaGialla {
0% {left:144px; top:88px;}
68% {left:144px; top:88px;}
75% {left:162px; top:70px;}
100% {left:162px; top:70px;}
}
Il birillo centrale
Qui utilizzeremo un'animazione semplicissima: al passaggio della palla gialla, intorno al 70% il birillo assumerà sfondo trasparente, "sparendo" dal tavolo
codice CSS: animazione birillo
@keyframes birillo1 {
0% {background:red;}
70% {background:red;}
71% {background:none;}
100% {background:none;}
}
Abbiamo proprio tutte le informazioni per terminare il tutorial. Ci basta assegnare i vari @keyframes, gestire le regole animation (per maggiori informazioni potete consultare questo articolo sulle animazioni) e otterremo l'ottavina reale!
Conclusione:
codice HTML
codice CSS
#biliardo {padding:10px; background:#009727; width:310px; height:160px; border:15px solid #9B3107;}
#panno {width:310px; height:160px; background:#01b12f; position:relative; box-shadow:0 0 10px #333 inset;}
.birillo {width:2px; height:2px; border-radius:2px; position:absolute; box-shadow:1px 2px 3px #333; z-index:10;}
@keyframes birillo1 {
0% {background:red;}
70% {background:red;}
71% {background:none;}
100% {background:none;}
}
#birillo1 {background:red; top:80px; left:155px; animation-name:birillo1; animation-duration:10s; animation-delay:0; animation-iteration-count:infinite;}
#birillo2 {background:blue; top:70px; left:155px;}
#birillo3 {background:blue; top:90px; left:155px;}
#birillo4 {background:blue; top:80px; left:145px;}
#birillo5 {background:blue; top:80px; left:165px;}
.palla {width:10px; height:10px; border-radius:10px; position:absolute; z-index:20; box-shadow:0 0 3px #333 inset;}
@keyframes pallaRossa {
0% {left:154px; top:150px;}
8.65% {left:305px; top:64px;}
15.2% {left:188px; top:5px;}
25.7% {left:5px; top:109px;}
30.8% {left:95px; top:155px;}
42.85% {left:305px; top:36px;}
46.25% {left:244px; top:5px;}
60.05% {left:5px; top:141px;}
61.55% {left:33px; top:155px;}
68.25% {left:144px; top:88px;}
100% {left:144px; top:88px;}
}
#pallaRossa {background:red; left:154px; top:150px; animation-name:pallaRossa; animation-duration:10s; animation-delay:0; animation-timing-function:linear; animation-iteration-count:infinite;}
@keyframes pallaGialla {
0% {left:144px; top:88px;}
68% {left:144px; top:88px;}
75% {left:162px; top:70px;}
100% {left:162px; top:70px;}
}
#pallaGialla {background:yellow; left:144px; top:88px; animation-name:pallaGialla; animation-duration:10s; animation-delay:0; animation-timing-function:cubic-bezier(0,0.5,1,1); animation-iteration-count:infinite;}
#pallaBianca {background:white; left:146px; top:100px;}