4 pontos por GN⁺ 2024-11-25 | 1 comentários | Compartilhar no WhatsApp
  • Partindo da frosted acrylic UI de Forza Horizon 3 e Forza Motorsport 7, o texto organiza o processo de reproduzir na web um efeito semelhante de painel de vidro com HTML/CSS/JavaScript
  • O centro do efeito é o Gaussian blur, e é preciso usar juntos o CSS backdrop-filter e o -webkit-backdrop-filter do iOS para reduzir diferenças entre navegadores
  • Como só o desfoque parece plano, usa-se box-shadow: inset para adicionar profundidade nas bordas e subsurface scattering, além de uma sombra normal para criar a sensação de que o painel flutua sobre o fundo
  • O reflexo da superfície é implementado com uma imagem de raios de luz em uma camada separada, imitando reflexos dinâmicos alinhados ao movimento do vidro com background-attachment: fixed ou JavaScript
  • A UI final combina as camadas .glass, .light e .drag-me, adicionando cantos arredondados, clipping e cor de fundo semitransparente para formar um componente de vidro reutilizável

Efeito de painel de vidro trazido da UI de jogos

  • O objetivo é recriar em HTML o design frosted acrylic visto na experiência de desenvolvimento de UI de Forza Horizon 3 e Forza Motorsport 7
  • O resultado é um painel de vidro arrastável, com desfoque de fundo, profundidade nas bordas, reflexo de luz, cantos arredondados e uma camada de cor semitransparente
  • No começo, é apresentada uma receita final que pode ser copiada e usada imediatamente, e depois cada efeito é construído passo a passo

backdrop-filter para criar o desfoque de fundo

  • O ponto central de um bom efeito de frosted glass é o Gaussian blur, que desfoca o fundo para fazê-lo parecer uma tela semitransparente
  • Em CSS, isso é implementado aplicando backdrop-filter com blur
  • O elemento base de vidro começa com uma div simples e a classe .glass
    • backdrop-filter: blur(10px)
    • -webkit-backdrop-filter: blur(10px)
  • No iOS, -webkit-backdrop-filter é necessário, a menos que se alterem configurações mais profundas
  • Como o suporte a backdrop-filter só chegou recentemente aos navegadores, usuários de Internet Explorer não conseguem ver a demo

Criando profundidade com bordas e sombras

  • Aplicar apenas backdrop-filter: blur(10px) pode fazer o vidro parecer plano e monótono
  • As bordas são implementadas com box-shadow: inset em vez de border: 1px solid
    • border afeta o tamanho do elemento e o posicionamento dos elementos filhos
    • Com box-shadow: inset, os filhos podem preencher naturalmente a área de conteúdo do vidro sem ajustes como margem negativa
  • Duas sombras inset brancas semitransparentes representam as bordas do vidro
    • A primeira shadow representa a borda visível do lado de fora do vidro e, no exemplo, aparece nas bordas inferior e esquerda
    • A segunda shadow representa a borda vista através do vidro e, no exemplo, aparece nas bordas superior e direita
  • Como a luz diminui nas bordas vistas através do vidro, elas são configuradas de forma mais suave e transparente
  • Adicionar um box-shadow escuro normal pode dar a sensação de que o vidro está fisicamente flutuando sobre o fundo

Dispersão de luz e reflexo na superfície

  • A sensação de luz se espalhando dentro do vidro é representada de forma simplificada usando subsurface scattering
  • A implementação novamente usa box-shadow: inset
    • Efeito curto de dispersão: inset 0px 0px 10px 5px rgba(255, 255, 255, 0.025)
    • Efeito mais profundo de dispersão: inset 0px 0px 40px 5px rgba(255, 255, 255, 0.025)
  • Esse efeito aparece melhor ao arrastar o vidro sobre um fundo escuro
  • Além da sensação de fundo desfocado e refratado, também se adiciona a característica de a luz refletir na superfície do vidro
  • O reflexo de luz é implementado misturando uma imagem de raios de luz ao fundo
    • Há um tutorial no YouTube e uma explicação em texto que podem servir de referência para criar uma imagem parecida
    • Se a imagem for colocada diretamente como background-image do elemento .glass, o backdrop-filter também a desfoca, por isso é usada uma camada separada como ::before

Transformando reflexos estáticos em dinâmicos

  • Se apenas a imagem de raios de luz for adicionada, o reflexo aparece, mas pode parecer preso à superfície do vidro mesmo quando ela se move
  • A abordagem puramente em CSS adiciona background-attachment: fixed ao ::before
    • A implementação é simples, mas pode não funcionar em todas as plataformas
  • Para funcionar em todas as plataformas, usa-se JavaScript para imitar background-attachment: fixed
    • Como lidar diretamente com ::before em JavaScript é ineficiente, usa-se um elemento div.light separado
    • O elemento-alvo recebe o atributo data-js-background-attachment-fixed
  • A cada frame de animação, o JavaScript lê getBoundingClientRect() do elemento-alvo e atualiza background-position na direção oposta à posição dentro da viewport
    • backgroundPositionX = -clientRect.x
    • backgroundPositionY = -clientRect.y
  • O loop de repetição roda com requestAnimationFrame

Estrutura final em HTML/CSS

  • No HTML final da versão com JavaScript, a .glass contém a .light para reflexo da luz e a .drag-me, que é a camada de texto/cor

  Drag Me

  • .glass é responsável pela forma básica do painel de vidro e pelos efeitos visuais
    • aplica desfoque de fundo com backdrop-filter e -webkit-backdrop-filter
    • aplica bordas, sombras e efeito de dispersão com vários box-shadow
    • usa position: relative para permitir que as camadas filhas preencham a área do elemento pai
    • aplica cantos arredondados com border-radius: 5px
    • corta os elementos filhos para que não ultrapassem os cantos arredondados com overflow: hidden
  • .light usa a imagem de raios de luz como fundo repetido
    • background-image: url(path/to/light.png)
    • background-repeat: repeat
    • background-size: 750px
    • opacity: 0.075
    • preenche todo o pai com position: absolute e offsets 0 nos quatro lados
    • é renderizada atrás dos outros filhos com z-index: -1
  • .drag-me centraliza o conteúdo e cria uma camada de vidro colorida e semitransparente
    • display: flex
    • align-items: center
    • justify-content: center
    • height: 30px
    • background-color: rgba(12, 13, 14, 0.75)

Diferenças da versão sem JavaScript

  • A versão sem JavaScript usa .glass::before em vez de um elemento .light separado
  • A imagem de raios de luz é aplicada ao ::before, e background-attachment: fixed implementa um reflexo preso à tela
  • Esse método não funciona em todas as plataformas, e a versão com JavaScript contorna isso atualizando background-position diretamente

1 comentários

 
GN⁺ 2024-11-25
Comentários do Hacker News
  • Esteticamente eu gosto muito, mas há partes nas bordas que não fazem sentido fisicamente.
    Do ponto de vista de um desenvolvedor embarcado, parece um tanto desperdiçador. Fico com a impressão de que todo cliente acaba calculando, toda vez, um filtro de blur “caro” para misturar com uma versão desfocada da imagem de fundo.
    Talvez, por usar GPU e ser otimizado, no fim não tenha um custo tão grande, mas o desenvolvimento web hoje em dia, no geral, parece caminhar para ficar inchado demais. Até sites simples levam 5 segundos para carregar e empurram processamento pesado para o cliente — claro que isso não é culpa de quem escreveu este texto.

    • Cada pessoa parece ter seus próprios vieses sobre o que considera desperdício.
      Cresci na época dos modems de 14,4k, então estou acostumado a pensar que largura de banda de rede é muito mais escassa e cara do que tempo de CPU.
      Se dá para calcular facilmente no cliente, acho mais desperdiçador baixar uma imagem inteira pela internet. Para receber essa imagem, roteadores, servidores e até discos distantes precisam entrar em ação; usar tudo isso só para evitar um processamento sobre dados que já estão na RAM do cliente parece um desperdício maior.
    • Mesmo sites que, tecnicamente, são “desperdiçadores” em algum sentido, quando olhamos para o uso real, em uma perspectiva mais ampla, são usados em grande parte para entretenimento puro.
      Então ou entretenimento em si é desperdício, ou, se não for, também é aceitável gastar mais computação para tornar o entretenimento melhor.
    • Para uma pessoa, isso pode parecer desperdício, como “recalcular bastante os gráficos já renderizados”, mas tecnicamente não acho que seja necessariamente assim.
      Para redesenhar o que muda na UI, algum cálculo de GPU já é necessário de qualquer forma, e um blur simples pode ser adicionado de maneira bem eficiente. É provável que custe menos do que animar objetos DOM que não foram otimizados como camadas de GPU.
      Considerando que hoje até os sites mais simples carregam mais de 1 MB de JavaScript e um monte de rastreadores que consomem CPU, um blur para efeito estético fica bem abaixo na lista de desperdícios.
    • Enviar pela rede tanto a imagem desfocada quanto a original não foi justamente o jeito como o desenvolvimento web fez isso nos últimos 20 anos?
      Quando há muitas imagens em alta resolução, a largura de banda real da rede é finita e, especialmente em ambientes móveis com cobertura sem fio ruim, isso com certeza tem desempenho pior do que computação local. Hoje é surpreendente o que dá para fazer só com CSS/WebGL; antigamente, eram necessários muitos hacks e gambiarras para obter esse tipo de efeito.
    • Acho que já está na hora de levar a sério que muitas tecnologias do tipo “nossa, isso parece legal, com certeza eu/nós precisamos disso” não têm lugar neste mundo.
      Independentemente de o ato em si ser desperdício ou não, esse modo de pensar revela um problema maior da sociedade. Por que isso é necessário e por que enxergamos a ausência disso como algo ruim?
      Dada a escala dos problemas sociais de hoje, quem realmente se importa se um painel de UI está desfocado ou não?
  • Ao tentar recriar o efeito Windows 7 Aero Glass no Android para ver o que dava para fazer com a nova API de shaders, extraí uma textura de “raios de luz” parecida.
    O resultado acabou ficando muito parecido com o deste artigo, embora eu não tenha colocado sombra interna e tenha aumentado um pouco a saturação do fundo desfocado.
    https://mastodon.social/@grishka/110524476584503201

    • Muito bonito. A textura de raios de luz pode realmente fazer bastante diferença nesse efeito.
      Para ser sincero, a que foi feita para o tutorial nem é tão excelente assim. Gosto das linhas mais nítidas da versão do Windows 7.
      Também pensei em ajustar a saturação e vi isso em outros exemplos, mas decidi não usar no texto. A imagem da lua que usei não tem muitas cores, então provavelmente não faria tanta diferença. Quem for criar seu próprio efeito de vidro deveria experimentar a saturação também.
  • O trabalho em si é excelente, e a forma de apresentar com uma demo interativa também é boa. É divertido arrastar a janela sobre a lua.
    Mas não gosto do uso do efeito de vidro fosco em design de interface, e senti que foi um retrocesso quando ele foi adicionado ao Mac OS. Designers se encantam fácil demais com esse efeito, mas na prática ele nunca é ideal. Especialmente quando o conteúdo atrás do painel é dinâmico ou criado pelo usuário.
    É como o metal escovado dos anos 2010, e é surpreendente que tenha vazado do Windows Vista e se espalhado por toda parte.

    • Não sei por que ele não seria “ideal”. Design visual tem muito mais a ver com gosto pessoal sobre o que é bonito do que com um objetivo prático.
      Claro que o design também afeta a função, mas o objetivo principal é tornar a experiência do usuário mais agradável.
      Acho que o esqueumorfismo torna as interfaces mais agradáveis do que a tendência minimalista de achatar tudo que prevaleceu por mais de uma década. Ornamentos visuais que imitam superfícies e materiais do mundo real acrescentam familiaridade e acessibilidade. Em termos práticos, o design flat dificulta distinguir elementos e estados, enquanto, na época dos botões 3D, do metal escovado e do vidro fosco, tudo era muito mais claro.
      Acho que agora o pêndulo está voltando. Como mais designers estão evitando a aparência plana, espero que uma UI mais amigável para humanos volte a surgir.
    • Não sou designer de UI, então gostaria de perguntar seriamente: o problema é usar efeitos estéticos como vidro fosco ou metal escovado no design de UI em si, ou é que, ao tentar criar esse tipo de interface, alguns designers acabam perdendo as pistas visuais que indicam a posição e a função dos controles?
    • Há anos uso um pouco de transparência na janela do terminal, mas agora isso me fez repensar.
    • Metal escovado não afeta o contexto da informação. O blur oferece um contexto ajustável.
      Blur geralmente não é a resposta certa, mas às vezes é a escolha correta.
    • Ironicamente, versões anteriores do macOS também usavam bastante metal escovado.
  • Em 2008, antes de o CSS dar suporte a backdrop-blur, já fiz um experimento em CSS para obter um efeito parecido: https://webdev.andersriggelsen.dk/aero/
    A abordagem era aplicar um efeito de vidro a uma imagem de fundo em posição fixa, previamente desfocada: https://webdev.andersriggelsen.dk/aero/bgl.jpg
    O desempenho é muito melhor do que um desfoque gaussiano em tempo real, mas a desvantagem de não permitir imagens de fundo dinâmicas continua a mesma

    • Em uma época ainda anterior, fui um passo além usando um arquivo Flash como fundo
      Dava para criar o efeito de vidro mesmo dentro de um frame que podia se mover dinamicamente. Não me lembro se usei iframe, então teria de procurar o código, mas, considerando a época, provavelmente usei
    • A janela flutuante não é atualizada depois da posição inicial
      Estou no Windows 10 19045.5131, e o Chrome é a versão mais recente, Version 131.0.6778.86 (Official Build) (64-bit)
  • A realização técnica é legal, mas vejo isso como UX ruim
    O conteúdo dentro de painéis translúcidos é mais difícil de ler ou entender do que sobre um fundo sólido consistente, e o contraste com o fundo é baixo e irregular. Além disso, se algo se move por baixo, pode distrair e desorientar

    • É difícil generalizar um único efeito visual simples como “UX ruim”. Depende muito de como ele é integrado
      Uma boa integração deve ajustar a intensidade do efeito para não deixar a UI exagerada, verificar o suporte ao recurso para evitar decoração extra quando o desfoque não for suportado, e verificar os recursos de tela e vídeo para não renderizar em dispositivos em que talvez não haja GPU suficiente
      Também deve verificar as preferências do usuário para oferecer uma cor sólida de alto contraste a usuários que têm dificuldade com fundos complexos, limitar o alcance do efeito e das sombras conforme o espaço disponível, e ajustar o desfoque e a opacidade levando em conta a complexidade e o contraste do fundo sob a área desfocada
      Também é necessário garantir que o desfoque e as sombras escalem de forma adaptativa de acordo com a tipografia. UX é, em essência, o design de como o usuário vivencia a interação com o app inteiro, não algo que dá certo ou errado por causa de uma única escolha de estilo
    • O Windows Vista resolvia esse problema dando ao texto preto sobre o vidro fosco um contorno parecido com uma sombra branca
      Isso garantia a legibilidade do texto mesmo em casos extremos em que o fundo era preto. Em CSS, dá para reproduzir isso com a propriedade text-shadow
    • É por isso que não uso esse efeito no site inteiro. Porque fica mais difícil criar uma boa UX
      Mas em jogos há mais lugares onde ele pode ser usado. Em especial, pode ser adequado em um HUD, quando você não quer esconder o fundo, que é a área principal com a qual o usuário interage
    • Se o problema é o baixo contraste, basta deixar o fundo ou a tonalidade do vidro mais escuros e o conteúdo em primeiro plano mais claro, ou o contrário
      Bom contraste é um desafio em qualquer elemento de design, seja com cor sólida ou efeito de vidro
      A ideia de que o que acontece no fundo distrai e desorienta também é muito subjetiva. Assim como se pode reduzir a opacidade de uma cor sólida, também se pode reduzir a translucidez do vidro
      Essa crítica é difícil de considerar objetivamente verdadeira, e há maneiras de integrar esse elemento de design evitando esses problemas. A captura de tela do Forza parece boa e, quando vi na prática, o fundo também não distraía. Em vez disso, você ganha uma UI mais interessante e visualmente agradável do que um fundo sólido. Isso pode ser mais importante em videogames, mas também pode ser usado com elegância em design de OS e web
    • O desfoque é uma forma de ocultar informação preservando o contexto na medida em que ele pode ser controlado
      Se você precisa de muito contexto, o desfoque não é uma boa escolha; se não precisa de contexto nenhum, também não é uma boa escolha
      Mas, às vezes, ele é uma excelente escolha
  • O exemplo interativo é bom, mas teria sido ainda melhor se houvesse um toggle para comparar lado a lado com a etapa anterior ou alternar entre elas
    Na maioria das etapas, a melhoria era sutil demais para perceber a diferença

    • Concordo. No celular, depois da segunda etapa, a diferença quase não aparece, ou nem dá para perceber
  • Há uns 10 efeitos sobrepostos, e, a menos que o objetivo seja atingir a estética mais exigente possível, uns 7 deles são exagero
    Bastaria usar cor de fundo, desfoque e talvez sombra ou borda

    • Quem quiser um efeito de vidro menos pesado pode escolher partes do tutorial
      Já na terceira etapa, só com desfoque e sombra, sai um pedaço de vidro bem decente. Pessoalmente, eu recomendaria misturar a isso uma imagem estática de raios de luz. Acho que a maioria das aplicações não precisa do efeito completo em JavaScript. É divertido, mas pode distrair
      Só com desfoque, sombra e raios de luz, já dá para chegar bem perto da imagem do Forza lá de cima
    • É interessante que a maioria dos comentários acima fale de desperdício
      Acho que esse foi um dos motivos pelos quais todo mundo foi para o flat design. O Windows Vista e o efeito de vidro eram bonitos, mas tinham um custo computacional alto
      O flat design é esteticamente controverso e, especialmente para usuários mais velhos, pode ser mais difícil de usar do que o design esqueumórfico [0][1]
      Se o realismo pode ajudar na usabilidade, acho perfeitamente razoável usar efeitos como esse na web
      [0]: https://www.tandfonline.com/doi/abs/10.1080/0144929X.2020.18...
      [1]: https://www.sciencedirect.com/science/article/abs/pii/S01419...
    • Fico curioso para saber por que o limite dos efeitos sobrepostos seria n <= 3
      Não sei se é uma questão de acessibilidade, desempenho, manutenção ou outro motivo
      Entre minhas habilidades de desenvolvimento, CSS é de longe a mais fraca, então estou totalmente sem noção sobre boas e más práticas
    • Você não deixou passar a parte em que o autor explicou que o objetivo era a estética mais exigente possível?
  • É interessante porque parece que demos uma volta completa
    Uma das primeiras demos de CSS, uma demo para CSS 1, era um efeito de vidro fosco: https://meyerweb.com/eric/css/edge/complexspiral/glassy.html

  • Sinceramente, é bem impressionante. É sempre um prazer ver o quanto CSS pode ser criativo e poderoso
    Mas sinto que há um nível em HTML/CSS que nunca vou entender. Esta demo é exatamente isso: essa pessoa está criando uma janela fosca, enquanto eu ainda não consigo centralizar uma única div

    • Quando eu estava aprendendo como desenvolvimento web funciona, aprendi do jeito difícil que adicionar mais uma div muitas vezes é uma boa ideia
      Se você olhar para a maioria dos sites modernos, vai ver divs empilhadas como uma pilha enorme. Se quiser uma div centralizada, fica relativamente fácil criar dentro dela mais uma div que ocupe todo o espaço a ser centralizado
      Muitos truques visuais são parecidos, mas este exemplo é muito limpo, o que o torna ainda mais impressionante
  • Não é exatamente vidro fosco, mas experimentei colocar um efeito de vidro na barra lateral de https://www.gyan.dev/ffmpeg/builds/

    • No PC, o site fica muito confortável e bonito de ver