El glassmorphism es una tendencia en el diseño que busca replicar el aspecto y las propiedades del vidrio en los elementos de la interfaz o de un contenido. Este estilo se caracteriza por el uso de transparencia, desenfoque y efectos de luz para crear la ilusión de superficies de vidrio.
Seamos sinceros: un vidrio transparente no es el lugar más práctico para escribir, y al elaborar un tutorial se hace evidente lo difícil que es generalizar un diseño para que funcione en todos los escenarios y, sobre todo, para todos los usuarios. Sin embargo, dejemos de lado las buenas prácticas y exploremos diversas maneras interesantes de lograr un efecto de vidrio solo con CSS.
Un approccio diverso
En mi experiencia, el aspecto más frustrante de implementar un diseño basado en el glassmorphism es que las posibilidades que ofrece CSS parecen infinitas, y en los distintos fragmentos de código que encontramos o que generan nuestros asistentes virtuales, no se entiende la relación entre las propiedades de CSS y el efecto realista.
Hay mil recetas y todas logran efectos increíbles, pero ¿cómo se alcanzan esos efectos sin ir a ciegas?
Para crear un efecto de vidrio convincente, debemos preguntarnos: ¿qué hace que algo parezca vidrio? ¿Qué “vende el efecto”?
Pensemos en estos elementos clave:
- Transparencia: El vidrio permite ver a través de él, aunque no siempre de manera completamente clara.
- Desenfoque (Blur): Los objetos detrás del vidrio se ven borrosos, no nítidos.
- Bordes redondeados: Los bordes del vidrio suelen tener una ligera redondez que refleja la luz de forma particular.
- Espesor: El vidrio tiene cierta profundidad, visible en sus bordes.
Nuestro enfoque seguirá algunas reglas de oro:
- Reflexionemos sobre la propiedad que queremos dar a nuestro elemento antes de aventurarnos con números al azar en las fórmulas.
- Avancemos con “pasos de bebé”.
- Organicemos nuestras clases para representar claramente los materiales y su lógica.
¿Listos para crear su propia colección de materiales de vidrio?
Empecemos con un escenario divertido y versátil: una aplicación web para mostrar el clima y la hora, quizás para instalar como PWA en tu vieja tablet y transformarla en un regalo original.
Diseño básico: una app con hora, temperatura y clima.
Comencemos con un diseño básico para nuestra app de clima:
<code><!DOCTYPE <strong>html</strong>>
<<strong>html</strong> lang="en">
<<strong>head</strong>>
<<strong>meta</strong> charset="UTF-8">
<<strong>meta</strong> name="viewport" content="width=device-width, initial-scale=1.0">
<<strong>title</strong>>Glass Meteo and Clock</<strong>title</strong>>
<<strong>link</strong> rel="stylesheet" href="styles.css">
<<strong>link</strong> rel="manifest" href="manifest.json">
<<strong>meta</strong> name="theme-color" content="#ffffff">
<mark> <<strong>link</strong> rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined&display=block" />
</mark> <<strong>script</strong> type="module" src="app.js"></<strong>script</strong>>
</<strong>head</strong>>
<<strong>body</strong>>
<<strong>main</strong> class="room">
<<strong>div</strong> id="dashboard" class="glass meteo-info">
<<strong>div</strong> id="time">20:30</<strong>div</strong>>
<<strong>div</strong> id="weather">
<mark> <<strong>span</strong> class="material-symbols-outlined">clear_day</<strong>span</strong>>
</mark> </<strong>div</strong>>
<<strong>div</strong> id="meteo">
<<strong>div</strong> id="temperature">35.5°C</<strong>div</strong>>
<<strong>div</strong> id="location">Rome, Italy</<strong>div</strong>>
</<strong>div</strong>>
</<strong>div</strong>>
</<strong>main</strong>>
</<strong>body</strong>>
</<strong>html</strong>>
</code>
En nuestro index.html
, estamos cargando un CSS de Google Fonts Icons & Symbols.
En nuestro index.html
, estamos cargando un CSS de Google Fonts Icons & Symbols que nos permitirá tener un ícono para cada condición meteorológica.
Si prefieres, también puedes usar emojis 🌤️☀️🌧️.
Demos algo de estructura y facilitemos nuestra exploración con un poco de CSS que centre la información del clima en nuestra pantalla.
<code>:root {
<strong>font-family</strong>: system-ui, sans-serif;
<strong>font-size</strong>: clamp(1rem, 10vw, 5rem);
}
* {
<strong>margin</strong>: 0;
<strong>padding</strong>: 0;
<strong>line-height</strong>: 1;
}
<strong>main</strong> {
<strong>block-size</strong>: 100vh;
<strong>margin</strong>: 0;
<strong>display</strong>: flex;
<strong>justify-content</strong>: center;
<strong>align-items</strong>: center;
}
.meteo-info {
<strong>display</strong>: grid;
<strong>grid-template-columns</strong>: 1fr 2fr;
<strong>grid-template-areas</strong>: "time time" "weather meteo";
<strong>gap</strong>: 1rem;
<strong>transition</strong>: font-size 0.2s cubic-bezier(0.6, -0.28, 0.74, 0.05), opacity 0.5s linear;
}
.meteo-info><strong>div</strong> {
<strong>display</strong>: flex;
<strong>justify-content</strong>: center;
<strong>align-items</strong>: center;
}
#time {
<strong>grid-area</strong>: time;
<strong>font-size</strong>: 200%;
<strong>font-weight</strong>: 900;
}
<strong>span</strong>.material-symbols-outlined {
<strong>font-size</strong>: inherit;
<strong>max-width</strong>: 1ch;
}
#weather {
<strong>grid-area</strong>: weather;
<strong>font-size</strong>: 120%;
}
#meteo {
<strong>grid-area</strong>: meteo;
<strong>display</strong>: flex;
<strong>flex-direction</strong>: column;
<strong>align-items</strong>: flex-start;
}
#location {
<strong>font-size</strong>: 50%;
}</code>
Lenguaje del código: HTML, XML (xml)
Entre los dispositivos que podemos simular en Google Chrome también está el Nest Hub Max, ¡que es perfecto para nuestro ejercicio!
El fondo: ¡de problema a punto fuerte de nuestro diseño!
¿Cómo podemos apreciar nuestro efecto de vidrio sin algo detrás?
Es evidente que no todas las fotos son adecuadas como fondo y será necesario ajustar el color del texto para que sea visible. Este es el punto débil del glassmorphism, que limita su uso a escenarios específicos. Sin embargo, ¡este tutorial busca romper el tabú de que, si una técnica no es universal, entonces no merece ser estudiada!
Abracemos la especificidad y elijamos una buena foto en dominio público (CC-Zero by Gray Wooden Sideboard).
Agreguemos una clase room
a nuestro main
y pongamos un elegante blanco como color para nuestra fuente (y símbolo), carguemos nuestro fondo y configuremos la propiedad background-size
en cover
para asegurarnos de que sea bien visible en diferentes pantallas:
<code><strong>main</strong>.room {
<mark> <strong>background-image</strong>: url(./backgrounds/pexels-pixabay-271816.jpg);
</mark> <strong>background-size</strong>: cover;
<strong>background-position</strong>: center;
<strong>color</strong>: white;
}
</code>
Lenguaje del código: HTML, XML (xml)
Efecto vidrio base
Si nuestro elemento de vidrio fuera perfectamente liso y transparente, la luz y, por tanto, lo que hay detrás se vería sin interferencia. Pero, ¿qué ocurre si el vidrio es poroso? ¿Cómo podemos lograr ese efecto con CSS?
La base del efecto vidrio es, sin duda, la propiedad backdrop-filter
, que nos permite usar diversas funciones para alterar los píxeles que “atraviesan” nuestro elemento… ¡justo como lo hacen los fotones al pasar por el vidrio! ¿Y qué mejor función que el clásico blur
para desenfocar el fondo?
<code>.glass {
<strong>background-color</strong>: rgba(255, 255, 255, 0.2);
<strong>backdrop-filter</strong>: blur(0.2rem);
<strong>border-radius</strong>: 1rem;
<strong>padding</strong>: 1rem;
<strong>color</strong>: white;
}</code>
Lenguaje del código: HTML, XML (xml)
El efecto de desenfoque suele expresarse en píxeles (px
), pero en este ejercicio utilizaremos la unidad rem
para pensar en términos de valores proporcionales en lugar de cantidades fijas de píxeles.
Además del backdrop-filter
, que define cuánto se desenfocará la imagen de fondo (simulando la refracción de la luz en el vidrio), podemos jugar con el color del vidrio mediante background-color
. En este caso, optaremos siempre por un blanco y, usando la función rgba()
, especificaremos un valor entre 0.0
y 1.0
, donde 0.0
es totalmente transparente y 1.0
es un material opaco blanco (lo cual, desde luego, no sería vidrio).
Veamos el resultado de este efecto de vidrio básico, donde podemos controlar el desenfoque, el color y la opacidad. En este ejemplo, se ha aplicado blur(0.2rem)
y rgba(255, 255, 255, 0.2)
.
A este nivel, podemos experimentar con la elección de imágenes de fondo bien seleccionadas, el color de la tipografía y la base, además del desenfoque del vidrio. ¡Felicidades! Habéis desbloqueado una nueva habilidad para sus diseños personales y sus interfaces futuristas.
El borde del vidrio
Si observamos un vidrio real, veremos que en los bordes tiende a ser más opaco (menos transparente) y, en algunos casos, puede ser incluso más luminoso. Esto se debe a que la luz de fondo no llega directamente, sino que es refractada por el propio vidrio y, dado que el vidrio nunca es perfectamente puro, sufre más perturbaciones en los bordes que en la superficie perpendicular a nosotros.
Esta característica se puede reproducir en CSS con la propiedad border
, ajustando el grosor, el color y la opacidad.
<code>.with-border {
<mark> <strong>--border-width</strong>: 0.1rem;
<strong>--border-color</strong>: 255, 255, 255;
<strong>--border-opacity</strong>: 0.1;
</mark> <strong>border</strong>: var(--border-width) solid rgba(var(--border-color), var(--border-opacity));
}
</code>
Lenguaje del código: HTML, XML (xml)
Aprovechemos esta oportunidad para definir nuestros parámetros como variables, de modo que podamos modificar los “parámetros físicos” del vidrio sin tener que cambiar constantemente la implementación en CSS. Es una forma de lograr mayor claridad mental, si lo prefieren ☯️
Ahora tenemos la habilidad de aplicar el efecto del borde, lo cual nos permite hacer fácilmente una mejora en nuestro diseño al especificar bordes diferentes para cada lado, logrando dar una dirección a la luz. Por ejemplo, si imaginamos que la luz proviene desde la esquina inferior derecha y se refleja en los lados opuestos del vidrio, podríamos recrear este efecto usando cuatro niveles de opacidad diferentes.
<code> .with-border-and-reflection {
<strong>--border-width</strong>: 0.1rem;
<strong>--border-color</strong>: 255, 255, 255;
<strong>--border-opacity-top</strong>: 0.7;
<strong>--border-opacity-right</strong>: 0.7;
<strong>--border-opacity-bottom</strong>: 0.3;
<strong>--border-opacity-left</strong>: 0.2;
<strong>border-top</strong>: var(--border-width) solid rgba(var(--border-color), var(--border-opacity-top));
<strong>border-right</strong>: var(--border-width) solid rgba(var(--border-color), var(--border-opacity-right));
<strong>border-bottom</strong>: var(--border-width) solid rgba(var(--border-color), var(--border-opacity-bottom));
<strong>border-left</strong>: var(--border-width) solid rgba(var(--border-color), var(--border-opacity-left));
}</code>
Lenguaje del código: HTML, XML (xml)
¿Pero por qué detenernos aquí? ¿Y si intentamos simular diferentes materiales jugando con otras fantásticas propiedades del CSS moderno?
¡Creamos nuestra colección de efectos de vidrio!
Vetro ondulato
Para lograr un efecto que dé la impresión de un vidrio ondulado, debemos recurrir a una propiedad poderosa pero poco conocida: background-image. Normalmente, se usa con archivos a través de la función url(), pero en realidad su verdadero poder proviene del uso de gradientes. En este caso, para obtener nuestro efecto, aprovecharemos precisamente esta capacidad de «composición» del CSS.
El patrón de una onda se puede lograr de muchas maneras, y aquí entra en juego tu creatividad junto con la habilidad (que se debe entrenar) de traducir ideas en código. Una forma de hacerlo es con un gradiente lineal que comienza en 0.0 y vuelve a 0.0 pasando por 1.0 y -1.0… ¿te suena familiar?
Esta vez definimos base, mínimo y máximo en las variables CSS, y recordemos especificar la dirección en ángulos (0deg es vertical). Según esta dirección, debemos «comprimir» nuestro background-size en el eje correspondiente (en este caso, el eje Y):
<code>.waved {
<strong>background-image</strong>: linear-gradient(0deg, var(--base), var(--maximum), var(--base), var(--minimum), var(--base));
<strong>background-size</strong>: 100% 10%;
<strong>--base</strong>: #fff3;
<strong>--minimum</strong>: #fff0;
<strong>--maximum</strong>: #fff6;
}</code>
Lenguaje del código: HTML, XML (xml)
Vidrio con patrón
Hemos visto cómo usar background-image para crear un efecto que se repite horizontal o verticalmente, como el ondulado. Pero, ¿qué sucede si se repite en ambas direcciones?
<code>.pattern-brushed {
<strong>background-image</strong>: linear-gradient(45deg, #fff0, #fff3, #fff0);
<strong>background-size</strong>: 10% 10%;
}
.pattern-grid {
<strong>background-image</strong>: linear-gradient(0deg, #fff3, #fff0 0.1rem), linear-gradient(90deg, #fff3, #fff0 0.1rem);
<strong>background-size</strong>: 5% 5%;
}
.pattern-triangles {
<strong>background-image</strong>: linear-gradient(153deg, #fff3 0.2rem, #fff0 0.1rem);
<strong>background-size</strong>: 5% 5%;
}</code>
Lenguaje del código: HTML, XML (xml)
Vidrio con reflejos
Ahora que estamos familiarizados con background-image y el uso de la función linear-gradient, ¡podemos aprovecharla para un efecto adicional!
<code>.reflected-light {
<strong>background-image</strong>: 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>
Lenguaje del código: HTML, XML (xml)
Vidrio coloreado
Para centrarnos en otros parámetros, no hemos cambiado nunca el color del vidrio, dejando todo en blanco. Pero es evidente que, con el color, realmente podemos darle un toque extra de personalidad.
<code>.aqua-marine {
<strong>background-image</strong>: linear-gradient(0deg, #00f7ff9e 30%, #0072ff99);
}
.color-from-half {
<strong>background-image</strong>: linear-gradient(0deg, #fff0 45%, #ff03 30%, #f009);
}
.color-points {
<strong>background-image</strong>: radial-gradient(#f096 20%, transparent 50%);
<strong>background-size</strong>: 2% 2%;
<strong>background-color</strong>: #f096;
}</code>
Lenguaje del código: HTML, XML (xml)
Efecto Lente
Para obtener un simpático efecto de lente y jugar con el aumento causado por el vidrio, debemos recurrir a un pequeño truco, ya que no podemos usar backdrop-filter con la función blur(). Utilizaremos un pseudo-elemento ::before y heredaremos el fondo del contenedor para luego poder cambiar la propiedad filter en lugar de backdrop-filter.
<code>.lens {
<strong>--zoom</strong>: 100%;
<strong>transition</strong>: background-size 1s ease-in;
<strong>background-image</strong>: inherit;
<strong>overflow</strong>: hidden;
<strong>background-size</strong>: var(--zoom);
<strong>background-attachment</strong>: fixed;
<strong>background-position</strong>: center;
}
.lens::before {
<strong>content</strong>: '';
<strong>background</strong>: inherit;
<strong>position</strong>: absolute;
<strong>inset</strong>: -0.5rem;
<strong>filter</strong>: blur(0.1rem);
<strong>z-index</strong>: -1;
<strong>background-blend-mode</strong>: overlay;
}</code>
Lenguaje del código: HTML, XML (xml)
Conclusiones
El objetivo de este tutorial no era promover el uso universal del glassmorphism, ni tampoco fomentar prácticas que puedan reducir la accesibilidad para algunos usuarios. Escribir sobre un vidrio conlleva muchas dificultades, pero en el contexto adecuado puede añadir un toque futurista a nuestros diseños, ¡y sobre todo es extremadamente divertido de implementar!
¿Y tú, qué esperas para crear tu propio efecto de vidrio y compartirlo en la Comunidad de Codemotion en Telegram? ¡Te esperamos! 👀