Houdini - Mengupas Tuntas CSS

Pernahkah Anda memikirkan tentang banyaknya pekerjaan yang dilakukan CSS? Anda mengubah satu atribut, dan tiba-tiba seluruh situs Anda muncul dalam tata letak yang berbeda. Ini seperti ajaib. Sejauh ini, kami—komunitas developer web—hanya dapat menyaksikan dan mengamati keajaibannya. Bagaimana jika kita ingin mengalami sihir kita sendiri? Bagaimana jika kita ingin menjadi pesulap?

Masuki Houdini!

Satuan tugas Houdini terdiri dari engineer dari Mozilla, Apple, Opera, Microsoft, HP, Intel, dan Google yang bekerja sama untuk mengekspos bagian tertentu mesin CSS kepada developer web. Satuan tugas sedang mengerjakan kumpulan draf dengan tujuan agar draf tersebut diterima oleh W3C menjadi standar web yang sebenarnya. Mereka menetapkan beberapa sasaran tingkat tinggi, mengubahnya menjadi draf spesifikasi yang kemudian melahirkan serangkaian draf spesifikasi tingkat rendah pendukung.

Kumpulan draf ini biasanya dimaksudkan ketika seseorang berbicara tentang "Houdini". Pada saat penulisan ini, daftar draf tidak lengkap dan beberapa draf hanyalah placeholder.

Spesifikasi

Worklet (spec)

Worklet itu sendiri tidak terlalu berguna. {i>Wireframe<i} adalah konsep yang diperkenalkan untuk membuat banyak draf baru. Jika Anda memikirkan Pekerja Web ketika Anda membaca "worklet", Anda tidak salah. Mereka memiliki banyak tumpang tindih konsep. Jadi mengapa ada hal baru ketika kita sudah memiliki pekerja?

Tujuan Houdini adalah mengekspos API baru agar developer web dapat menghubungkan kode mereka sendiri ke mesin CSS dan sistem di sekitarnya. Mungkin tidak realistis untuk mengasumsikan bahwa beberapa fragmen kode ini harus dijalankan setiap. satu frame. Beberapa di antaranya harus sesuai dengan definisi. Mengutip spesifikasi Web Worker:

Itu berarti pekerja web tidak memenuhi syarat untuk hal-hal yang akan dilakukan Houdini. Oleh karena itu, worklet ditemukan. Worklet menggunakan class ES2015 untuk menentukan sekumpulan metode, yang tanda tangannya telah ditetapkan sebelumnya oleh jenis worklet. Mereka ringan dan berumur pendek.

CSS Paint API (spec)

Paint API diaktifkan secara default pada Chrome 65. Baca pengantar mendetail.

Worklet kompositor

API yang dijelaskan di sini sudah tidak berlaku. Worklet Compositor telah didesain ulang dan sekarang diusulkan sebagai "Worklet Animasi". Baca selengkapnya tentang iterasi API saat ini.

Meskipun spesifikasi worklet compositor telah dipindahkan ke WICG dan akan diiterasi, spesifikasi ini merupakan spesifikasi yang paling menarik bagi saya. Beberapa operasi dialihkan ke kartu grafis komputer Anda oleh mesin CSS, meskipun hal tersebut bergantung pada kartu grafis dan perangkat secara umum.

Browser biasanya mengambil hierarki DOM dan, berdasarkan kriteria tertentu, memutuskan untuk memberikan beberapa cabang dan subtree sebagai lapisannya sendiri. Subpohon ini melukis dirinya sendiri (mungkin akan menggunakan worklet cat di masa mendatang). Sebagai langkah terakhir, semua lapisan individu ini, yang kini telah dicat, ditumpuk dan diposisikan di atas satu sama lain, dengan mematuhi indeks z, transformasi 3D, dan sedemikian untuk menghasilkan gambar akhir yang terlihat pada layar Anda. Proses ini disebut pengomposisian dan dijalankan oleh compositor.

Keuntungan dari proses pengomposisian adalah Anda tidak perlu membuat semua elemen dicat ulang sendiri saat halaman di-scroll sedikit. Sebagai gantinya, Anda dapat menggunakan kembali lapisan dari frame sebelumnya dan cukup menjalankan ulang compositor dengan posisi scroll yang diperbarui. Hal ini mempercepat proses. Hal ini membantu kami mencapai 60 fps.

Worklet kompositor.

Seperti namanya, worklet compositor memungkinkan Anda mengaitkan ke compositor dan memengaruhi cara lapisan elemen, yang telah dicat, diletakkan dan dilapiskan di atas lapisan lainnya.

Agar lebih spesifik, Anda dapat memberi tahu browser bahwa Anda ingin terhubung ke proses komposisi untuk node DOM tertentu dan dapat meminta akses ke atribut tertentu seperti posisi scroll, transform, atau opacity. Hal ini memaksa elemen ini ke lapisannya sendiri dan pada setiap frame kode Anda dipanggil. Anda dapat memindahkan lapisan dengan memanipulasi lapisan transformasi dan mengubah atributnya (seperti opacity) sehingga Anda dapat melakukan hal-hal keren di 60 fps.

Berikut adalah implementasi lengkap untuk scroll paralaks, menggunakan worklet compositor.

// 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 telah menulis polyfill untuk worklet compositor agar Anda dapat mencobanya – tentu saja dengan dampak performa yang jauh lebih tinggi.

Worklet tata letak (spec)

Draf spesifikasi sebenarnya yang pertama telah diusulkan. Implementasi tidaklah sulit.

Sekali lagi, spesifikasi untuk hal ini praktis kosong, tetapi konsepnya menarik: tulis tata letak Anda sendiri. Worklet tata letak seharusnya memungkinkan Anda melakukan display: layout('myLayout') dan menjalankan JavaScript untuk mengatur turunan node di kotak node.

Tentu saja, menjalankan implementasi JavaScript penuh dari tata letak flex-box CSS akan lebih lambat daripada menjalankan implementasi native yang setara, tetapi akan mudah untuk membayangkan skenario di mana perubahan cepat dapat menghasilkan peningkatan performa. Bayangkan situs yang hanya terdiri dari kartu, seperti Windows 10 atau tata letak bergaya masonry. Pemosisian absolut dan tetap tidak digunakan, begitu pula z-index, dan tidak ada elemen yang pernah tumpang tindih atau memiliki jenis batas atau tambahan. Mampu melewati semua pemeriksaan ini pada tata letak ulang dapat menghasilkan peningkatan performa.

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
        };
    }
});

GCLID yang diketik (spec)

Berkelanjutan (CSS Object Model atau Cascading Style Sheets Object Model) mengatasi masalah yang mungkin semua pernah kita temui dan baru saja kita pelajari. Mari saya ilustrasikan dengan baris JavaScript:

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

Kita sedang melakukan perhitungan, mengonversi angka menjadi string untuk menambahkan unit hanya agar browser mengurai string tersebut dan mengonversinya kembali menjadi angka untuk mesin CSS. Hal ini akan semakin jelek jika Anda memanipulasi transformasi dengan JavaScript. Tidak lagi! CSS akan mulai mengetik.

Draf ini adalah salah satu versi yang lebih matang dan polyfill sedang dikerjakan. (Pernyataan penyangkalan: menggunakan polyfill jelas akan menambah overhead komputasi yang lebih banyak. Intinya adalah menunjukkan seberapa praktisnya API tersebut.)

Sebagai ganti string, Anda akan mengerjakan StylePropertyMap elemen, dengan setiap atribut CSS memiliki kunci dan jenis nilai yang sesuai. Atribut seperti width memiliki LengthValue sebagai jenis nilainya. LengthValue adalah kamus dari semua unit CSS seperti em, rem, px, percent, dan seterusnya. Menetapkan height: calc(5px + 5%) akan menghasilkan LengthValue{px: 5, percent: 5}. Beberapa properti seperti box-sizing hanya menerima kata kunci tertentu sehingga memiliki jenis nilai KeywordValue. Validitas atribut tersebut kemudian dapat diperiksa saat runtime.

<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}

Properti dan nilai

(spec)

Apakah Anda mengetahui Properti Khusus CSS (atau alias tidak resminya "Variabel CSS")? Ini saja, tetapi dengan jenis. Sejauh ini, variabel hanya dapat memiliki nilai string dan menggunakan pendekatan cari dan ganti sederhana. Draf ini akan memungkinkan Anda tidak hanya menentukan jenis untuk variabel, tetapi juga menentukan nilai default dan memengaruhi perilaku pewarisan menggunakan JavaScript API. Secara teknis, hal ini juga akan memungkinkan properti kustom dianimasikan dengan transisi dan animasi CSS standar, yang juga sedang dipertimbangkan.

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

Metrik font

Metrik font persis seperti namanya. Apa kotak pembatas (atau kotak pembatas) ketika saya merender string X dengan font Y berukuran Z? Bagaimana jika saya menggunakan anotasi ruby? Hal ini telah sering diminta dan Houdini akhirnya harus mewujudkan keinginan ini.

Tunggu, masih ada lagi!

Daftar draf Houdini masih memiliki spesifikasi lain, tetapi masa depannya agak tidak pasti dan tidak lebih dari sekadar placeholder untuk ide. Contohnya mencakup perilaku overflow kustom, API ekstensi sintaksis CSS, ekstensi perilaku scroll native, dan hal-hal serupa yang semuanya memungkinkan berbagai hal di platform web yang sebelumnya tidak mungkin dilakukan.

Demo

Saya telah membuat kode untuk demo menjadi open source (demo live menggunakan polyfill).