Houdini: Talvez o desenvolvimento mais emocionante em CSS que você nunca ouviu falar
Publicados: 2022-03-10Você já quis usar um recurso CSS específico, mas não o fez porque não era totalmente suportado em todos os navegadores ? Ou, pior, era suportado em todos os navegadores, mas o suporte era bugado, inconsistente ou até mesmo completamente incompatível? Se isso aconteceu com você – e aposto que aconteceu – então você deveria se preocupar com Houdini.
Houdini é uma nova força-tarefa do W3C cujo objetivo final é fazer com que esse problema desapareça para sempre. Ele planeja fazer isso introduzindo um novo conjunto de APIs que, pela primeira vez, dará aos desenvolvedores o poder de estender o próprio CSS e as ferramentas para se conectar ao processo de estilo e layout do mecanismo de renderização de um navegador .
Leitura adicional no SmashingMag:
- Por que você deve parar de instalar seu ambiente WebDev localmente
- O Futuro do CSS: Propriedades Experimentais do CSS
- 53 técnicas CSS que você não poderia viver sem
Mas o que isso significa, especificamente? É mesmo uma boa ideia? E como isso nos ajudará, desenvolvedores, a criar sites agora e no futuro?
Neste artigo, vou tentar responder a essas perguntas. Mas antes disso, é importante deixar claro quais são os problemas hoje e por que há tanta necessidade de mudança. Em seguida, falarei mais especificamente sobre como Houdini resolverá esses problemas e listarei alguns dos recursos mais interessantes atualmente em desenvolvimento. Por último, vou oferecer algumas coisas concretas que nós, como desenvolvedores da Web, podemos fazer hoje para ajudar a tornar o Houdini uma realidade.
Quais problemas Houdini está tentando resolver?
Sempre que escrevo um artigo ou construo uma demonstração mostrando algum novo recurso CSS, inevitavelmente alguém nos comentários ou no Twitter dirá algo como: “Isso é incrível! Pena que não poderemos usá-lo por mais 10 anos.”
Por mais irritantes e pouco construtivos que sejam comentários como esse, eu entendo o sentimento. Historicamente, levou anos para que as propostas de recursos ganhassem ampla adoção. E a razão é que, ao longo da história da web, a única maneira de obter um novo recurso adicionado ao CSS era passar pelo processo de padrões.

Embora eu não tenha absolutamente nada contra o processo de padrões, não há como negar que pode levar muito tempo!
Por exemplo, o flexbox foi proposto pela primeira vez em 2009, e os desenvolvedores ainda reclamam que não podem usá-lo hoje devido à falta de suporte ao navegador. É verdade que esse problema está desaparecendo lentamente porque quase todos os navegadores modernos agora são atualizados automaticamente; mas mesmo com navegadores modernos, sempre haverá um atraso entre a proposta e a disponibilidade geral de um recurso.
Curiosamente, este não é o caso em todas as áreas da web. Considere como as coisas têm funcionado recentemente em JavaScript:

Nesse cenário, o tempo entre ter uma ideia e colocá-la em prática na produção às vezes pode ser uma questão de dias. Quer dizer, eu já estou usando as funções async
/ await
em produção, e esse recurso não foi implementado nem em um único navegador!
Você também pode ver uma enorme diferença nos sentimentos gerais dessas duas comunidades. Na comunidade JavaScript, você lê artigos nos quais as pessoas reclamam que as coisas estão indo rápido demais. Em CSS, por outro lado, você ouve as pessoas lamentando a futilidade de aprender algo novo por causa de quanto tempo levará até que possam realmente usá-lo.
Então, por que não escrevemos mais Polyfills CSS?
À primeira vista, escrever mais polyfills CSS pode parecer a resposta. Com bons polyfills, o CSS pode se mover tão rápido quanto o JavaScript, certo?
Infelizmente, não é tão simples. Polyfilling CSS é incrivelmente difícil e, na maioria dos casos, impossível de fazer de uma forma que não destrua completamente o desempenho.
JavaScript é uma linguagem dinâmica, o que significa que você pode usar JavaScript para polyfill JavaScript. E por ser tão dinâmico, é extremamente extensível. CSS, por outro lado, raramente pode ser usado para polyfill CSS. Em alguns casos, você pode transpilar CSS para CSS em uma etapa de construção (PostCSS faz isso); mas se você quiser polyfill qualquer coisa que dependa da estrutura do DOM ou do layout ou posição de um elemento, você terá que executar a lógica do polyfill do lado do cliente.
Infelizmente, o navegador não torna isso fácil.
O gráfico abaixo fornece um esboço básico de como seu navegador vai desde o recebimento de um documento HTML até a exibição de pixels na tela. As etapas coloridas em azul mostram onde o JavaScript tem o poder de controlar os resultados:

A imagem é bem sombria. Como desenvolvedor, você não tem controle sobre como o navegador analisa HTML e CSS e os transforma no modelo de objeto DOM e CSS (CSSOM). Você não tem controle sobre a cascata. Você não tem controle sobre como o navegador escolhe dispor os elementos no DOM ou como ele pinta esses elementos visualmente na tela. E você não tem controle sobre o que o compositor faz.
A única parte do processo à qual você tem acesso total é o DOM. O CSSOM é um pouco aberto; no entanto, para citar o site da Houdini, ele é “subespecificado, inconsistente entre navegadores e faltando recursos críticos”.
Por exemplo, o CSSOM nos navegadores de hoje não mostrará regras para folhas de estilo de origem cruzada e simplesmente descartará quaisquer regras ou declarações CSS que não entenda, o que significa que, se você quiser preencher um recurso em um navegador que não suporta, você não pode usar o CSSOM. Em vez disso, você precisa passar pelo DOM, encontrar as tags <style>
e/ou <link rel=“stylesheet”>
, obter o CSS você mesmo, analisá-lo, reescrevê-lo e adicioná-lo de volta ao DOM.
É claro que atualizar o DOM geralmente significa que o navegador precisa passar por todas as etapas de cascata, layout, pintura e composição novamente.

Embora ter que rerenderizar completamente uma página possa não parecer um grande impacto no desempenho (especialmente para alguns sites), considere com que frequência isso tem que acontecer. Se a lógica do seu polyfill precisa ser executada em resposta a coisas como eventos de rolagem, redimensionamento de janela, movimentos do mouse, eventos de teclado - realmente a qualquer momento, qualquer coisa muda - então as coisas serão notavelmente, às vezes até incapacitantes, lentas.
Isso fica ainda pior quando você percebe que a maioria dos polyfills CSS disponíveis hoje incluem seu próprio analisador CSS e sua própria lógica em cascata. E como a análise e a cascata são realmente coisas muito complicadas, esses polyfills geralmente são muito grandes ou muito problemáticos.
Para resumir tudo o que eu disse de forma mais concisa: Se você quer que o navegador faça algo diferente do que ele pensa que deve fazer (dado o CSS que você deu), então você tem que descobrir uma maneira de fingir atualizando e modificando o DOM você mesmo. Você não tem acesso às outras etapas no pipeline de renderização.
Mas por que eu iria querer modificar o mecanismo de renderização interno do navegador?
Esta, para mim, é absolutamente a pergunta mais importante a ser respondida em todo este artigo. Então, se você está folheando as coisas até agora, leia esta parte devagar e com cuidado!
Depois de ver a última seção, tenho certeza de que alguns de vocês estavam pensando: “Não preciso disso! Estou apenas construindo páginas da web normais. Não estou tentando invadir os componentes internos do navegador ou construir algo super chique, experimental ou de ponta.”
Se você está pensando isso, então eu recomendo fortemente que você dê um passo atrás por um segundo e realmente examine as tecnologias que você tem usado para construir sites ao longo dos anos. Querer acesso e ganchos no processo de estilo do navegador não se trata apenas de construir demonstrações sofisticadas — trata-se de dar aos desenvolvedores e autores de framework o poder de fazer duas coisas principais:
- para normalizar as diferenças entre navegadores,
- para inventar ou preencher novos recursos para que as pessoas possam usá-los hoje.
Se você já usou uma biblioteca JavaScript como jQuery, já se beneficiou dessa capacidade! Na verdade, esse é um dos principais pontos de venda de quase todas as bibliotecas e frameworks front-end atuais. Os cinco repositórios JavaScript e DOM mais populares no GitHub — AngularJS, D3, jQuery, React e Ember — todos fazem muito trabalho para normalizar as diferenças entre navegadores para que você não precise pensar nisso. Cada um expõe uma única API, e ela simplesmente funciona.
Agora, pense no CSS e em todos os seus problemas entre navegadores. Mesmo frameworks CSS populares, como Bootstrap e Foundation, que alegam compatibilidade entre navegadores, não normalizam bugs entre navegadores - eles apenas os evitam. E bugs entre navegadores em CSS não são apenas uma coisa do passado. Ainda hoje, com novos módulos de layout como o flexbox, enfrentamos muitas incompatibilidades entre navegadores.
A linha inferior é, imagine o quão melhor seria sua vida de desenvolvimento se você pudesse usar qualquer propriedade CSS e saber com certeza que iria funcionar, exatamente da mesma forma, em todos os navegadores. E pense em todos os novos recursos que você lê nas postagens do blog ou ouve falar em conferências e encontros - coisas como grades CSS, pontos de snap CSS e posicionamento fixo. Imagine se você pudesse usar todos eles hoje e de uma maneira que fosse tão eficiente quanto os recursos CSS nativos. E tudo que você precisa fazer é pegar o código do GitHub.

Este é o sonho de Houdini. Este é o futuro que a força-tarefa está tentando tornar possível.
Portanto, mesmo que você nunca planeje escrever um polyfill CSS ou desenvolver um recurso experimental, provavelmente gostaria que outras pessoas pudessem fazê-lo – porque uma vez que esses polyfills existam, todos se beneficiarão deles.
Quais recursos Houdini estão atualmente em desenvolvimento?
Mencionei acima que os desenvolvedores têm muito poucos pontos de acesso no pipeline de renderização do navegador. Realmente, os únicos lugares são o DOM e, até certo ponto, o CSSOM.
Para resolver esse problema, a força-tarefa Houdini introduziu várias novas especificações que, pela primeira vez, darão aos desenvolvedores acesso a outras partes do pipeline de renderização. O gráfico abaixo mostra o pipeline e quais novas especificações podem ser usadas para modificar quais etapas. (Observe que as especificações em cinza estão planejadas, mas ainda precisam ser escritas.)

As próximas seções fornecem uma breve visão geral de cada nova especificação e quais tipos de recursos ela oferece. Devo também observar que outras especificações não são mencionadas neste artigo; para a lista completa, veja o repositório GitHub dos rascunhos de Houdini.
API do analisador de CSS
A API do Analisador de CSS não está gravada no momento; então, muito do que eu digo pode mudar facilmente, mas a ideia básica é que ele permite que os desenvolvedores estendam o analisador CSS e falem sobre novas construções — por exemplo, novas regras de mídia, novas pseudoclasses, aninhamento, @extends
, @apply
, etc
Assim que o analisador souber sobre essas novas construções, ele poderá colocá-las no lugar certo no CSSOM, em vez de apenas descartá-las.
API de propriedades e valores CSS
CSS já tem propriedades personalizadas e, como já disse antes, estou muito empolgado com as possibilidades que elas abrem. A API CSS Properties and Values leva as propriedades personalizadas um passo adiante e as torna ainda mais úteis ao adicionar tipos.
Há muitas coisas boas em adicionar tipos a propriedades personalizadas, mas talvez o maior ponto de venda seja que os tipos permitirão aos desenvolvedores fazer a transição e animar propriedades personalizadas, algo que não podemos fazer hoje.
Considere este exemplo:
body { --primary-theme-color: tomato; transition: --primary-theme-color 1s ease-in-out; } body.night-theme { --primary-theme-color: darkred; }
No código acima, se a classe night-theme
for adicionada ao elemento <body>
, cada elemento na página que fizer referência ao valor da propriedade –primary-theme-color
fará uma transição lenta de tomato
para darkred
. Se você quisesse fazer isso hoje, teria que escrever a transição para cada um desses elementos manualmente, porque não é possível fazer a transição da propriedade em si.
Outro recurso promissor dessa API é a capacidade de registrar um “apply hook”, que dá aos desenvolvedores uma maneira de modificar o valor final de uma propriedade personalizada em elementos após a conclusão da etapa de cascata, o que pode ser um recurso muito útil para polyfills.
OM digitado em CSS
O CSS Typed OM pode ser considerado a versão 2 do CSSOM atual. Seu objetivo é resolver muitos dos problemas com o modelo atual e incluir recursos adicionados pela nova CSS Parsing API e CSS Properties and Values API.
Outro objetivo principal do Typed OM é melhorar o desempenho. A conversão dos valores de string do CSSOM atual em representações JavaScript tipadas de forma significativa renderia ganhos de desempenho substanciais.
API de layout CSS
A API de layout CSS permite que os desenvolvedores escrevam seus próprios módulos de layout. E por “módulo de layout”, quero dizer qualquer coisa que possa ser passada para a propriedade de display
CSS. Isso dará aos desenvolvedores, pela primeira vez, uma maneira de layout com desempenho tão bom quanto os módulos de layout nativos, como display: flex
e display: table
.
Como um exemplo de caso de uso, a biblioteca de layout Masonry mostra até que ponto os desenvolvedores estão dispostos a ir hoje para obter layouts complexos que não são possíveis apenas com CSS. Embora esses layouts sejam impressionantes, infelizmente, eles sofrem com problemas de desempenho, especialmente em dispositivos menos potentes.
A API de layout CSS funciona fornecendo aos desenvolvedores um método registerLayout
que aceita um nome de layout (que é usado posteriormente em CSS) e uma classe JavaScript que inclui toda a lógica de layout. Aqui está um exemplo básico de como você pode definir masonry
via registerLayout
:
registerLayout('masonry', class { static get inputProperties() { return ['width', 'height'] } static get childrenInputProperties() { return ['x', 'y', 'position'] } layout(children, constraintSpace, styleMap, breakToken) { // Layout logic goes here. } }
Se nada no exemplo acima fizer sentido para você, não se preocupe. A principal coisa a se preocupar é o código no próximo exemplo. Depois de baixar o arquivo masonry.js
e adicioná-lo ao seu site, você pode escrever CSS assim e tudo funcionará:
body { display: layout('masonry'); }
API de pintura CSS
A API CSS Paint é muito semelhante à API Layout acima. Ele fornece um método registerPaint
que opera exatamente como o método registerLayout
. Os desenvolvedores podem então usar a função paint()
em CSS em qualquer lugar que uma imagem CSS seja esperada e passar o nome que foi registrado.
Aqui está um exemplo simples que pinta um círculo colorido:
registerPaint('circle', class { static get inputProperties() { return ['--circle-color']; } paint(ctx, geom, properties) { // Change the fill color. const color = properties.get('--circle-color'); ctx.fillStyle = color; // Determine the center point and radius. const x = geom.width / 2; const y = geom.height / 2; const radius = Math.min(x, y); // Draw the circle \o/ ctx.beginPath(); ctx.arc(x, y, radius, 0, 2 * Math.PI, false); ctx.fill(); } });
E pode ser usado em CSS assim:
.bubble { --circle-color: blue; background-image: paint('circle'); }
Agora, o elemento .bubble
será exibido com um círculo azul como plano de fundo. O círculo será centrado e do mesmo tamanho que o próprio elemento, seja lá o que for.
Worklets
Muitas das especificações listadas acima mostram exemplos de código (por exemplo, registerLayout
e registerPaint
). Se você está se perguntando onde colocaria esse código, a resposta está nos scripts de worklet.
Worklets são semelhantes aos web workers e permitem importar arquivos de script e executar código JavaScript que (1) pode ser invocado em vários pontos no pipeline de renderização e (2) é independente do thread principal.
Os scripts de worklet restringirão fortemente os tipos de operações que você pode fazer, o que é fundamental para garantir alto desempenho.
Rolagem composta e animação
Embora ainda não haja uma especificação oficial para rolagem composta e animação, na verdade é um dos recursos Houdini mais conhecidos e altamente esperados. As APIs eventuais permitirão que os desenvolvedores executem a lógica em um worklet de composição, fora do thread principal, com suporte para modificação de um subconjunto limitado de propriedades de um elemento DOM. Esse subconjunto incluirá apenas propriedades que podem ser lidas ou definidas sem forçar o mecanismo de renderização a recalcular o layout ou o estilo (por exemplo, transformar, opacidade, deslocamento de rolagem).
Isso permitirá que os desenvolvedores criem animações baseadas em rolagem e entrada de alto desempenho, como cabeçalhos de rolagem fixos e efeitos de paralaxe. Você pode ler mais sobre os casos de uso que essas APIs estão tentando resolver no GitHub.
Embora ainda não haja uma especificação oficial, o desenvolvimento experimental já começou no Chrome. Na verdade, a equipe do Chrome está atualmente implementando pontos de encaixe CSS e posicionamento fixo usando as primitivas que essas APIs eventualmente exporão. Isso é incrível porque significa que as APIs Houdini têm desempenho suficiente para que novos recursos do Chrome sejam construídos sobre elas. Se você ainda tem algum medo de que Houdini não seja tão rápido quanto nativo, esse fato por si só deve convencê-lo do contrário.
Para ver um exemplo real, Surma gravou um vídeo de demonstração rodando em uma versão interna do Chrome. A demonstração imita o comportamento do cabeçalho de rolagem visto nos aplicativos móveis nativos do Twitter. Para ver como funciona, confira o código-fonte.
O que você pode fazer agora?
Como mencionado, acho que todos que constroem sites devem se preocupar com Houdini; vai tornar a nossa vida muito mais fácil no futuro. Mesmo que você nunca use uma especificação Houdini diretamente, você quase certamente usará algo construído em cima de uma.
E embora esse futuro possa não ser imediato, provavelmente está mais próximo do que muitos de nós pensamos. Representantes de todos os principais fornecedores de navegadores estiveram na última reunião presencial de Houdini em Sydney no início deste ano, e houve muito pouco desacordo sobre o que construir ou como proceder.
Pelo que pude dizer, não é uma questão de se Houdini será uma coisa, mas quando, e é aí que todos vocês entram.
Os fornecedores de navegadores, como todos os outros que criam software, precisam priorizar novos recursos. E essa prioridade geralmente é uma função do quanto os usuários desejam esses recursos.
Então, se você se preocupa com a extensibilidade de estilo e layout na web, e se você quer viver em um mundo onde você pode usar novos recursos CSS sem ter que esperar que eles passem pelo processo de padrões, fale com membros do equipes de relações com o desenvolvedor para o(s) navegador(es) que você usa e diga a eles que você deseja isso.
A outra maneira de ajudar é fornecendo casos de uso do mundo real — coisas que você deseja fazer com estilo e layout que são difíceis ou impossíveis de fazer hoje. Vários dos rascunhos no GitHub têm documentos de caso de uso e você pode enviar uma solicitação de pull para contribuir com suas ideias. Se um documento não existir, você poderá iniciar um.
Os membros da força-tarefa Houdini (e do W3C em geral) realmente querem uma contribuição cuidadosa dos desenvolvedores da web. A maioria das pessoas que participam do processo de redação de especificações são engenheiros que trabalham em navegadores. Eles geralmente não são desenvolvedores web profissionais, o que significa que nem sempre sabem onde estão os pontos problemáticos.
Eles dependem de nós para lhes dizer.
Recursos e links
- CSS-TAG Houdini Editor Drafts, W3C A última versão pública de todos os rascunhos Houdini
- CSS-TAG Houdini Task Force Specifications, GitHub O repositório oficial do Github onde ocorrem atualizações e desenvolvimento de especificações
- Amostras de Houdini, exemplos de código do GitHub mostrando e experimentando possíveis APIs
- Lista de discussão Houdini, W3C Um lugar para fazer perguntas gerais
Agradecimentos especiais aos membros do Houdini, Ian Kilpatrick e Shane Stephens, pela revisão deste artigo.