Houdini - Mengupas Tuntas CSS

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

Masuki Houdini!

Gugus tugas Houdini terdiri dari insinyur dari Mozilla, Apple, Opera, Microsoft, HP, Intel, dan Google bekerja sama untuk mengekspos bagian tertentu dari Mesin CSS kepada developer web. Satuan tim sedang mengerjakan kumpulan draf agar dapat diterima di W3C untuk menjadi web standar. Mereka menetapkan beberapa sasaran tingkat tinggi, mengubahnya menjadi draf spesifikasi yang kemudian menghasilkan serangkaian materi pendukung, draf spesifikasi di tingkat yang lebih rendah.

Kumpulan draf ini adalah apa yang biasanya dimaksudkan ketika seseorang berbicara tentang "Houdini". Pada saat penulisan ini, daftar draf terdapat tidak lengkap dan beberapa draf hanyalah sebagai {i>placeholder<i}.

Spesifikasi

Worklet (spesifikasi)

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

Tujuan Houdini adalah mengekspos API baru untuk memungkinkan developer web menghubungkan kode mereka sendiri ke mesin CSS dan sistem-sistem yang ada di sekitarnya. Mungkin tidak realistis untuk berasumsi bahwa beberapa dari fragmen kode harus dijalankan setiap kali. tunggal. Bingkai. Beberapa dari mereka harus menurut definisinya. Mengutip spesifikasi Web Worker:

Itu berarti pekerja web tidak memenuhi syarat untuk hal-hal yang akan dilakukan Houdini. Oleh karena itu, worklet diciptakan. Worklet memanfaatkan kelas ES2015 untuk mendefinisikan sebuah 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 pada Chrome 65. Baca pengantar mendetail.

Worklet kompositor

API yang dijelaskan di sini sudah tidak berlaku. Worklet Compositor memiliki telah dirancang ulang dan kini diusulkan sebagai "Worklet Animasi". Baca selengkapnya di iterasi API saat ini.

Meskipun spesifikasi {i>worklet <i}compositor telah dipindahkan ke WICG dan akan ulangi, inilah spesifikasi yang paling menarik bagi saya. Agak besar operasi dialihkan ke kartu grafis komputer Anda oleh CSS mesin telusur, meskipun hal itu bergantung pada kartu grafis dan perangkat Anda umum.

Browser biasanya mengambil hierarki DOM dan, berdasarkan kriteria tertentu, memutuskan untuk memberikan beberapa cabang dan sub pohon {i>layer<i} mereka sendiri. Sub-pohon ini melukis dirinya sendiri (mungkin menggunakan worklet cat di di masa mendatang). Sebagai langkah terakhir, semua lapisan individual ini, yang sekarang telah dicat, ditumpuk dan diposisikan di atas satu sama lain, dengan mematuhi indeks z, transformasi 3D, dan untuk menghasilkan gambar akhir yang terlihat di layar Anda. Proses ini yang disebut pengomposisian dan dieksekusi oleh compositor.

Keuntungan dari proses pengomposisian adalah bahwa Anda tidak harus membuat semua elemen dilukis ulang sendiri ketika laman bergulir sedikit kecil. Sebaliknya, Anda dapat dapat menggunakan kembali layer dari {i>frame<i} sebelumnya dan hanya menjalankan ulang compositor dengan posisi scroll yang diperbarui. Hal ini mempercepat proses. Hal ini membantu kami mencapai 60 fps.

Worklet kompositor.

Seperti namanya, {i>worklet<i} compositor memungkinkan Anda mengaitkannya ke compositor dan mempengaruhi cara lapisan elemen, yang telah dicat, adalah diletakkan dan diletakkan di atas lapisan lainnya.

Untuk mendapatkan lebih banyak spesifik, Anda dapat memberi tahu browser bahwa Anda ingin menarik ke dalam {i>compositing<i} untuk simpul DOM tertentu dan dapat meminta akses ke atribut tertentu, posisi scroll, transform atau opacity. Ini memaksa elemen ini ke lapisan Anda sendiri dan pada setiap frame, kode Anda akan dipanggil. Anda dapat memindahkan lapisan dengan memanipulasi transformasi lapisan dan mengubah atributnya (seperti opacity) yang memungkinkan Anda melakukan hal-hal keren di 60 fps.

Berikut ini adalah implementasi lengkap untuk scroll paralaks, menggunakan compositor {i>worklet<i}.

// 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 {i>compositor <i}sehingga Anda dapat mencobanya – tentu saja dengan dampak performa yang lebih tinggi.

Worklet tata letak (spesifikasi)

Draf spesifikasi sebenarnya yang pertama telah diusulkan. Penerapan adalah pilihan yang baik.

Sekali lagi, spesifikasi untuk ini praktis kosong, tetapi konsepnya menarik: tulis tata letak Anda sendiri! Worklet tata letak seharusnya memungkinkan Anda untuk melakukan display: layout('myLayout') dan menjalankan JavaScript Anda guna mengatur kode {i>child<i} pada kotak {i>node<i}.

Tentu saja, menjalankan implementasi JavaScript penuh dari tata letak flex-box CSS lebih lambat daripada menjalankan implementasi bawaan yang setara, tetapi mudah untuk bayangkan sebuah skenario di mana perubahan cepat dapat menghasilkan peningkatan kinerja. Bayangkan situs web yang hanya terdiri dari apa-apa selain ubin, seperti Windows 10 atau bergaya masonry tata letak. Pemosisian absolut dan tetap tidak digunakan, z-index, juga tidak digunakan elemen yang tumpang tindih atau memiliki batas atau tambahan. Mampu melewati semua pemeriksaan tata letak ini dapat menghasilkan peningkatan kinerja.

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)

GCLID yang diketik (CSS Object Model atau Cascading Style Sheets Object Model) menangani masalah yang mungkin pernah kita hadapi dan baru saja kita belajar untuk bertahan. Mari saya ilustrasikan dengan baris JavaScript:

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

Kita melakukan matematika, mengonversi angka menjadi {i>string<i} untuk menambahkan unit hanya agar browser akan mengurai string itu 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 draf yang lebih matang dan polyfill adalah yang sudah dikerjakan. (Penafian: menggunakan polyfill jelas akan akan menambahkan lebih banyak lagi overhead komputasi. Intinya adalah untuk menunjukkan seberapa praktis API adalah.)

Sebagai ganti string, Anda akan mengerjakan StylePropertyMap elemen, dengan setiap atribut CSS memiliki kuncinya sendiri dan jenis nilainya yang sesuai. Atribut seperti width memiliki LengthValue sebagai jenis nilainya. LengthValue adalah semua unit CSS seperti em, rem, px, percent, dan seterusnya. Latar (Setting) height: calc(5px + 5%) akan menghasilkan LengthValue{px: 5, percent: 5}. Agak besar properti seperti box-sizing hanya menerima kata kunci tertentu sehingga memiliki Jenis nilai KeywordValue. Validitas atribut tersebut kemudian dapat diperiksa pada 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

(spesifikasi)

Apakah Anda mengetahui Properti Khusus CSS (atau alias tidak resminya "Variabel CSS")? Ini saja, tetapi dengan jenis. Sejauh ini, variabel hanya bisa memiliki nilai {i>string<i} dan menggunakan pendekatan {i>search and replace<i} yang sederhana. Draf ini akan memungkinkan Anda untuk tidak hanya tentukan jenis untuk variabel, tetapi juga tentukan nilai default dan memengaruhi perilaku pewarisan menggunakan JavaScript API. Secara teknis, juga akan memungkinkan properti khusus untuk dianimasikan dengan transisi CSS standar dan animasi, yang juga 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 yang dimaksud dengan kotak pembatas (atau kotak pembatas) saat saya merender string X dengan font Y berukuran Z? Bagaimana jika saya menggunakan anotasi ruby? Ini sudah sering diminta dan Houdini akhirnya mewujudkan keinginan tersebut.

Tunggu, masih ada lagi!

Ada lebih banyak spesifikasi dalam daftar draf Houdini, tetapi {i>masa depan<i} itu tidak pasti dan tidak lebih dari sekedar {i>placeholder<i} untuk ide-ide. Contohnya mencakup perilaku overflow kustom, API ekstensi sintaksis CSS, ekstensi perilaku scroll native dan hal-hal serupa yang ambisius, semuanya memungkinkan di platform web yang sebelumnya tidak mungkin dilakukan.

Demo

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