Il Glassmorphism è una tendenza nel design che mira a replicare l’aspetto e le proprietà del vetro negli elementi dell’interfaccia o di un contenuto. Questo stile si caratterizza per l’uso di trasparenza, sfocatura e effetti di luce per creare l’illusione di superfici vetrose.
Diciamoci la verità: un vetro trasparente non è la cosa più pratica dove scrivere, e scrivere un tutorial evidenzia subito quanto non sia facile generalizzare un design perché sia adatto in tutti gli scenari e soprattutto a tutti gli utenti. Tuttavia, mettiamo da parte le best-practice e esploriamo diversi modi interessanti per ottenere un effetto vetro solo con CSS!
Un approccio diverso
Nella mia esperienza l’aspetto più frustrante nell’implementare un design basato sul glassmorphism è che le possibilità date dal CSS sembrano infinite e nei vari snippet che troviamo o che generano i nostri assistenti virtuali non si capisce la relazione tra proprietà CSS e effetto realistico!
Ci sono mille ricette e tutte danno effetti fantastici: ma come si arriva a quegli effetti senza procedere a caso?
Per creare un effetto vetro convincente, dobbiamo chiederci: cosa rende un vetro tale? Cosa “vende l’effetto”?
Pensiamo a questi elementi chiave:
- Trasparenza: Il vetro permette di vedere attraverso, anche se non sempre in modo completamente chiaro.
- Blur: Gli oggetti dietro il vetro appaiono sfocati, non nitidi.
- Smussatura dei bordi: I bordi del vetro spesso hanno una leggera smussatura che riflette la luce in modo particolare.
- Spessore: Il vetro ha una certa profondità, che si può percepire osservando i suoi bordi.
Il nostro approccio seguirà quindi alcune regole d’oro:
- Riflettiamo su quale proprietà vogliamo dare al nostro elemento prima di lasciarci andare con numeri a caso nelle formule
- Procediamo per “baby step”
- Organizziamo le nostre classi per rappresentare chiaramente i materiali e la loro logica
Pronti a creare la vostra collezione di materiali vetrosi?
Iniziamo con uno scenario simpatico e versatile: una web app per mostrare il meteo e l’orario, magari da installare come PWA sul vostro vecchio tablet per trasformarlo in un simpatico regalo!
Layout base: una app con orario, temperatura e meteo
Iniziamo con un layout base per la nostra app meteo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Glass Meteo and Clock</title>
<link rel="stylesheet" href="styles.css">
<link rel="manifest" href="manifest.json">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined&display=block" />
<script type="module" src="app.js"></script>
</head>
<body>
<main class="room">
<div id="dashboard" class="glass meteo-info">
<div id="time">20:30</div>
<div id="weather">
<span class="material-symbols-outlined">clear_day</span>
</div>
<div id="meteo">
<div id="temperature">35.5°C</div>
<div id="location">Rome, Italy</div>
</div>
</div>
</main>
</body>
</html>
Code language: HTML, XML (xml)
Nel nostro index.html
stiamo caricando un CSS dal Google Fonts Icons & Symbols
Nel nostro index.html stiamo caricando un CSS dal Google Fonts Icons & Symbols che ci permetterà di avere una icona per ogni condizione meteo!
Se preferite potete anche usare delle emoji 🌤️☀️🌧️
Diamo un po’ di struttura e per facilitare la nostra esplorazione con un po’ di CSS che centra le informazioni meteo nella nostra schermata:
:root {
font-family: system-ui, sans-serif;
font-size: clamp(1rem, 10vw, 5rem);
}
* {
margin: 0;
padding: 0;
line-height: 1;
}
main {
block-size: 100vh;
margin: 0;
display: flex;
justify-content: center;
align-items: center;
}
.meteo-info {
display: grid;
grid-template-columns: 1fr 2fr;
grid-template-areas: "time time" "weather meteo";
gap: 1rem;
transition: font-size 0.2s cubic-bezier(0.6, -0.28, 0.74, 0.05), opacity 0.5s linear;
}
.meteo-info>div {
display: flex;
justify-content: center;
align-items: center;
}
#time {
grid-area: time;
font-size: 200%;
font-weight: 900;
}
span.material-symbols-outlined {
font-size: inherit;
max-width: 1ch;
}
#weather {
grid-area: weather;
font-size: 120%;
}
#meteo {
grid-area: meteo;
display: flex;
flex-direction: column;
align-items: flex-start;
}
#location {
font-size: 50%;
}
Code language: CSS (css)
Tra i device che possiamo simulare in Google Chrome c’è anche un Nest Hub Max che è perfetto per il nostro esercizio!
Lo sfondo: da problema a punto di forza del nostro design!
Come possiamo apprezzare il nostro effetto vetro senza qualcosa dietro?
È evidente che non tutte le foto sono adatte a fare da sfondo e sarà necessario adattare il colore del testo perché sia visibile. Questo è il punto debole del glassmorphism che ne limita l’uso a specifici scenari. Tuttavia questo tutorial vuole proprio abbattere il taboo che se una tecnica non è universale allora non merita essere studiata!
Abbracciamo la specificità e scegliamo una bella foto in Public Domain (CC-Zero by Gray Wooden Sideboard)
Aggiungiamo quindi una classe room
al nostro main
e mettiamo un elegante bianco come colore per il nostro font (e simbolo), carichiamo il nostro sfondo e impostiamo la proprietà background-size
a cover
per fare in modo che sia ben visibile su diversi display:
main.room {
background-image: url(./backgrounds/pexels-pixabay-271816.jpg);
background-size: cover;
background-position: center;
color: white;
}
Code language: CSS (css)
Effetto Vetro Base
Se il nostro elemento di vetro fosse perfettamente liscio e trasparente la luce e quindi quello che c’è dietro si vedrebbe senza interferenza ma cosa succede se il vetro è poroso? Come possiamo renderlo con il CSS?
La base dell’effetto vetro è senza dubbio la proprietà backdrop-filter
che ci permette di usare diverse funzioni per alterare i pixel che “attraversano il nostro elemento”… proprio come i fotoni con il vetro! Quale migliore funzione se non il classico blur
per sfocare lo sfondo?
.glass {
background-color: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(0.2rem);
border-radius: 1rem;
padding: 1rem;
color: white;
}
Code language: CSS (css)
L’effetto blur è normalmente espresso in px ma in questo esercizio sfrutteremo l’unità rem per ragionare in termini di valori in proporzione tra loro piuttosto che pixel in quantità fisse.
Oltre al backdrop-filter
che definisce quanto l’immagine dietro verrà sfocata (simulando la rifrazione della luce nel vetro) possiamo giocare con il colore del vetro background-color
ed in questo caso opteremo sempre per un bianco ed usando la funzione rgba()
specificheremo un valore tra 0.0
e 1.0
dove 0.0
è totalmente trasparente e 1.0
è un materiale opaco bianco (quindi sicuramente non vetro).
Vediamo il risultato di questo effetto vetro base dove possiamo controllare la sfocatura, il colore e l’opacità! In questo screenshot vediamo blur(0.2rem)
e rgba(255, 255, 255, 0.2)
A questo livello possiamo quindi giocare con la scelta di immagini di sfondo ben selezionate, il colore del font e della base e la sfocatura del nostro vetro: complimenti avete sbloccato una nuova abilità per i vostri personali design e le vostre interfacce futuristiche!
Il bordo del vetro
Se osserviamo un vero vetro vedremo che sui bordi tende ad essere più opaco (meno trasparente) ed in alcuni casi può essere anche più luminoso: la luce dello sfondo non ci arriva diretta ma rifratta dal vetro stesso e, poiché il vetro non è mai perfettamente puro, perturbata maggiormente della superficie a noi perpendicolare.
Questa caratteristica può essere riprodotta dalla proprietà border
e controllata da spessore, colore e opacità:
.with-border {
--border-width: 0.1rem;
--border-color: 255, 255, 255;
--border-opacity: 0.1;
border: var(--border-width) solid rgba(var(--border-color), var(--border-opacity));
}
Code language: CSS (css)
Approfittiamo dell’occasione per specificare i nostri parametri come variabili in modo da poter cambiare i parametri “fisici” del vetro invece di manipolare e cambiare continuamente l’implementazione CSS. È un modo per imporsi maggiore chiarezza mentale se volete ☯️
Abbiamo ora l’abilità di rendere l’effetto del bordo e questo ci permette di fare facilmente un upgrade al nostro design specificando bordi differenti ad ogni lato ed ottenendo una direzione alla luce. Se ad esempio immaginiamo che la luce provenga da in basso a destra e si rifletta nei lati opposti del vetro potremo rendere questo effetto con 4 differenti opacitità:
.with-border-and-reflection {
--border-width: 0.1rem;
--border-color: 255, 255, 255;
--border-opacity-top: 0.7;
--border-opacity-right: 0.7;
--border-opacity-bottom: 0.3;
--border-opacity-left: 0.2;
border-top: var(--border-width) solid rgba(var(--border-color), var(--border-opacity-top));
border-right: var(--border-width) solid rgba(var(--border-color), var(--border-opacity-right));
border-bottom: var(--border-width) solid rgba(var(--border-color), var(--border-opacity-bottom));
border-left: var(--border-width) solid rgba(var(--border-color), var(--border-opacity-left));
}
Code language: CSS (css)
Ma perché fermarsi qui? E se provassimo a simulare diversi materiali giocando con altre fantastiche proprietà del CSS moderno?
Creiamo la nostra collezioni di effetti vetro!
Vetro ondulato
Per realizzare un effetto che dia l’impressione di un vetro ondulato dobbiamo ricorrere ad una proprietà potente ma non così conosciuta: background-image
viene infatti utilizzata il più delle volte con dei file grazie alla funzione url()
ma in realtà il vero potere viene dall’uso di gradienti ed in questo caso per ottenere il nostro effetto sfrutteremo proprio questa capacità di “compositing” del CSS!
Il pattern di un’onda si può ottenere in tanti modi e qui entra in gioco la vostra creatività unita alla capacità (che va allenata) di tradurre idee in codice. Un modo per farlo è con un gradiente lineare che parte da 0.0 e torna a 0.0 passando per 1.0 e -1.0… vi ricorda qualcosa?
Questa volta definiamo base, minimo e massimo nelle variabili CSS e ricordiamoci di specificare la direzione in angoli (0deg
è in verticale) e la in base a questa dobbiamo “schiacciare” il nostro background-size sull’asse corrispettivo (in questo caso la Y):
.waved {
background-image: linear-gradient(0deg, var(--base), var(--maximum), var(--base), var(--minimum), var(--base));
background-size: 100% 10%;
--base: #fff3;
--minimum: #fff0;
--maximum: #fff6;
}
Code language: CSS (css)
Vetro con pattern
Abbiamo visto come usare background-image per un effetto che si ripete in orizzontale o verticale come l’ondulato, ma cosa succede se si ripetesse in entrambe le direzioni?
.pattern-brushed {
background-image: linear-gradient(45deg, #fff0, #fff3, #fff0);
background-size: 10% 10%;
}
.pattern-grid {
background-image: linear-gradient(0deg, #fff3, #fff0 0.1rem), linear-gradient(90deg, #fff3, #fff0 0.1rem);
background-size: 5% 5%;
}
.pattern-triangles {
background-image: linear-gradient(153deg, #fff3 0.2rem, #fff0 0.1rem);
background-size: 5% 5%;
}
Code language: CSS (css)
Vetro con riflessi
Ora che abbiamo preso dimestichezza con background-image e l’uso della funzione linear-gradient possiamo sfruttarla per un ulteriore effetto!
.reflected-light {
background-image: linear-gradient(45deg, #fff0, #fff0 70%, #fff6 60%, #fff6 90%, #fff0 90%), linear-gradient(45deg, #fff0, #fff0 20%, #fff6 50%, #fff6 60%, #fff0 60%);
}
Code language: CSS (css)
Vetro colorato
Per concentrarci sugli altri parametri non abbiamo cambiato colore mai al vetro lasciando tutto basato sul bianco. Ma è evidente che con il colore possiamo davvero dare un tocco di personalità in più!
.aqua-marine {
background-image: linear-gradient(0deg, #00f7ff9e 30%, #0072ff99);
}
.color-from-half {
background-image: linear-gradient(0deg, #fff0 45%, #ff03 30%, #f009);
}
.color-points {
background-image: radial-gradient(#f096 20%, transparent 50%);
background-size: 2% 2%;
background-color: #f096;
}
Code language: CSS (css)
Effetto lente
Per ottenere un simpatico effetto lente e giocare con l’ingrandimento causato dal vetro dobbiamo ricorrere ad un piccolo stratagemma in quanto non possiamo infatti usare backdrop-filter
per la funzione blur()
: sfruttiamo uno pseudo-elemento ::before
ed ereditiamo lo sfondo del contenitore per poter poi cambiare la proprietà filter anziché backdrop-filter
!
.lens {
--zoom: 100%;
transition: background-size 1s ease-in;
background-image: inherit;
overflow: hidden;
background-size: var(--zoom);
background-attachment: fixed;
background-position: center;
}
.lens::before {
content: '';
background: inherit;
position: absolute;
inset: -0.5rem;
filter: blur(0.1rem);
z-index: -1;
background-blend-mode: overlay;
}
Code language: CSS (css)
Conclusioni
L’obiettivo di questo tutorial non era promuovere l’uso universale del glassmorphism. Ne tanto meno promuovere pratiche che possano ridurre l’accessibilità per alcuni utenti: scrivere su un vetro comporta fare i conti con tante difficoltà ma nel giusto contesto può aggiungere un tocco futuristico ai nostri design e soprattutto è estremamente divertente da implementare!
E voi cosa aspettate a creare il vostro effetto vetro e condividerlo sulla Codemotion Community su Telegram: ti aspettiamo!!! 👀