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 semacam sihir. 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. Ini adalah konsep yang diperkenalkan untuk memungkinkan banyak draf berikutnya. 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. Fungsi ini 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 memberi beberapa cabang dan subhierarki lapisannya sendiri. Subtree ini melukis dirinya sendiri ke dalamnya (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 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. Tindakan ini akan memaksa elemen ini ke lapisan sendiri dan di setiap frame kode Anda akan dipanggil. Anda dapat memindahkan lapisan dengan memanipulasi transformasi lapisan dan mengubah atributnya (seperti opacity) sehingga Anda dapat melakukan hal-hal yang menarik dengan kecepatan 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 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 dalam 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. Kemampuan untuk 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 menjadi lebih buruk saat Anda memanipulasi transformasi dengan JavaScript. Tidak lagi! CSS akan segera 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 sebagainya. 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 adalah 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 ambisius lainnya yang semuanya memungkinkan hal-hal di platform web yang sebelumnya tidak dapat dilakukan.

Demo

Saya telah merilis kode untuk demo (demo langsung menggunakan polyfill) sebagai open source.