Houdini – Làm sáng tỏ CSS

Bạn đã bao giờ nghĩ đến lượng công việc mà CSS thực hiện chưa? Bạn thay đổi một thuộc tính và đột nhiên toàn bộ trang web của bạn xuất hiện theo bố cục khác. Đó là một phép màu. Cho đến nay, chúng tôi – cộng đồng nhà phát triển web – chỉ có thể chứng kiến và quan sát sự kỳ diệu này. Nếu chúng ta muốn tạo ra phép thuật của riêng mình thì sao? Nếu chúng ta muốn trở thành ảo thuật gia thì sao?

Hãy nhập Houdini!

Nhóm tác vụ Houdini bao gồm các kỹ sư của Mozilla, Apple, Opera, Microsoft, HP, Intel và Google cùng nhau làm việc để giới thiệu một số phần nhất định của công cụ CSS cho các nhà phát triển web. Nhóm đặc nhiệm đang làm việc trên một bộ sưu tập bản nháp với mục tiêu được W3C chấp nhận để trở thành các tiêu chuẩn web thực tế. Họ đặt ra một số mục tiêu cấp cao, biến chúng thành bản nháp quy cách, từ đó tạo ra một bộ bản nháp quy cách cấp thấp hơn để hỗ trợ.

Tập hợp các bản nháp này thường được đề cập đến khi ai đó nói về "Houdini". Tại thời điểm viết bài, danh sách bản nháp chưa hoàn chỉnh và một số bản nháp chỉ là phần giữ chỗ.

Thông số kỹ thuật

Worklet (spec)

Bản thân các công việc không thực sự hữu ích. Đây là một khái niệm được giới thiệu để tạo ra nhiều bản nháp sau này. Nếu bạn nghĩ đến Web Worker khi đọc "worklet", thì bạn không sai. Các khái niệm này có nhiều điểm trùng lặp. Vậy tại sao chúng ta lại cần một thứ mới khi đã có worker?

Mục tiêu của Houdini là hiển thị các API mới để cho phép nhà phát triển web kết nối mã của riêng họ vào công cụ CSS và các hệ thống xung quanh. Có lẽ không thực tế khi giả định rằng một số mảnh mã này sẽ phải chạy mỗi khung. Một số trong số đó phải theo định nghĩa. Trích dẫn thông số kỹ thuật của Web Worker:

Điều đó có nghĩa là worker web không phù hợp với những việc mà Houdini dự định làm. Vì vậy, các worklet đã được phát minh. Worklet sử dụng các lớp ES2015 để xác định một tập hợp phương thức, chữ ký của các phương thức này được xác định trước theo loại worklet. Các tệp này có kích thước nhỏ và tồn tại trong thời gian ngắn.

CSS Paint API (thông số kỹ thuật)

Paint API được bật theo mặc định trong Chrome 65. Hãy đọc nội dung giới thiệu chi tiết.

Worklet của trình kết hợp

API được mô tả ở đây đã lỗi thời. Worklet của trình kết hợp đã được thiết kế lại và hiện được đề xuất là "Animation Worklet" (Worklet ảnh động). Đọc thêm về lần lặp lại hiện tại của API.

Mặc dù thông số kỹ thuật của công cụ kết hợp đã được chuyển sang WICG và sẽ được lặp lại, nhưng đây là thông số kỹ thuật khiến tôi hào hứng nhất. Một số thao tác được công cụ CSS thuê ngoài cho thẻ đồ hoạ của máy tính, mặc dù điều đó phụ thuộc vào cả thẻ đồ hoạ và thiết bị của bạn nói chung.

Trình duyệt thường lấy cây DOM và dựa trên các tiêu chí cụ thể, quyết định cung cấp một số nhánh và cây con riêng. Các cây con này tự vẽ lên đó (có thể sử dụng một công cụ vẽ trong tương lai). Ở bước cuối cùng, tất cả các lớp riêng lẻ, hiện đã được vẽ, được xếp chồng lên nhau và được đặt chồng lên nhau, tuân theo chỉ mục z, phép biến đổi 3D và các lớp khác để tạo ra hình ảnh cuối cùng hiển thị trên màn hình. Quá trình này được gọi là kết hợp và do trình kết hợp thực thi.

Ưu điểm của quy trình kết hợp là bạn không phải tự vẽ lại tất cả các phần tử khi trang cuộn một chút. Thay vào đó, bạn có thể sử dụng lại các lớp từ khung trước đó và chỉ cần chạy lại trình kết hợp với vị trí cuộn đã cập nhật. Điều này giúp mọi việc diễn ra nhanh chóng. Điều này giúp chúng tôi đạt được tốc độ 60 khung hình/giây.

Worklet của trình kết hợp.

Như tên gọi, công cụ kết hợp cho phép bạn kết nối với công cụ kết hợp và ảnh hưởng đến cách lớp của một phần tử (đã được vẽ) được định vị và xếp lớp trên các lớp khác.

Để cụ thể hơn một chút, bạn có thể cho trình duyệt biết rằng bạn muốn kết nối với quy trình kết hợp cho một nút DOM nhất định và có thể yêu cầu quyền truy cập vào một số thuộc tính nhất định như vị trí cuộn, transform hoặc opacity. Thao tác này buộc phần tử này chuyển sang lớp riêng và trên mỗi khung, mã của bạn sẽ được gọi. Bạn có thể di chuyển lớp bằng cách thao tác với phép biến đổi lớp và thay đổi các thuộc tính của lớp (như opacity) cho phép bạn thực hiện các thao tác thú vị ở tốc độ 60 khung hình/giây.

Dưới đây là cách triển khai đầy đủ hiệu ứng cuộn thị sai bằng cách sử dụng công cụ công việc của trình kết hợp.

// 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 đã viết một polyfill cho công việc của trình kết hợp để bạn có thể thử – rõ ràng là với tác động hiệu suất cao hơn nhiều.

Worklet bố cục (thông số kỹ thuật)

Đã đề xuất bản nháp thông số kỹ thuật thực tế đầu tiên. Bạn nên triển khai sau.

Xin nhắc lại, thông số kỹ thuật cho việc này thực tế là trống, nhưng khái niệm này rất thú vị: viết bố cục của riêng bạn! Worklet bố cục được thiết kế để cho phép bạn thực hiện display: layout('myLayout') và chạy JavaScript để sắp xếp các nút con của một nút trong hộp của nút đó.

Tất nhiên, việc chạy một cách triển khai JavaScript đầy đủ của bố cục flex-box của CSS sẽ chậm hơn so với việc chạy một cách triển khai gốc tương đương, nhưng bạn có thể dễ dàng tưởng tượng một tình huống mà việc cắt bớt có thể mang lại hiệu suất cao hơn. Hãy tưởng tượng một trang web chỉ bao gồm các thẻ thông tin, chẳng hạn như Windows 10 hoặc bố cục kiểu xếp kề. Không sử dụng vị trí tuyệt đối và cố định, cũng không sử dụng z-index, cũng như các phần tử không bao giờ chồng chéo hoặc có bất kỳ loại đường viền hoặc tràn nào. Việc có thể bỏ qua tất cả các bước kiểm tra này khi bố cục được sắp xếp lại có thể giúp tăng hiệu suất.

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 đã nhập (thông số kỹ thuật)

CSSOM được nhập (Mô hình đối tượng CSS hoặc Mô hình đối tượng của trang định kiểu xếp tầng) giải quyết một vấn đề mà có thể tất cả chúng ta đều gặp phải và chỉ mới học cách chấp nhận. Hãy để tôi minh hoạ bằng một dòng mã JavaScript:

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

Chúng ta đang thực hiện phép tính, chuyển đổi một số thành một chuỗi để thêm một đơn vị chỉ để trình duyệt phân tích cú pháp chuỗi đó và chuyển đổi chuỗi đó trở lại thành một số cho công cụ CSS. Điều này càng trở nên khó coi hơn khi bạn thao tác với các phép biến đổi bằng JavaScript. Không còn nữa! CSS sắp được nhập.

Bản thảo này là một trong những bản thảo đã hoàn thiện hơn và một polyfill đang được triển khai. (Tuyên bố từ chối trách nhiệm: việc sử dụng polyfill rõ ràng sẽ làm tăng ngay cả nhiều hơn chi phí tính toán. Mục đích là để cho thấy API này tiện lợi như thế nào.)

Thay vì chuỗi, bạn sẽ làm việc trên StylePropertyMap của một phần tử, trong đó mỗi thuộc tính CSS có khoá riêng và loại giá trị tương ứng. Các thuộc tính như widthLengthValue làm loại giá trị. LengthValue là một từ điển của tất cả các đơn vị CSS như em, rem, px, percent, v.v. Việc thiết lập height: calc(5px + 5%) sẽ tạo ra một LengthValue{px: 5, percent: 5}. Một số thuộc tính như box-sizing chỉ chấp nhận một số từ khoá nhất định và do đó có loại giá trị KeywordValue. Sau đó, bạn có thể kiểm tra tính hợp lệ của các thuộc tính đó trong thời gian chạy.

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

Thuộc tính và giá trị

(spec)

Bạn có biết Thuộc tính tuỳ chỉnh CSS (hoặc bí danh không chính thức "Biến CSS") không? Đây là các biến đó nhưng có thêm kiểu! Cho đến nay, các biến chỉ có thể có giá trị chuỗi và sử dụng phương pháp tìm và thay thế đơn giản. Bản nháp này cho phép bạn không chỉ chỉ định một loại cho các biến mà còn xác định giá trị mặc định và ảnh hưởng đến hành vi kế thừa bằng cách sử dụng API JavaScript. Về mặt kỹ thuật, điều này cũng cho phép các thuộc tính tuỳ chỉnh tạo ảnh động bằng các hiệu ứng chuyển đổi và ảnh động CSS tiêu chuẩn. Chúng tôi cũng đang xem xét điều này.

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

Chỉ số phông chữ

Chỉ số phông chữ là chỉ số về phông chữ. Hộp giới hạn (hoặc hộp giới hạn) là gì khi tôi kết xuất chuỗi X bằng phông chữ Y ở kích thước Z? Nếu tôi sử dụng chú thích ruby thì sao? Đây là một yêu cầu được đưa ra rất nhiều và cuối cùng thì Houdini cũng sẽ giúp bạn thực hiện những điều này.

Tuy nhiên, hãy đợi vì còn nhiều thứ khác nữa!

Thậm chí còn có nhiều thông số kỹ thuật hơn trong danh sách bản nháp của Houdini, nhưng tương lai của những thông số kỹ thuật đó khá không chắc chắn và chúng chỉ là phần giữ chỗ cho các ý tưởng. Ví dụ: hành vi tràn tuỳ chỉnh, API tiện ích cú pháp CSS, tiện ích của hành vi cuộn gốc và các tính năng tham vọng tương tự, tất cả đều cho phép thực hiện những việc trên nền tảng web mà trước đây không thể thực hiện được.

Bản thu thử

Tôi đã phát hành nguồn mở mã cho bản minh hoạ (bản minh hoạ trực tiếp sử dụng polyfill).