A introdução da UI Liquid Glass da Apple no macOS Tahoe 26 estabeleceu um novo padrão para design de interface. A boa notícia? Agora você pode implementar efeitos similares em suas aplicações React. Este guia abrangente percorre a criação de componentes Liquid Glass inspirados na Apple para aplicações web.
Liquid Glass representa a evolução de design de interface mais sofisticada da Apple desde a introdução da translucidez no macOS. O efeito combina:
Transparência dinâmica que responde ao conteúdo
Refração de luz em tempo real criando profundidade
Animações fluidas que se sentem naturais e responsivas
Adaptabilidade contextual baseada na interação do usuário
O efeito Liquid Glass depende de várias tecnologias-chave:
Shaders WebGL para renderização em tempo real
CSS backdrop-filter para efeitos de desfoque
Filtros SVG para manipulação avançada de luz
Aceleração GPU para animações suaves
Primeiro, instale o componente liquid-glass-react:
npm install liquid-glass-react
# ou
yarn add liquid-glass-react
import React from 'react' ;
import { LiquidGlass } from 'liquid-glass-react' ;
import './App.css' ;
function App () {
return (
< div className = "app" >
< LiquidGlass
displacementScale = { 2.0 }
blurAmount = { 1.5 }
elasticity = { 0.7 }
className = "liquid-container"
>
< div className = "content" >
< h1 >Bem-vindo ao Liquid Glass</ h1 >
< p >Experimente o design de interface revolucionário da Apple</ p >
</ div >
</ LiquidGlass >
</ div >
);
}
.liquid-container {
width : 100 % ;
height : 100 vh ;
background : linear-gradient ( 135 deg ,
rgba ( 255 , 255 , 255 , 0.1 ) 0 % ,
rgba ( 255 , 255 , 255 , 0.05 ) 100 % );
backdrop-filter : blur ( 10 px ) saturate ( 180 % );
border : 1 px solid rgba ( 255 , 255 , 255 , 0.2 );
border-radius : 16 px ;
}
.content {
padding : 40 px ;
color : rgba ( 255 , 255 , 255 , 0.9 );
text-align : center ;
}
Escala de Deslocamento (0.0 - 5.0)
Controla a intensidade do efeito de distorção líquida:
< LiquidGlass displacementScale = { 2.5 }>
{ /* Valores mais altos criam deformação mais dramática */ }
</ LiquidGlass >
Quantidade de Desfoque (0.0 - 3.0)
Determina a intensidade do desfoque de fundo:
< LiquidGlass blurAmount = { 1.8 }>
{ /* Imita o efeito de profundidade de campo do macOS Tahoe */ }
</ LiquidGlass >
Elasticidade (0.0 - 1.0)
Ajusta quão fluido o vidro aparenta:
< LiquidGlass elasticity = { 0.9 }>
{ /* Valores mais altos se sentem mais líquidos */ }
</ LiquidGlass >
Raio de Canto
< LiquidGlass cornerRadius = { 20 }>
{ /* Combina com elementos de interface arredondados do macOS Tahoe */ }
</ LiquidGlass >
Intensidade de Aberração
< LiquidGlass aberrationIntensity = { 0.4 }>
{ /* Cria separação sutil de cores para sensação premium */ }
</ LiquidGlass >
import React, { useState } from 'react' ;
import { LiquidGlass } from 'liquid-glass-react' ;
const MenuBar = () => {
const [ isActive , setIsActive ] = useState ( false );
return (
< LiquidGlass
displacementScale = { 1.2 }
blurAmount = { 2.0 }
elasticity = { 0.8 }
className = { `menu-bar ${ isActive ? 'active' : ''}` }
style = {{
position: 'fixed' ,
top: 0 ,
left: 0 ,
right: 0 ,
height: '32px' ,
background: 'rgba(255, 255, 255, 0.05)' ,
backdropFilter: 'blur(20px) saturate(180%)' ,
borderBottom: '1px solid rgba(255, 255, 255, 0.1)' ,
zIndex: 1000
}}
>
< div className = "menu-items" >
< span className = "menu-item" >Arquivo</ span >
< span className = "menu-item" >Editar</ span >
< span className = "menu-item" >Visualizar</ span >
< span className = "menu-item" >Janela</ span >
< span className = "menu-item" >Ajuda</ span >
</ div >
</ LiquidGlass >
);
};
const CompatibilityCard = ({ macModel , compatibility }) => {
const [ isHovered , setIsHovered ] = useState ( false );
return (
< LiquidGlass
displacementScale = {isHovered ? 3.0 : 2.0 }
blurAmount = {isHovered ? 2.0 : 1.5 }
elasticity = { 0.85 }
className = "compatibility-card"
onMouseEnter = {() => setIsHovered ( true )}
onMouseLeave = {() => setIsHovered ( false )}
style = {{
padding: '24px' ,
margin: '16px' ,
background: compatibility.isSupported
? 'rgba(52, 199, 89, 0.1)'
: 'rgba(255, 69, 58, 0.1)' ,
border: '1px solid rgba(255, 255, 255, 0.15)' ,
borderRadius: '16px' ,
transition: 'all 0.3s ease'
}}
>
< h3 >{macModel}</ h3 >
< p >{compatibility.features. join ( ', ' )}</ p >
< div className = "support-indicator" >
{compatibility.isSupported ? '✅ Totalmente Suportado' : '⚠️ Suporte Limitado' }
</ div >
</ LiquidGlass >
);
};
Habilitar Aceleração de Hardware:
.liquid-glass-container {
transform : translateZ ( 0 );
will-change : transform, opacity;
contain : layout style paint;
}
Otimizar para Mobile:
const isMobile = window.innerWidth < 768 ;
< LiquidGlass
displacementScale = {isMobile ? 1.0 : 2.5 }
blurAmount = {isMobile ? 0.8 : 1.5 }
elasticity = {isMobile ? 0.5 : 0.8 }
>
Limpeza de Componente:
import { useEffect, useRef } from 'react' ;
const OptimizedLiquidGlass = ({ children , ... props }) => {
const containerRef = useRef ( null );
useEffect (() => {
const container = containerRef.current;
return () => {
// Limpar contextos WebGL e event listeners
if (container) {
const canvas = container. querySelector ( 'canvas' );
if (canvas) {
const gl = canvas. getContext ( 'webgl' ) || canvas. getContext ( 'webgl2' );
if (gl) {
gl. getExtension ( 'WEBGL_lose_context' )?. loseContext ();
}
}
}
};
}, []);
return (
< div ref = {containerRef}>
< LiquidGlass { ... props}>{children}</ LiquidGlass >
</ div >
);
};
const hasWebGLSupport = () => {
try {
const canvas = document. createElement ( 'canvas' );
return !! (
window.WebGLRenderingContext &&
(canvas. getContext ( 'webgl' ) || canvas. getContext ( 'webgl2' ))
);
} catch (e) {
return false ;
}
};
const hasBackdropFilterSupport = () => {
return CSS . supports ( 'backdrop-filter' , 'blur(1px)' );
};
const ConditionalLiquidGlass = ({ children , fallbackComponent , ... props }) => {
const supportsLiquidGlass = hasWebGLSupport () && hasBackdropFilterSupport ();
if ( ! supportsLiquidGlass) {
return fallbackComponent || (
< div className = "fallback-glass" >{children}</ div >
);
}
return < LiquidGlass { ... props}>{children}</ LiquidGlass >;
};
.fallback-glass {
background : rgba ( 255 , 255 , 255 , 0.1 );
border : 1 px solid rgba ( 255 , 255 , 255 , 0.2 );
border-radius : 16 px ;
backdrop-filter : blur ( 10 px );
}
/* Correções específicas do Safari */
@supports ( -webkit-backdrop-filter : blur ( 10 px )) {
.fallback-glass {
-webkit-backdrop-filter : blur ( 10 px );
}
}
// Biblioteca de componentes de vidro
const GlassButton = ({ variant = 'primary' , children , ... props }) => {
const variants = {
primary: {
displacementScale: 1.5 ,
blurAmount: 1.0 ,
background: 'rgba(0, 122, 255, 0.2)'
},
secondary: {
displacementScale: 1.2 ,
blurAmount: 0.8 ,
background: 'rgba(255, 255, 255, 0.1)'
},
danger: {
displacementScale: 1.8 ,
blurAmount: 1.2 ,
background: 'rgba(255, 69, 58, 0.2)'
}
};
return (
< LiquidGlass
{ ... variants[variant]}
elasticity = { 0.7 }
cornerRadius = { 8 }
className = { `glass-button glass-button--${ variant }` }
{ ... props}
>
< button className = "button-content" >{children}</ button >
</ LiquidGlass >
);
};
const GlassCard = ({ children , ... props }) => (
< LiquidGlass
displacementScale = { 2.0 }
blurAmount = { 1.5 }
elasticity = { 0.8 }
cornerRadius = { 16 }
className = "glass-card"
{ ... props}
>
< div className = "card-content" >{children}</ div >
</ LiquidGlass >
);
import { useSpring, animated } from '@react-spring/web' ;
const AnimatedLiquidGlass = ({ isActive , children }) => {
const springProps = useSpring ({
displacementScale: isActive ? 3.0 : 2.0 ,
blurAmount: isActive ? 2.0 : 1.5 ,
elasticity: isActive ? 0.9 : 0.7 ,
config: { tension: 200 , friction: 25 }
});
return (
< animated.div style = {springProps}>
< LiquidGlass
displacementScale = {springProps.displacementScale}
blurAmount = {springProps.blurAmount}
elasticity = {springProps.elasticity}
>
{children}
</ LiquidGlass >
</ animated.div >
);
};
const customShaderConfig = {
fragmentShader: `
precision mediump float;
uniform sampler2D u_texture;
uniform float u_time;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
vec2 uv = v_texCoord;
// Adicionar distorção baseada em tempo
uv.x += sin(uv.y * 10.0 + u_time) * 0.01;
uv.y += sin(uv.x * 10.0 + u_time * 0.5) * 0.01;
vec4 color = texture2D(u_texture, uv);
// Aplicar refração tipo vidro
float aberration = 0.005;
color.r = texture2D(u_texture, uv + vec2(aberration, 0.0)).r;
color.b = texture2D(u_texture, uv - vec2(aberration, 0.0)).b;
gl_FragColor = color;
}
`
};
< LiquidGlass
customShader = {customShaderConfig}
displacementScale = { 2.5 }
>
{children}
</ LiquidGlass >
const AccessibleLiquidGlass = ({ children , ... props }) => {
const prefersReducedMotion = window. matchMedia (
'(prefers-reduced-motion: reduce)'
).matches;
const accessibleProps = prefersReducedMotion
? {
displacementScale: 0.5 ,
elasticity: 0.3 ,
// Movimento reduzido para usuários sensíveis
}
: props;
return (
< LiquidGlass { ... accessibleProps}>
{children}
</ LiquidGlass >
);
};
< LiquidGlass
aria-label = "Elemento de interface de vidro interativo"
role = "presentation"
{ ... props}
>
< div aria-live = "polite" className = "sr-only" >
Conteúdo atualizado com efeito liquid glass
</ div >
{children}
</ LiquidGlass >
const PerformanceMonitor = ({ children }) => {
useEffect (() => {
let frameCount = 0 ;
let lastTime = performance. now ();
const measureFPS = () => {
frameCount ++ ;
const currentTime = performance. now ();
if (currentTime - lastTime >= 1000 ) {
console. log ( `Liquid Glass FPS: ${ frameCount }` );
frameCount = 0 ;
lastTime = currentTime;
}
requestAnimationFrame (measureFPS);
};
measureFPS ();
}, []);
return children;
};
class LiquidGlassErrorBoundary extends React . Component {
constructor ( props ) {
super (props);
this .state = { hasError: false };
}
static getDerivedStateFromError ( error ) {
return { hasError: true };
}
componentDidCatch ( error , errorInfo ) {
console. error ( 'Erro Liquid Glass:' , error, errorInfo);
}
render () {
if ( this .state.hasError) {
return (
< div className = "fallback-glass" >
{ this .props.fallback || this .props.children}
</ div >
);
}
return this .props.children;
}
}
// webpack.config.js otimização para Liquid Glass
module . exports = {
optimization: {
splitChunks: {
chunks: 'all' ,
cacheGroups: {
liquidGlass: {
test: / [ \\ /] node_modules [ \\ /] liquid-glass-react [ \\ /] / ,
name: 'liquid-glass' ,
priority: 10 ,
reuseExistingChunk: true
}
}
}
}
};
// Carregamento lazy para performance
const LiquidGlass = React. lazy (() =>
import ( 'liquid-glass-react' ). then ( module => ({
default: module .LiquidGlass
}))
);
const LazyLiquidGlass = ({ children , ... props }) => (
< Suspense fallback = {< div className = "fallback-glass" >{children}</ div >}>
< LiquidGlass { ... props}>{children}</ LiquidGlass >
</ Suspense >
);
// Interface TypeScript para integração com sistema de design
interface LiquidGlassTheme {
colors : {
glassTint : string ;
borderColor : string ;
backgroundGradient : string [];
};
effects : {
displacementScale : number ;
blurAmount : number ;
elasticity : number ;
};
accessibility : {
reducedMotion : boolean ;
highContrast : boolean ;
};
}
const ThemedLiquidGlass : React . FC <{
theme : LiquidGlassTheme ;
children : React . ReactNode ;
}> = ({ theme , children }) => {
const effectProps = theme.accessibility.reducedMotion
? { ... theme.effects, displacementScale: 0.5 }
: theme.effects;
return (
< LiquidGlass
{ ... effectProps}
style = {{
background: `linear-gradient(${ theme . colors . backgroundGradient . join ( ', ' ) })` ,
border: `1px solid ${ theme . colors . borderColor }`
}}
>
{children}
</ LiquidGlass >
);
};
Implementar a UI Liquid Glass da Apple em React abre possibilidades empolgantes para criar interfaces de usuário premium e envolventes. O componente liquid-glass-react fornece uma base sólida, mas a verdadeira mágica acontece quando você o combina com princípios de design cuidadosos e otimização de performance.
Principais Conclusões:
Comece simples com configurações básicas antes de adicionar complexidade
Priorize performance com aceleração GPU adequada e fallbacks
Considere acessibilidade para usuários com sensibilidade ao movimento
Teste completamente em diferentes dispositivos e navegadores
Monitore performance para garantir experiências suaves do usuário
Conforme o macOS Tahoe continua a influenciar tendências de design de interface, dominar a implementação Liquid Glass posiciona suas aplicações na vanguarda do desenvolvimento de UI moderno. A combinação de sofisticação técnica e elegância visual torna-se uma ferramenta poderosa para criar experiências memoráveis do usuário.
Próximos Passos:
Experimente com a demo oficial
Faça fork do repositório GitHub para customização
Participe das discussões da comunidade de desenvolvedores
Compartilhe suas implementações e aprenda com outros
Pronto para trazer Liquid Glass para seu projeto? Verifique nosso guia de compatibilidade para garantir que seus navegadores alvo suportem os recursos avançados necessários para renderização ótima do Liquid Glass.