Houdini - Mengupas Tuntas CSS

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

Masuk ke Houdini.

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

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

Spesifikasi

Worklet (spesifikasi)

Worklet itu sendiri tidak terlalu berguna. {i>Wireframe<i} adalah konsep yang diperkenalkan untuk membuat banyak draf baru. Jika Anda memikirkan Web Worker saat membaca "worklet", Anda tidak salah. Keduanya memiliki banyak tumpang-tindih konseptual. Jadi, mengapa ada hal baru jika 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 tidak realistis untuk mengasumsikan bahwa beberapa fragmen kode ini harus dijalankan setiap frame. Beberapa di antaranya harus sesuai definisi. Mengutip spesifikasi Web Worker:

Artinya, pekerja web tidak dapat digunakan untuk hal-hal yang ingin dilakukan Houdini. Oleh karena itu, worklet diciptakan. Worklet menggunakan class ES2015 untuk menentukan kumpulan metode, yang tanda tangannya telah ditentukan sebelumnya oleh jenis worklet. Mereka ringan dan berumur pendek.

CSS Paint API (spesifikasi)

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

Worklet komposer

API yang dijelaskan di sini sudah tidak digunakan lagi. Worklet kompositor telah didesain ulang dan kini diusulkan sebagai "Worklet Animasi". Baca selengkapnya tentang iterasi API saat ini.

Meskipun spesifikasi worklet kompositor telah dipindahkan ke WICG dan akan di-iterasi, spesifikasi ini adalah spesifikasi yang paling menarik bagi saya. Beberapa operasi di-outsource ke kartu grafis komputer Anda oleh mesin CSS, meskipun hal itu bergantung pada kartu grafis dan perangkat Anda secara umum.

Browser biasanya mengambil hierarki DOM dan, berdasarkan kriteria tertentu, memutuskan untuk memberikan beberapa cabang dan subpohon lapisan tersendiri. Subtree ini melukis dirinya sendiri ke atasnya (mungkin menggunakan worklet cat di masa mendatang). Sebagai langkah terakhir, semua lapisan individual yang sekarang dicat ini ditumpuk dan diposisikan di atas satu sama lain, dengan mempertimbangkan z-index, transformasi 3D, dan sebagainya, untuk menghasilkan gambar akhir yang terlihat di layar Anda. Proses ini disebut komposisi dan dijalankan oleh kompositor.

Keuntungan dari proses komposisi adalah Anda tidak perlu membuat semua elemen mengecat ulang sendiri saat halaman di-scroll sedikit. Sebagai gantinya, Anda dapat menggunakan kembali lapisan dari frame sebelumnya dan cukup jalankan kembali kompositor dengan posisi scroll yang diperbarui. Hal ini membuat prosesnya cepat. Hal ini membantu kami mencapai 60 fps.

Worklet komposer.

Seperti namanya, worklet kompositor memungkinkan Anda terhubung ke kompositor dan memengaruhi cara lapisan elemen, yang telah dicat, diposisikan dan dilapiskan di atas lapisan lainnya.

Untuk lebih spesifiknya, 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 komponisator.

// 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 komposer sehingga Anda dapat mencobanya – tentu saja dengan dampak performa yang jauh lebih tinggi.

Worklet tata letak (spesifikasi)

Draf spesifikasi sebenarnya yang pertama telah diusulkan. Penerapannya masih memerlukan waktu yang lama.

Sekali lagi, spesifikasi untuk 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 lengkap dari tata letak flex-box CSS lebih lambat daripada menjalankan implementasi native yang setara, tetapi mudah untuk membayangkan skenario saat memotong sudut dapat menghasilkan peningkatan performa. Bayangkan situs yang hanya terdiri dari kartu, seperti Windows 10 atau tata letak gaya masonry. Pemosisi absolut dan tetap tidak digunakan, begitu juga dengan z-index, dan elemen tidak pernah tumpang-tindih atau memiliki jenis batas atau overflow apa pun. 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
        };
    }
});

CSSOM Berjenis (spesifikasi)

CSSOM Berjenis (CSS Object Model atau Cascading Style Sheets Object Model) mengatasi masalah yang mungkin kita semua alami dan baru saja belajar untuk menerimanya. Mari kita ilustrasikan dengan baris JavaScript:

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

Kita melakukan matematika, 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 yang lebih matang dan polyfill sudah dikerjakan. (Pernyataan penyangkalan: penggunaan polyfill jelas akan menambahkan overhead komputasi lebih banyak. Intinya adalah untuk menunjukkan betapa mudahnya API.)

Anda akan mengerjakan StylePropertyMap elemen, bukan string, dengan setiap atribut CSS memiliki kuncinya sendiri 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 adalah jenisnya, tetapi dengan jenis. Sejauh ini, variabel hanya dapat memiliki nilai string dan menggunakan pendekatan penelusuran dan penggantian sederhana. Dengan draf ini, Anda tidak hanya dapat 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) saat saya merender string X dengan font Y pada ukuran Z? Bagaimana jika saya menggunakan anotasi ruby? Hal ini telah banyak diminta dan Houdini akhirnya akan mewujudkan keinginan ini.

Tunggu, masih ada lagi!

Ada lebih banyak spesifikasi dalam daftar draf Houdini, tetapi masa depannya cukup 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 merilis kode untuk demo (demo langsung menggunakan polyfill) sebagai open source.