DroidGlass: Vidrio Líquido para cualquier plataforma
El Vidrio Líquido es el material de Apple que refracta lo que hay debajo. Cerca del borde, el fondo se desplaza hacia el centro como una lente gruesa, aparece un suave arcoíris en el borde, un destello fino recorre el borde y, al tocarlo, el vidrio se hincha, se estira hacia el dedo y vuelve a su lugar. El glassmorphism común solo difumina el fondo bajo una neblina blanca, por eso se ve barato y mate.
La regla principal del buen gusto: el vidrio es transparente. Si no se puede leer lo que hay detrás, es vidrio esmerilado de iOS 7, no Vidrio Líquido. Añade desenfoque y una superficie solo donde el texto se asienta sobre el vidrio.
Indica al usuario honestamente dónde están los límites. El material real solo existe en iOS, iPadOS y macOS 26 y posteriores; todo lo demás es una imitación. En Android, Backdrop proporciona la imitación completa (la lente necesita Android 13). En la web, la refracción funciona solo en Chromium (Chrome, Edge, Samsung Internet, Android WebView, Electron). Safari, Firefox y cualquier navegador en iOS obtienen un desenfoque ligero con los mismos destellos, sombras y muelles, pero sin curvatura.
Flujo de trabajo
- Identifica la plataforma.
- SwiftUI, UIKit, AppKit, WidgetKit en iOS/macOS 26: API del sistema, consulta
references/apple.md. No imites nada. - Jetpack Compose o Compose Multiplatform:
references/android-compose.md. No escribas shaders desde cero, usa la librería. - Web, Electron, Android WebView, Capacitor, Cordova, Tauri en Windows/Android: el motor en
assets/, consultareferences/web.md. En WebView y Electron la refracción siempre funciona. - React Native, Flutter: no hay equivalente del sistema. Para React Native sugiere una capa WebView o un módulo nativo sobre Backdrop; para Flutter,
BackdropFiltercomo alternativa y unFragmentProgramcon las fórmulas dereferences/math-and-motion.md. Revisa los paquetes actuales por tu cuenta; esta habilidad no los lista.
- SwiftUI, UIKit, AppKit, WidgetKit en iOS/macOS 26: API del sistema, consulta
- Elige de 1 a 3 elementos de la capa de control: barra de pestañas, botón flotante, barra superior, hoja, menú, interruptor o el pulgar de un deslizador mientras se toca. No hagas que el contenido sea de vidrio.
- Elige una receta de la tabla siguiente. No inventes parámetros: los valores provienen del catálogo de Kyant y se verificaron en pantalla.
- Verifica el fondo detrás del vidrio. El vidrio solo es visible sobre contenido rico: fotos, color, gráficos, texto mientras se desplaza. Sobre una página blanca lisa, el vidrio transparente casi desaparece: pon color detrás, añade una capa de atenuación o elimina el vidrio allí.
- Construye siguiendo la referencia correcta y verifícalo con tus propios ojos usando la lista de verificación al final. No lo entregues sin capturas de pantalla en reposo, pulsación y arrastre.
Reglas de Apple
De las Guías de Interfaz Humana, WWDC25 "Conoce el Vidrio Líquido" y habilidades populares de la comunidad. Romper cualquiera de ellas delata la imitación de inmediato.
- Solo la capa de navegación y control que flota sobre el contenido. Las listas, filas, tarjetas y el fondo de la página no son de vidrio. Excepción: los pulgares de interruptores y deslizadores se convierten en vidrio mientras se tocan.
- No vidrio sobre vidrio. Los elementos sobre el vidrio se diferencian por relleno y opacidad. Excepción de Backdrop: el pulgar de un deslizador sobre una hoja de vidrio refracta la hoja (
exportedBackdrop): una lente sobre otra, no dos placas mate. - Úsalo con moderación. Solo los controles más importantes.
- El vidrio es incoloro. El color y el brillo provienen del fondo: claro sobre claro, oscuro sobre oscuro, el destello se tiñe por el fondo. Sin superficie blanca o gris propia.
- Dos modos, no los mezcles. Claro (botones, pulgares, lupa, barra de pestañas agrupada con un botón): desenfoque 0 a 4, sin superficie. Regular (hoja, diálogo con texto largo): desenfoque 8 a 16; añade una superficie del 40 al 60% solo si el texto es ilegible sin ella.
- Tiñe solo la acción principal.
- Forma. Cápsula: radio igual a la mitad de la altura. Esquinas concéntricas: el radio interior es igual al radio del contenedor menos el relleno.
- Más grande significa más grueso: los elementos grandes obtienen un borde curvo más ancho y una refracción más profunda.
- Nunca dejes contenido a medio camino bajo el vidrio.
- Líquido en movimiento. Al presionar, el vidrio crece unos píxeles y se inclina hacia el dedo con amortiguación; un pulgar se infla 1.5x y se estira formando una gota a velocidad. Todo funciona con muelles, sin transiciones lineales.
Recetas (valores del catálogo de Kyant)
| Elemento | Efectos | Destello y sombras | Toque |
|---|---|---|---|
| Botón, cápsula de 48 dp | vibrancia, desenfoque 2, lente(12, 24) | Predeterminado, sombra predeterminada | brillo; crece 4 dp en altura; desplazamiento min × tanh(0.05 × offset / min); se estira hasta 4 dp hacia el dedo |
| Botón teñido | mismo + tinte | mismo | mismo |
| Botón con superficie | mismo + blanco 30% | mismo | mismo |
| Pulgar de interruptor 40×24 sobre pista 64×28 | en reposo blanco 100% y desenfoque 8; presionado p: desenfoque 8(1−p), lente(5p, 10p, dispersión), blanco (1−p) | Ambiente, ancho /1.5, alfa p; sombra radio 4, 5%; sombra interior radio 4p, alfa p | escala a 1.5; la pista se ve a través de la lente, reducida a 0.75 |
| Pulgar de deslizador 40×24, pista de 6 dp | como el interruptor, lente(10p, 14p) | como el interruptor | escala a 1.5; tocar la pista salta al punto |
| Barra de pestañas 64 dp | vibrancia, desenfoque 8, lente(24, 24), superficie #FAFAFA 40% (oscuro #121212 40%) | Predeterminado | al presionar, todo el panel crece 16 dp de ancho (las etiquetas con él) y se inclina hasta 4 dp detrás del dedo |
Copia de fila oculta 56 dp (tabsBackdrop) | el mismo panel en el color de acento, alpha(0): vibrancia, desenfoque 8, lente(24p, 24p), superficie del panel | Predeterminado con alfa p, InteractiveHighlight | iconos y etiquetas ×1.2 al presionar (LocalLiquidBottomTabScale se establece solo en esta fila) |
| Pulgar de barra de pestañas 56 dp | en reposo gris 10%; presionado lente(10p, 14p, dispersión) sobre el fondo y la copia de fila (rememberCombinedBackdrop(backdrop, tabsBackdrop)) | Predeterminado, sombra y sombra interior 8p con alfa p | escala 78/56; dentro de la gota una "barra bajo la barra": su propio elemento en acento, magnificado, vecinos visibles en los bordes |
| Diálogo, radio 48 | brillo 0.2 (claro), saturación 1.5, desenfoque 16 (oscuro 8), lente(24, 48, profundidad) | Sin sombra | atenúa el fondo #29293A 23% (oscuro #121212 56%) |
| Mosaico del centro de control | vibrancia, lente(24, 48, profundidad) | Predeterminado, ángulo según inclinación del dispositivo, caída 2 | entrada: desplazamiento 48 dp y alfa |
| Lupa 128×96 | lente(8, 24, profundidad, dispersión), fondo ampliado 1.5x | sombra interior 16 | arrastrar |
Los muelles, gestos y las matemáticas compartidas detrás de cada plataforma están en references/math-and-motion.md.
Web y Android WebView en un minuto
Copia los tres archivos de assets/ en el proyecto sin cambios y configúralos con opciones. No reescribas el motor.
<link rel="stylesheet" href="liquid-glass.css">
<button id="buy">Comprar</button>
<div id="wifi" aria-label="Wi-Fi"></div>
<div id="volume" style="width: 280px"></div>
<nav id="tabs" style="position: fixed; left: 16px; right: 16px; bottom: 16px"></nav>
<script src="liquid-glass.js"></script>
<script src="liquid-ui.js"></script>
<script>
LiquidUI.button(document.getElementById('buy'), { tint: '#0088FF', onClick: () => {} });
LiquidUI.toggle(document.getElementById('wifi'), { checked: true, onChange: (on) => {} });
LiquidUI.slider(document.getElementById('volume'), { value: 0.4, onInput: (v) => {}, label: 'Volumen' });
const tabs = LiquidUI.tabs(document.getElementById('tabs'), {
items: [{ label: 'Inicio', icon: '<svg>…</svg>' }, { label: 'Buscar', icon: '<svg>…</svg>' }],
index: 0, onChange: (i) => {},
});
// fusión: una barra y un botón uno al lado del otro se funden en una sola gota; los botones elásticos vecinos lo hacen solos
// LiquidUI.blob([tabs.panel, fab], { blur: 3.5 }); LiquidUI.autoMerge(document.body); después de un cambio de pantalla LiquidUI.sweep()
// vidrio desnudo para tu propio marcado
const g = LiquidGlass.attach(document.getElementById('panel'), { radius: 28, blur: 8, refractionHeight: 24, refractionAmount: 24, surface: 'rgb(250 250 250 / .4)' });
// g.set({ lens: 0..1, blur, surface, highlightAlpha, angle, shadowAlpha, innerShadow, press: { p, x, y }, tx, ty, sx, sy, sleep })
</script>
| Archivo | Qué es |
|---|---|
assets/liquid-glass.js | motor de vidrio: mapas de refracción, dispersión, destello, sombras, grupos de fusión (LiquidGlass) |
assets/liquid-glass.css | estilos base, alternativas de accesibilidad, estilos de componentes |
assets/liquid-ui.js | muelles, gestos y componentes: botón, interruptor, deslizador, pestañas, lupa, blob, autoMerge (LiquidUI) |
assets/demo.html | cada componente en una página; ábrelo para ver cómo se ve correctamente |
Antes de cambiar algo o integrarlo en una aplicación, lee references/web.md: enumera los hechos de Chromium que rompen casi todas las implementaciones (raíces de fondo, position: fixed, touch-action, fondos del body) y todas las opciones. Cuando algo se vea mal, ve a references/troubleshooting.md; cuando algo se entrecorte, ve a references/performance.md.
Cinco cosas que nunca debes hacer mal en la web:
- El fondo debe ser un elemento real. Un fondo establecido en
bodyque se propaga a la raíz no es visto porbackdrop-filter. - Nunca animes
opacity,filter,maskoclip-pathen un ancestro del vidrio (por ejemplo, una transición de pantalla): se convierte en una raíz de fondo y el vidrio pierde su fondo y se oscurece. Mueve las pantallas contransformy revélalas con una capa de velo encima. - No establezcas tu propio
transformen un elemento de vidrio; escribe el desplazamiento base en--lg-base. - Los botones elásticos necesitan
touch-action: none(el valor predeterminado). Conpan-yel navegador roba el arrastre y envíapointercancel. - En un Android WebView, desactiva la pulsación larga y las hápticas:
setOnLongClickListener(v -> true)ysetHapticFeedbackEnabled(false).
Accesibilidad y legibilidad
- El motor web respeta
prefers-reduced-transparency: reduce(vidrio desactivado, superficie casi opaca; Chrome y Edge 119+, aún no Safari o Firefox),prefers-contrast: more(superficie sólida y borde) yprefers-reduced-motion(los muelles se vuelven instantáneos). - Los componentes obtienen roles y soporte de teclado: botón (Enter, Espacio),
switch(Enter, Espacio),slider(flechas),tablist(flechas izquierda y derecha). Etiquétalos conaria-labeloaria-labelledby. - En Android, establece
semantics { role = Role.Switch }y etiquetas, como en el catálogo de Kyant; en Android antiguo verifica que el coloronDrawSurfacesea legible sin efectos. - Verifica el contraste del texto sobre el contenido más claro y más cargado que pueda terminar debajo del panel: 4.5:1 para el texto del cuerpo. Si falla, añade desenfoque y una superficie o mueve el contenido. Una sombra de texto no lo soluciona.
No hagas
- Una superficie blanca translúcida más
blur(10px)en botones: eso es vidrio esmerilado, no Vidrio Líquido. La densidad solo está bien para barras de pestañas, hojas y diálogos con texto. - Tarjetas de contenido de vidrio y fondo de página de vidrio.
- Dispersión en paneles grandes: caro y llamativo.
- Un borde blanco grueso en lugar de un destello fino.
- El mismo tinte en cada botón.
- Transiciones lineales en lugar de muelles para pulsación y arrastre.
- Animar
widthyheightdel vidrio en la web: el mapa se reconstruye cada fotograma. Anima el scale. - Pasos de filtro pesados (desenfoque, desplazamiento, convolución, morfología) bajo un resultado que varios pasos leen: Chrome los calcula una vez por rama y los teléfonos se congelan.
- Pintar el vidrio con tu propia superficie "por estética". Solo los paneles densos con texto obtienen una superficie.
- Escribir tus propios shaders de Compose cuando Backdrop encaja.
- Símbolos SF y logotipos de Apple fuera de las plataformas Apple: su licencia lo prohíbe. Usa conjuntos de iconos abiertos.
- Llamar al resultado web o Android "Vidrio Líquido oficial". Es una imitación en su estilo.
Lista de verificación antes de entregar
Capturas de pantalla a escala 2, míralas tú mismo:
- Reposo sobre una cuadrícula o texto: las líneas son visibles a través del vidrio transparente, tiradas hacia el centro en el borde, el destello es fino. En blanco, el vidrio se separa de la página por el sombreado del borde y la sombra; en oscuro, por una línea brillante en el lado iluminado.
- Pulsación: el botón creció y se inclina hacia el dedo; un pulgar está inflado y transparente, la pista se ve a través de él, el arcoíris es suave, sin agujeros de color.
- Arrastre: un pulgar se estira a velocidad y se desinfla solo después de llegar; la barra de pestañas se inclina y regresa. La gota de la barra de pestañas en pestañas de borde y cerca del borde inferior de la pantalla: su propio elemento dentro, vecinos en los bordes, sin áreas negras, bandas o piezas reflejadas.
- Tirador: un botón sigue el dedo en una banda elástica y rebota; una barra tirada hacia un botón vecino se funde con él, el puente crece a medida que se acercan, sin costura ni borde doble; en reposo y en una pulsación simple permanecen separados; un toque normal funciona, un botón tirado lejos y soltado no se activa.
- Sobre una foto y sobre blanco: el color bajo el vidrio es rico, el texto es legible.
- Tema oscuro.
- Alternativa: falsifica el motor (agente de usuario de Safari y
navigator.userAgentDatavacío) y verifica que los elementos no se hayan convertido en agujeros y los iconos debajo del pulgar de la barra de pestañas no estén borrosos. - Redimensionamiento y rotación: el mapa se reconstruye, sin escalones en el borde.
- Transiciones de pantalla: captura varios fotogramas consecutivos mientras una pantalla entra; los botones de vidrio nunca son más oscuros que en reposo, las capas de fusión permanecen exactamente debajo de sus botones después de la animación.
- Sin errores en la consola y sin bloqueos: después de una ráfaga de toques, la página responde igual de rápido. Un bucle de animación, sin
requestAnimationFramesueltos. - No más de 3 elementos grandes de vidrio en una pantalla de teléfono, sin vidrio sobre vidrio, sin contenido de vidrio.
Si algo falla, arréglalo primero, luego muéstraselo al usuario.
Fuentes
- Kyant0/AndroidLiquidGlass, librería Backdrop y catálogo (Apache-2.0): fórmulas de lente, dispersión, destello y sombra, recetas de componentes, constantes de muelles y gestos. El motor web es un puerto de este esquema.
- Apple: Guías de Interfaz Humana "Materiales", "Adoptando el Vidrio Líquido", WWDC25 "Conoce el Vidrio Líquido".
- kube.io, "Vidrio Líquido en el Navegador": refracción a través de
feDisplacementMapdentro debackdrop-filter. - iyinchao/liquid-glass-studio (MIT): fusión de formas mediante
smin, refracción de Snell, vidrio incoloro con un alto ...