Houdini: Desmitificación de CSS

¿Alguna vez pensaste en la cantidad de trabajo que realiza CSS? Cambias un solo y, de repente, todo tu sitio web aparece en un diseño diferente. Es algo así como magia. Hasta ahora, nosotros, la comunidad de desarrolladores web, que solo pudieron presenciar y observar la magia. ¿Qué pasa si queremos encontrar nuestra propia magia? ¿Y si queremos convertirnos en mago?

¡Conoce a Houdini!

El grupo de trabajo de Houdini está formado por ingenieros de Mozilla, Apple, Opera, Microsoft, HP, Intel y Google trabajan en conjunto para exponer ciertas partes de la de CSS Engine a los desarrolladores web. El grupo de trabajo está trabajando en una colección de borradores con el objetivo de que W3C los acepte para que se conviertan en sitios web reales con los estándares necesarios. Se establecieron algunos objetivos de alto nivel y los convirtieron en borradores de especificaciones que, a su vez, dieron origen a un conjunto de material de apoyo, borradores de especificaciones de nivel inferior.

La colección de estos borradores es lo que generalmente se hace cuando alguien habla de "Houdini". Al momento de la redacción, la lista de borradores es incompletos y algunos de los borradores son simples marcadores de posición.

Las especificaciones

Worklets (spec)

Los Worklets por sí solos no son muy útiles. Son un concepto que se presenta posibilitan muchos de los borradores posteriores. Si pensaste en los trabajadores web cuando “worklet”, no estás equivocado. Tienen mucha superposición conceptual. ¿Por qué algo nuevo cuando ya tenemos trabajadores?

El objetivo de Houdini es exponer nuevas APIs para permitir que los desarrolladores web conecten su propio código al motor de CSS y al los sistemas circundantes. Probablemente no sea poco realista suponer que algunos de estos los fragmentos de código se deberán ejecutar todas. único. fotograma. Algunos tienen que por definición. Cita de la especificación de Web Worker:

Esto significa que los trabajadores web no son viables para lo que Houdini planea hacer. Por lo tanto, se inventaron los worklets. Los Worklets usan clases ES2015 para definir un conjunto de métodos cuyas firmas están predefinidas por el tipo del worklet. Son ligeros y de corta duración.

API de pintura de CSS (spec)

La API de Paint está habilitada de forma predeterminada en Chrome 65. Lee el introducción detallada.

Worklet del compositor

La API descrita aquí es obsoleta. El worklet del compositor tiene se rediseñó y ahora se propone como "Worklet de animación". Obtén más información en el iteración actual de la API.

Aunque la especificación del worklet del compositor se ha trasladado al WICG y es la que más me entusiasma. Algunos las operaciones se externalizan a la tarjeta gráfica de tu computadora por el CSS automático, aunque eso depende tanto de la tarjeta gráfica como del dispositivo general.

Un navegador generalmente toma el árbol del DOM y, según criterios específicos, decide dar su propia capa a algunas ramas y subárboles. Estos subárboles se pintan en él (quizás usando un worklet de pintura en la en el futuro). Por último, todas estas capas individuales, ahora pintadas, se apilan y posicionarse una encima de la otra, respetando los índices z, las transformaciones 3D y para obtener la imagen final visible en la pantalla. Este proceso es llamada composición, y la ejecuta el compositor.

La ventaja del proceso de composición es que no tienes que hacer todo los elementos se vuelven a pintar cuando la página se desplaza un poco. En cambio, puedes reutilizar las capas del fotograma anterior y volver a ejecutar el compositor con la posición de desplazamiento actualizada. Eso hace que todo sea más rápido. Esto nos ayuda a alcanzar los 60 fps.

Worklet del compositor

Como su nombre lo indica, el worklet del compositor te permite conectarte al compositor. e influir en la forma en que se pinta la capa de un elemento, y se coloca en capas encima de las demás capas.

Para obtener un poco más específica, puedes indicarle al navegador que quieres conectarse a la composición para un nodo del DOM determinado y puede solicitar acceso a ciertos atributos, como la posición de desplazamiento, transform o opacity. Esto fuerza la activación del elemento propia capa y, en cada fotograma, se llama a tu código. Puedes mover tu capa Manipulando las capas, se transforman y cambian sus atributos (como opacity). lo que te permite hacer cosas elegantes y sofisticadas a 60 fps.

Esta es una implementación completa del desplazamiento con paralaje, con el compositor worklet.

// main.js
window.compositorWorklet.import('worklet.js')
    .then(function() {
    var animator = new CompositorAnimator('parallax');
    animator.postMessage([
        new CompositorProxy($('.scroller'), ['scrollTop']),
        new CompositorProxy($('.parallax'), ['transform']),
    ]);
    });

// worklet.js
registerCompositorAnimator('parallax', class {
    tick(timestamp) {
    var t = self.parallax.transform;
    t.m42 = -0.1 * self.scroller.scrollTop;
    self.parallax.transform = t;
    }

    onmessage(e) {
    self.scroller = e.data[0];
    self.parallax = e.data[1];
    };
});

Robert Flack escribió un polyfill para la en el compositor para que puedas probarlo, obviamente un mayor impacto en el rendimiento.

Worklet de diseño (spec)

Se propuso el primer borrador de especificaciones real. Implementación es un buen tiempo.

Nuevamente, la especificación para esto está prácticamente vacía, pero el concepto intrigante: ¡escribe tu propio diseño! El worklet de diseño debe permitirte que realices display: layout('myLayout') y ejecutes tu JavaScript para acomodar elementos secundarios en el cuadro del nodo.

Por supuesto, ejecutar una implementación completa de JavaScript del diseño flex-box de CSS es más lenta que ejecutar una implementación nativa equivalente, pero es fácil Imagina una situación en la que los recortes pueden mejorar el rendimiento. Imagina un solo mosaicos, como Windows 10 o un diseño de mampostería, . No se usa el posicionamiento absoluto y fijo, tampoco se usa z-index ni se los elementos se superponen o tienen algún tipo de borde o desbordamiento. Poder omitir todas estas comprobaciones de rediseño podrían aumentar el rendimiento.

registerLayout('random-layout', class {
    static get inputProperties() {
        return [];
    }
    static get childrenInputProperties() {
        return [];
    }
    layout(children, constraintSpace, styleMap) {
        const width = constraintSpace.width;
        const height = constraintSpace.height;
        for (let child of children) {
            const x = Math.random()*width;
            const y = Math.random()*height;
            const constraintSubSpace = new ConstraintSpace();
            constraintSubSpace.width = width-x;
            constraintSubSpace.height = height-y;
            const childFragment = child.doLayout(constraintSubSpace);
            childFragment.x = x;
            childFragment.y = y;
        }

        return {
            minContent: 0,
            maxContent: 0,
            width: width,
            height: height,
            fragments: [],
            unPositionedChildren: [],
            breakToken: null
        };
    }
});

CSSOM escrito (spec)

El CSSOM (modelo de objetos CSS o modelo de objetos en cascada) aborda un problema con el que todos nos hemos enfrentado y que aprendimos a soportar. Ilustrar con una línea de JavaScript:

    $('#someDiv').style.height = getRandomInt() + 'px';

Estamos haciendo cálculos matemáticos: convertimos un número en una cadena para agregar una unidad solo para obtener el navegador analizará esa cadena y la volverá a convertir en un número para el motor CSS. Esto se complica aún más cuando manipulas transformaciones con JavaScript. No más. A punto de empezar a escribir CSS,

Este borrador es uno de los más maduros y un polyfill es en las que ya estamos trabajando. (Renuncia de responsabilidad: Con polyfill, obviamente agregar aún más sobrecarga de procesamiento. El punto es mostrar cuán conveniente es sí).

En lugar de cadenas, trabajarás en el StylePropertyMap de un elemento, en el que cada atributo CSS tiene su propia clave y tipo de valor correspondiente. Atributos como width, tienen LengthValue como su tipo de valor. Un LengthValue es un diccionario de todas las unidades de CSS, como em, rem, px, percent, etcétera. Parámetro de configuración height: calc(5px + 5%) daría como resultado un LengthValue{px: 5, percent: 5}. Algunos Las propiedades como box-sizing solo aceptan ciertas palabras clave y, por lo tanto, tienen un Tipo de valor KeywordValue. Luego, se podría verificar la validez de esos atributos. durante el tiempo de ejecución.

<div style="width: 200px;" id="div1"></div>
<div style="width: 300px;" id="div2"></div>
<div id="div3"></div>
<div style="margin-left: calc(5em + 50%);" id="div4"></div>
var w1 = $('#div1').styleMap.get('width');
var w2 = $('#div2').styleMap.get('width');
$('#div3').styleMap.set('background-size',
    [new SimpleLength(200, 'px'), w1.add(w2)])
$('#div4')).styleMap.get('margin-left')
    // => {em: 5, percent: 50}

Propiedades y valores

(especificación)

¿Conoces las propiedades personalizadas de CSS (o su alias no oficial “Variables de CSS”)? Estos son todos, pero con tipos. Hasta ahora, las variables solo podrían tener valores de cadena y usamos un enfoque sencillo de búsqueda y reemplazo. Este borrador te permitiría no solo especificar un tipo para tus variables, sino también definir un valor predeterminado y influir en el comportamiento de herencia con una API de JavaScript. Técnicamente, esto también permitiría animar las propiedades personalizadas con transiciones de CSS estándar y animaciones, lo que también se está considerando.

["--scale-x", "--scale-y"].forEach(function(name) {
document.registerProperty({
    name: name,
    syntax: "<number>",
    inherits: false,
    initialValue: "1"
    });
});

Métricas de fuentes

Las métricas de fuentes son exactamente lo que parece. ¿Cuál es el cuadro delimitador (o el cuadros delimitadores) cuando renderiza la cadena X con la fuente Y con el tamaño Z? ¿Qué sucede si uso anotaciones ruby? Se ha pedido mucho, y Houdini finalmente debería hacer realidad estos deseos.

Espera, hay más calcomanías.

Hay más especificaciones en la lista de borradores de Houdini, pero el futuro de ellas más bien inciertos y no son mucho más que marcadores de posición para ideas. Los ejemplos incluyen comportamientos personalizados de desbordamiento, API de extensión de sintaxis CSS, extensión de desplazamiento nativo y otros elementos igualmente ambiciosos, cosas en la plataforma web que antes no eran posibles.

Demostraciones

Configuré el código de la demostración con código abierto (demostración en vivo con polyfill).