Houdini: quizás el desarrollo más emocionante en CSS del que nunca has oído hablar
Publicado: 2022-03-10¿Alguna vez ha querido usar una función CSS en particular pero no lo hizo porque no era totalmente compatible con todos los navegadores ? O, peor aún, era compatible con todos los navegadores, pero el soporte tenía errores, era inconsistente o incluso completamente incompatible. Si esto te ha sucedido, y apuesto a que sí, entonces deberías preocuparte por Houdini.
Houdini es un nuevo grupo de trabajo del W3C cuyo objetivo final es hacer que este problema desaparezca para siempre. Planea hacerlo mediante la introducción de un nuevo conjunto de API que, por primera vez, brindará a los desarrolladores el poder de extender CSS y las herramientas para conectarse con el proceso de estilo y diseño del motor de renderizado de un navegador .
Lectura adicional en SmashingMag:
- Por qué debería dejar de instalar su entorno WebDev localmente
- El futuro de CSS: propiedades experimentales de CSS
- 53 técnicas CSS sin las que no podrías vivir
Pero, ¿qué significa eso, específicamente? ¿Es siquiera una buena idea? ¿Y cómo nos ayudará a los desarrolladores a crear sitios web ahora y en el futuro?
En este artículo, voy a tratar de responder a estas preguntas. Pero antes de hacerlo, es importante dejar en claro cuáles son los problemas actuales y por qué hay tanta necesidad de cambio. Luego hablaré más específicamente sobre cómo Houdini resolverá estos problemas y enumeraré algunas de las funciones más interesantes que se encuentran actualmente en desarrollo. Por último, ofreceré algunas cosas concretas que nosotros, como desarrolladores web, podemos hacer hoy para ayudar a que Houdini sea una realidad.
¿Qué problemas está tratando de resolver Houdini?
Cada vez que escribo un artículo o construyo una demostración mostrando alguna característica CSS completamente nueva, inevitablemente alguien en los comentarios o en Twitter dirá algo como: “¡Esto es increíble! Lástima que no podremos usarlo durante otros 10 años”.
Por molestos y poco constructivos que sean comentarios como este, entiendo el sentimiento. Históricamente, las propuestas de funciones han tardado años en obtener una adopción generalizada. Y la razón es que, a lo largo de la historia de la web, la única forma de agregar una nueva función a CSS era pasar por el proceso de estándares.

Si bien no tengo absolutamente nada en contra del proceso de estándares, ¡no se puede negar que puede llevar mucho tiempo!
Por ejemplo, flexbox se propuso por primera vez en 2009, y los desarrolladores todavía se quejan de que no pueden usarlo hoy en día debido a la falta de compatibilidad con el navegador. De acuerdo, este problema está desapareciendo lentamente porque casi todos los navegadores modernos ahora se actualizan automáticamente; pero incluso con los navegadores modernos, siempre habrá un retraso entre la propuesta y la disponibilidad general de una característica.
Curiosamente, este no es el caso en todas las áreas de la web. Considere cómo han funcionado las cosas recientemente en JavaScript:

En este escenario, el tiempo entre tener una idea y llegar a utilizarla en producción a veces puede ser cuestión de días. Quiero decir, ya estoy usando las funciones async
/ await
en producción, ¡y esa función no se ha implementado ni en un solo navegador!
También puede ver una gran diferencia en los sentimientos generales de estas dos comunidades. En la comunidad de JavaScript, lee artículos en los que la gente se queja de que las cosas van demasiado rápido. En CSS, por otro lado, escuchas a las personas lamentarse de la futilidad de aprender algo nuevo debido al tiempo que pasará antes de que puedan usarlo.
Entonces, ¿por qué no escribimos más Polyfills CSS?
A primera vista, escribir más polyfills CSS podría parecer la respuesta. Con buenos polyfills, CSS podría moverse tan rápido como JavaScript, ¿verdad?
Lamentablemente, no es tan simple. Polyfilling CSS es increíblemente difícil y, en la mayoría de los casos, imposible de hacer de una manera que no destruya por completo el rendimiento.
JavaScript es un lenguaje dinámico, lo que significa que puede usar JavaScript para polirellenar JavaScript. Y debido a que es tan dinámico, es extremadamente extensible. CSS, por otro lado, rara vez se puede usar para rellenar CSS. En algunos casos, puede transpilar CSS a CSS en un paso de compilación (PostCSS hace esto); pero si desea policompletar cualquier cosa que dependa de la estructura del DOM o del diseño o la posición de un elemento, entonces tendrá que ejecutar la lógica del polirrelleno del lado del cliente.
Desafortunadamente, el navegador no lo hace fácil.
El cuadro a continuación brinda un resumen básico de cómo su navegador pasa de recibir un documento HTML a mostrar píxeles en la pantalla. Los pasos coloreados en azul muestran dónde JavaScript tiene el poder de controlar los resultados:

El panorama es bastante sombrío. Como desarrollador, no tiene control sobre cómo el navegador analiza HTML y CSS y lo convierte en el modelo de objetos DOM y CSS (CSSOM). No tienes control sobre la cascada. No tienes control sobre cómo el navegador elige diseñar los elementos en el DOM o cómo pinta esos elementos visualmente en la pantalla. Y no tienes control sobre lo que hace el compositor.
La única parte del proceso a la que tiene acceso completo es el DOM. El CSSOM es algo abierto; sin embargo, para citar el sitio web de Houdini, es "poco especificado, inconsistente entre navegadores y faltan funciones críticas".
Por ejemplo, el CSSOM en los navegadores actuales no le mostrará reglas para hojas de estilo de origen cruzado, y simplemente descartará cualquier regla o declaración CSS que no entienda, lo que significa que si desea policompletar una función en un navegador que no lo admite, no puede usar el CSSOM. En su lugar, debe pasar por el DOM, encontrar las etiquetas <style>
y/o <link rel=“stylesheet”>
, obtener el CSS usted mismo, analizarlo, reescribirlo y luego volver a agregarlo al DOM.
Por supuesto, actualizar el DOM generalmente significa que el navegador tiene que pasar por todos los pasos de cascada, diseño, pintura y composición nuevamente.

Si bien tener que volver a renderizar completamente una página puede no parecer un gran impacto en el rendimiento (especialmente para algunos sitios web), considere la frecuencia con la que esto tiene que suceder. Si la lógica de su polyfill necesita ejecutarse en respuesta a cosas como eventos de desplazamiento, cambio de tamaño de la ventana, movimientos del mouse, eventos del teclado, realmente en cualquier momento que cambie, entonces las cosas serán notablemente, a veces incluso abrumadoramente lentas.
Esto empeora aún más cuando te das cuenta de que la mayoría de los polyfills CSS que existen hoy en día incluyen su propio analizador CSS y su propia lógica en cascada. Y debido a que el análisis y la cascada son en realidad cosas muy complicadas, estos rellenos polifónicos suelen ser demasiado grandes o demasiado defectuosos.
Para resumir todo lo que acabo de decir de manera más concisa: si desea que el navegador haga algo diferente de lo que cree que debe hacer (dado el CSS que le dio), entonces debe encontrar una manera de falsificarlo actualizando y modificando el DOM usted mismo. No tiene acceso a los demás pasos de la canalización de representación.
Pero, ¿por qué querría modificar el motor de renderizado interno del navegador?
Esta, para mí, es absolutamente la pregunta más importante a responder en todo este artículo. Entonces, si has estado hojeando las cosas hasta ahora, ¡lee esta parte despacio y con cuidado!
Después de leer la última sección, estoy seguro de que algunos de ustedes estaban pensando: “¡No necesito esto! Solo estoy creando páginas web normales. No estoy tratando de piratear las partes internas del navegador o construir algo súper elegante, experimental o de última generación”.
Si está pensando eso, le recomiendo encarecidamente que retroceda un segundo y examine realmente las tecnologías que ha estado utilizando para crear sitios web a lo largo de los años. Querer acceso y enlaces al proceso de estilo del navegador no se trata solo de crear demostraciones elegantes, se trata de dar a los desarrolladores y autores de marcos el poder de hacer dos cosas principales:
- para normalizar las diferencias entre navegadores,
- para inventar o polillenar nuevas características para que la gente pueda usarlas hoy.
Si alguna vez ha utilizado una biblioteca de JavaScript como jQuery, ¡entonces ya se ha beneficiado de esta capacidad! De hecho, este es uno de los principales puntos de venta de casi todas las bibliotecas y marcos front-end en la actualidad. Los cinco repositorios de JavaScript y DOM más populares en GitHub (AngularJS, D3, jQuery, React y Ember) trabajan mucho para normalizar las diferencias entre navegadores para que no tengas que pensar en ello. Cada uno expone una sola API, y simplemente funciona.
Ahora, piense en CSS y todos sus problemas entre navegadores. Incluso los marcos CSS populares como Bootstrap y Foundation que afirman la compatibilidad entre navegadores en realidad no normalizan los errores entre navegadores, simplemente los evitan. Y los errores de navegador cruzado en CSS no son solo una cosa del pasado. Incluso hoy, con nuevos módulos de diseño como flexbox, enfrentamos muchas incompatibilidades entre navegadores.
La conclusión es, imagina cuánto mejor sería tu vida de desarrollo si pudieras usar cualquier propiedad CSS y saber con certeza que funcionará, exactamente igual, en todos los navegadores. Y piense en todas las nuevas funciones que lee en las publicaciones de blog o escucha en conferencias y reuniones, cosas como cuadrículas CSS, puntos de ajuste CSS y posicionamiento fijo. Imagínese si pudiera usarlos todos hoy y de una manera que tuviera el mismo rendimiento que las características nativas de CSS. Y todo lo que necesita hacer es obtener el código de GitHub.

Este es el sueño de Houdini. Este es el futuro que el grupo de trabajo está tratando de hacer posible.
Por lo tanto, incluso si nunca planea escribir un polyfill CSS o desarrollar una función experimental, probablemente querrá que otras personas puedan hacerlo, porque una vez que existen estos polyfill, todos se benefician de ellos.
¿Qué características de Houdini están actualmente en desarrollo?
Mencioné anteriormente que los desarrolladores tienen muy pocos puntos de acceso a la canalización de representación del navegador. Realmente, los únicos lugares son el DOM y, hasta cierto punto, el CSSOM.
Para resolver este problema, el grupo de trabajo de Houdini ha introducido varias especificaciones nuevas que, por primera vez, darán acceso a los desarrolladores a las otras partes de la canalización de renderizado. El gráfico a continuación muestra la canalización y qué nuevas especificaciones se pueden usar para modificar qué pasos. (Tenga en cuenta que las especificaciones en gris están planificadas pero aún no se han escrito).

Las siguientes secciones brindan una breve descripción general de cada nueva especificación y qué tipo de capacidades ofrece. También debo señalar que otras especificaciones no se mencionan en este artículo; para ver la lista completa, consulte el repositorio de GitHub de los borradores de Houdini.
API del analizador de CSS
La API de CSS Parser no está escrita actualmente; por lo tanto, gran parte de lo que digo podría cambiar fácilmente, pero la idea básica es que permite a los desarrolladores ampliar el analizador CSS e informarle sobre nuevas construcciones, por ejemplo, nuevas reglas de medios, nuevas pseudoclases, anidamiento, @extends
, @apply
, etc
Una vez que el analizador conoce estas nuevas construcciones, puede colocarlas en el lugar correcto en el CSSOM, en lugar de simplemente descartarlas.
API de propiedades y valores de CSS
CSS ya tiene propiedades personalizadas y, como he expresado antes, estoy muy entusiasmado con las posibilidades que abren. La API de propiedades y valores de CSS lleva las propiedades personalizadas un paso más allá y las hace aún más útiles al agregar tipos.
Hay muchas cosas buenas acerca de agregar tipos a las propiedades personalizadas, pero quizás el punto de venta más importante es que los tipos permitirán a los desarrolladores hacer la transición y animar las propiedades personalizadas, algo que no podemos hacer hoy.
Considere este ejemplo:
body { --primary-theme-color: tomato; transition: --primary-theme-color 1s ease-in-out; } body.night-theme { --primary-theme-color: darkred; }
En el código anterior, si la clase night-theme
se agrega al elemento <body>
, entonces cada elemento en la página que hace referencia al valor de la propiedad darkred
–primary-theme-color
cambiará lentamente de tomato
a rojo oscuro. Si quisiera hacer esto hoy, tendría que escribir la transición para cada uno de estos elementos manualmente, porque no puede hacer la transición de la propiedad en sí.
Otra característica prometedora de esta API es la capacidad de registrar un "gancho de aplicación", que brinda a los desarrolladores una forma de modificar el valor final de una propiedad personalizada en los elementos después de que se haya completado el paso en cascada, lo que podría ser una característica muy útil para polyfills.
OM escrito con CSS
CSS Typed OM se puede considerar como la versión 2 del CSSOM actual. Su objetivo es resolver muchos de los problemas con el modelo actual e incluir funciones agregadas por la nueva API de análisis de CSS y la API de propiedades y valores de CSS.
Otro objetivo importante de Typed OM es mejorar el rendimiento. La conversión de los valores de cadena del CSSOM actual en representaciones de JavaScript tipificadas de manera significativa generaría ganancias de rendimiento sustanciales.
API de diseño CSS
La API de diseño de CSS permite a los desarrolladores escribir sus propios módulos de diseño. Y por "módulo de diseño", me refiero a cualquier cosa que se pueda pasar a la propiedad de display
CSS. Esto brindará a los desarrolladores, por primera vez, una forma de diseño que tiene el mismo rendimiento que los módulos de diseño nativos, como display: flex
y display: table
.
Como ejemplo de caso de uso, la biblioteca de diseño Masonry muestra hasta qué punto los desarrolladores están dispuestos a llegar hoy para lograr diseños complejos que no son posibles solo con CSS. Si bien estos diseños son impresionantes, lamentablemente sufren problemas de rendimiento, especialmente en dispositivos menos potentes.
La API de diseño de CSS funciona brindando a los desarrolladores un método registerLayout
que acepta un nombre de diseño (que luego se usa en CSS) y una clase de JavaScript que incluye toda la lógica del diseño. Aquí hay un ejemplo básico de cómo puede definir masonry
a través de 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. } }
Si nada en el ejemplo anterior tiene sentido para usted, no se preocupe. Lo más importante a tener en cuenta es el código del siguiente ejemplo. Una vez que haya descargado el archivo masonry.js
y lo haya agregado a su sitio web, puede escribir CSS así y todo funcionará:
body { display: layout('masonry'); }
API de pintura CSS
La API de CSS Paint es muy similar a la API de diseño anterior. Proporciona un método registerPaint
que funciona igual que el método registerLayout
. Luego, los desarrolladores pueden usar la función paint()
en CSS en cualquier lugar donde se espere una imagen CSS y pasar el nombre que se registró.
Aquí hay un ejemplo simple que pinta un círculo de color:
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(); } });
Y se puede usar en CSS así:
.bubble { --circle-color: blue; background-image: paint('circle'); }
Ahora, el elemento .bubble
se mostrará con un círculo azul como fondo. El círculo estará centrado y tendrá el mismo tamaño que el elemento en sí, sea lo que sea.
Hojas de trabajo
Muchas de las especificaciones enumeradas anteriormente muestran ejemplos de código (por ejemplo, registerLayout
y registerPaint
). Si se pregunta dónde colocaría ese código, la respuesta está en los scripts de worklet.
Los worklets son similares a los trabajadores web y le permiten importar archivos de secuencias de comandos y ejecutar código JavaScript que (1) se puede invocar en varios puntos de la canalización de representación y (2) es independiente del subproceso principal.
Los scripts de Worklet restringirán en gran medida los tipos de operaciones que puede realizar, lo cual es clave para garantizar un alto rendimiento.
Desplazamiento compuesto y animación
Aunque todavía no hay una especificación oficial para el desplazamiento y la animación compuestos, en realidad es una de las funciones de Houdini más conocidas y esperadas. Las eventuales API permitirán a los desarrolladores ejecutar la lógica en un worklet de compositor, fuera del hilo principal, con soporte para la modificación de un subconjunto limitado de propiedades de un elemento DOM. Este subconjunto solo incluirá propiedades que se puedan leer o establecer sin obligar al motor de representación a volver a calcular el diseño o el estilo (por ejemplo, transformación, opacidad, desplazamiento de desplazamiento).
Esto permitirá a los desarrolladores crear animaciones basadas en entrada y desplazamiento de alto rendimiento, como encabezados de desplazamiento fijos y efectos de paralaje. Puede leer más sobre los casos de uso que estas API intentan resolver en GitHub.
Si bien aún no hay una especificación oficial, el desarrollo experimental ya comenzó en Chrome. De hecho, el equipo de Chrome actualmente está implementando puntos de ajuste de CSS y posicionamiento fijo utilizando las primitivas que estas API eventualmente expondrán. Esto es sorprendente porque significa que las API de Houdini tienen el rendimiento suficiente como para que se construyan nuevas funciones de Chrome sobre ellas. Si todavía tenía algún temor de que Houdini no fuera tan rápido como el nativo, este solo hecho debería convencerlo de lo contrario.
Para ver un ejemplo real, Surma grabó una demostración en video que se ejecuta en una versión interna de Chrome. La demostración imita el comportamiento del encabezado de desplazamiento que se ve en las aplicaciones móviles nativas de Twitter. Para ver cómo funciona, echa un vistazo al código fuente.
¿Que puedes hacer ahora?
Como se mencionó, creo que todos los que crean sitios web deberían preocuparse por Houdini; va a hacer que todas nuestras vidas sean mucho más fáciles en el futuro. Incluso si nunca usa una especificación de Houdini directamente, es casi seguro que usará algo construido sobre uno.
Y aunque este futuro puede no ser inmediato, probablemente esté más cerca de lo que muchos de nosotros pensamos. Representantes de todos los principales proveedores de navegadores asistieron a la última reunión cara a cara de Houdini en Sídney a principios de este año y hubo muy pocos desacuerdos sobre qué construir o cómo proceder.
Por lo que pude ver, no se trata de si Houdini será una cosa, sino de cuándo, y ahí es donde todos ustedes entran.
Los proveedores de navegadores, como todos los demás que crean software, deben priorizar las nuevas funciones. Y esa prioridad es a menudo una función de cuánto desean los usuarios esas características.
Por lo tanto, si le preocupa la extensibilidad del estilo y el diseño en la web, y si quiere vivir en un mundo en el que pueda usar nuevas funciones de CSS sin tener que esperar a que pasen por el proceso de estándares, hable con los miembros de la equipos de relaciones con los desarrolladores para los navegadores que usa y dígales que quiere esto.
La otra forma en que puede ayudar es proporcionando casos de uso del mundo real: cosas que desea poder hacer con estilo y diseño que son difíciles o imposibles de hacer hoy. Varios de los borradores en GitHub tienen documentos de casos de uso y puede enviar una solicitud de incorporación de cambios para contribuir con sus ideas. Si no existe un documento, puede iniciar uno.
Los miembros del grupo de trabajo de Houdini (y el W3C en general) realmente quieren aportes reflexivos de los desarrolladores web. La mayoría de las personas que participan en el proceso de redacción de especificaciones son ingenieros que trabajan en navegadores. A menudo, no son desarrolladores web profesionales, lo que significa que no siempre saben dónde están los puntos débiles.
Dependen de nosotros para decirles.
Recursos y enlaces
- CSS-TAG Borradores del editor de Houdini, W3C La última versión pública de todos los borradores de Houdini
- CSS-TAG Houdini Task Force Specifications, GitHub El repositorio oficial de Github donde se realizan las actualizaciones y el desarrollo de las especificaciones
- Muestras de Houdini, ejemplos de código de GitHub que muestran y experimentan con posibles API
- Lista de correo de Houdini, W3C Un lugar para hacer preguntas generales
Un agradecimiento especial a los miembros de Houdini Ian Kilpatrick y Shane Stephens por revisar este artículo.