ฮูดินี่ - ไขข้อข้องใจเกี่ยวกับ CSS

คุณเคยพิจารณาเกี่ยวกับปริมาณงานที่ CSS ทำไหม คุณเปลี่ยนรายการเดียว แล้วเว็บไซต์ทั้งเว็บไซต์จะปรากฏในเลย์เอาต์อื่นทันที ตอนนี้ มายากล ที่ผ่านมาเราซึ่งเป็นชุมชนนักพัฒนาเว็บ สามารถเป็นพยานและสังเกตเวทมนตร์ได้เท่านั้น ถ้าอยากมีไอเดียใหม่ๆ ความมหัศจรรย์ของตัวเราเองด้วย และถ้าเราต้องการเป็นนักมายากล

ป้อน Houdini!

ทีมงานของ Houdini ประกอบด้วยวิศวกรจาก Mozilla, Apple, Opera Microsoft, HP, Intel และ Google ทำงานร่วมกันเพื่อแสดง CSS Engine แก่นักพัฒนาเว็บ ทีมงานกำลังทำงานในคอลเล็กชันของ ฉบับร่าง โดยมีเป้าหมายเพื่อให้ W3C ยอมรับหัวข้อดังกล่าวกลายเป็นเว็บไซต์ มาตรฐาน พวกเขาตั้งเป้าหมายระดับสูงไม่กี่อย่างและเปลี่ยนให้เป็น แบบร่างข้อกำหนด ซึ่งนำไปสู่ชุดการสนับสนุน ฉบับร่างข้อกำหนดระดับต่ำลงมา

การรวบรวมข้อความฉบับร่างเหล่านี้เป็นสิ่งที่ผู้คนมักพูดถึง "ฮูดินี่" ในขณะที่เขียน รายการร่างคือ ไม่สมบูรณ์ และฉบับร่างบางส่วนเป็นเพียงตัวยึดตำแหน่งเท่านั้น

ข้อกำหนดเฉพาะ

Worklet (spec)

Worklets เพียงอย่างเดียวไม่มีประโยชน์เลย เป็นแนวคิดในการ ทำให้ฉบับร่างต่อๆ ไปเป็นไปได้หลายฉบับ ถ้าคุณนึกถึง Web Workers อ่าน "worklet" ว่าคุณตอบไม่ผิด ซึ่งมีแนวคิดที่ทับซ้อนกันอยู่มากมาย ทำไม ของใหม่ เมื่อเรามีพนักงานอยู่แล้ว

เป้าหมายของ Houdini คือการเปิดตัว API ใหม่ๆ เพื่อให้นักพัฒนาเว็บสามารถเชื่อมต่อโค้ดของตนเองลงในเครื่องมือ CSS และ ระบบแวดล้อม จึงอาจไม่สมเหตุสมผลนักที่จะตั้งสมมติฐานว่า ส่วนโค้ดจะต้องเรียกใช้ทุกรายการ โสด ซึ่งบางครั้งอาจต้องใช้ ตามคำจำกัดความ การถามข้อกำหนดของ Web Worker มีดังนี้

นั่นหมายความว่าคนทำงานบนเว็บจะไม่สามารถทำสิ่งเหล่านี้ได้ในสิ่งที่ Houdini วางแผนที่จะทำ ดังนั้นจึงมีการคิดค้นเวิร์กเล็ตขึ้น Worklet ใช้ประโยชน์จากคลาส ES2015 เพื่อกำหนด ชุดวิธีการ ซึ่งเป็นลายเซ็นที่กำหนดไว้ล่วงหน้าโดย ประเภทของงาน มีน้ำหนักเบาและมีอายุสั้น

CSS Paint API (ข้อกำหนด)

เปิดใช้ Paint API โดยค่าเริ่มต้นใน Chrome 65 อ่าน ข้อมูลเบื้องต้นโดยละเอียด

Worklet คอมโพสิต

API ที่อธิบายที่นี่ล้าสมัยแล้ว Worklet คอมโพสิตมี ได้รับการออกแบบใหม่และขณะนี้เสนอเป็น "Animation Worklet" อ่านเพิ่มเติมใน การทำซ้ำปัจจุบันของ API

แม้ว่าได้ย้ายข้อกำหนดของ Worklet คอมโพสิตไปยัง WICG แล้วและจะ มันเป็นสเปคที่ผมตื่นเต้นมากที่สุด ใช้บ้าง การดำเนินการต่างๆ ได้รับว่าจ้างจาก CSS ไปยังการ์ดแสดงผลของคอมพิวเตอร์ของคุณ แม้ว่าจะขึ้นอยู่กับทั้งการ์ดแสดงผลและอุปกรณ์ของคุณใน ทั่วไป

เบราว์เซอร์มักจะใช้แผนผัง DOM และตามเกณฑ์ที่ระบุ ตัดสินใจที่จะให้กิ่งก้านและต้นไม้บางส่วนแยกย่อยเลเยอร์ของตัวเอง ต้นไม้ย่อยเหล่านี้จะระบายสีตัวเอง (หรืออาจใช้โมเดลสีใน ในอนาคต) ขั้นตอนสุดท้าย รูปภาพเลเยอร์ทั้งหมดนี้ที่ลงสีแล้วจะวางซ้อนกัน และวางด้านบนกัน โดยปฏิบัติตามดัชนี z, การแปลงแบบ 3 มิติ และ เพื่อให้ได้ภาพสุดท้ายที่ปรากฏบนหน้าจอของคุณ กระบวนการนี้ เรียกว่า compositing และจะทำงานโดยเครื่องมือทำ Composite

ข้อดีของกระบวนการประกอบคือ คุณไม่ต้องทำการพิมพ์ องค์ประกอบจะสร้างสีใหม่ให้กับตัวเองเมื่อหน้าเว็บเลื่อนเล็กน้อย แต่คุณ สามารถนำเลเยอร์จากเฟรมก่อนหน้ามาใช้ซ้ำได้ และเพียงเรียกใช้เครื่องมือทำ Composite อีกครั้งด้วย ตำแหน่งการเลื่อนที่อัปเดตแล้ว การดำเนินการนี้ช่วยให้สิ่งต่างๆ เป็นไปอย่างรวดเร็ว อัตรานี้ช่วยให้เราบรรลุถึง 60 fps

เวิร์กเล็ตแบบผสม

เวิร์กเล็ตของคอมโพสิต (Compositor Worklet) ช่วยให้คุณเข้าคอมโพสิเตอร์ได้ตามที่ชื่อมา และส่งผลต่อลักษณะเลเยอร์ขององค์ประกอบที่ได้ลงสีไปแล้ว และวางทับบนเลเยอร์อื่นๆ

หากต้องการเพิ่มอีกเล็กน้อย คุณจึงสามารถบอกเบราว์เซอร์ได้ ว่าคุณต้องการดึงดูด สำหรับโหนด DOM บางรายการและสามารถขอสิทธิ์เข้าถึงแอตทริบิวต์บางอย่าง เช่น ตำแหน่งการเลื่อน transform หรือ opacity การดำเนินการนี้จะบังคับให้องค์ประกอบนี้ เลเยอร์ของตัวเองและในแต่ละเฟรมจะมีการเรียกโค้ดของคุณ คุณย้ายเลเยอร์ได้ โดยการควบคุมเลเยอร์จะเปลี่ยนรูปแบบและเปลี่ยนแอตทริบิวต์ (เช่น opacity) ซึ่งช่วยให้คุณทำสิ่งต่างๆ มากมาย ด้วยอัตราเฟรม 60 fps สูง

นี่คือการใช้งานการเลื่อนพารัลแลกซ์อย่างเต็มรูปแบบโดยใช้คอมโพสิต Worklet

// 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 ได้เขียน polyfill สำหรับ เครื่องมือทำ compositor ที่คุณสามารถลองใช้งานได้ ด้วย ผลกระทบด้านประสิทธิภาพที่สูงขึ้น

เวิร์กเล็ตเลย์เอาต์ (spec)

มีการเสนอร่างข้อกำหนดจริงครั้งแรก การใช้งาน ยังไม่ค่อยสะดวก

ขอย้ำอีกครั้งว่าข้อกำหนดในเรื่องนี้ไม่ได้ว่างเปล่า แต่แนวคิดก็คือ น่าสนใจ: เขียนการออกแบบของคุณเอง! เวิร์กเล็ตเลย์เอาต์ควรจะช่วยให้คุณ เพื่อdisplay: layout('myLayout') และเรียกใช้ JavaScript เพื่อจัดเรียง ในช่องของโหนด

แน่นอนว่าการใช้งาน JavaScript เต็มรูปแบบในเลย์เอาต์ flex-box ของ CSS นั้นช้ากว่าการใช้ตำแหน่งเนทีฟที่เทียบเท่ากัน แต่ก็สามารถ ลองนึกถึงสถานการณ์ที่การตัดมุมอาจช่วยเพิ่มประสิทธิภาพได้ ลองจินตนาการถึง เว็บไซต์ที่มีองค์ประกอบใดๆ ยกเว้นแต่ชิ้นส่วน เช่น Windows 10 หรือ รูปแบบการก่ออิฐ เลย์เอาต์ ไม่ได้ใช้ตำแหน่งแบบสัมบูรณ์และคงที่ ไม่ใช่ z-index หรือห้ามใช้ มีองค์ประกอบที่ซ้อนทับกันหรือมีขอบหรือองค์ประกอบที่ล้นชนิดใดก็ตาม สามารถข้ามได้ การตรวจสอบทั้งหมดเมื่อนำมาออกแบบใหม่อาจช่วยให้ประสิทธิภาพดีขึ้นได้

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 ที่พิมพ์ (ข้อกำหนด)

CSSOM (CSS Object Model หรือ Cascading Style Sheets Object Model) ที่พิมพ์ ที่พวกเราทุกคนน่าจะเคยเจอ และเพิ่งรู้วิธีจัดการกับเรื่องนี้ ผมขออธิบายด้วยบรรทัด JavaScript:

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

เรากำลังคำนวณอยู่ โดยแปลงตัวเลขเป็นสตริงเพื่อต่อท้ายหน่วย เบราว์เซอร์จะแยกวิเคราะห์สตริงดังกล่าวและแปลงกลับไปเป็นตัวเลขสำหรับเครื่องมือ CSS ซึ่งจะยิ่งแย่ลงไปอีกเมื่อคุณควบคุมการแปลงด้วย JavaScript หมดแล้ว! CSS กำลังจะได้พิมพ์

ฉบับร่างนี้เป็นฉบับร่างที่ไม่สมบูรณ์กว่าเวอร์ชันหนึ่ง และ polyfill ที่เราพัฒนากันอยู่ (ข้อจำกัดความรับผิด: การใช้ Polyfill จะ เพิ่มค่าใช้จ่ายในการประมวลผลมากยิ่งขึ้น ประเด็นคือ การแสดงให้เห็นว่า API)

คุณจะทำงานกับ StylePropertyMap ขององค์ประกอบแทนสตริง โดยที่ แอตทริบิวต์ CSS แต่ละรายการจะมีคีย์และประเภทค่าที่เกี่ยวข้องของตนเอง ลักษณะ เช่น width มี LengthValue เป็นประเภทค่า LengthValue คือ พจนานุกรมของหน่วย CSS ทั้งหมด เช่น em, rem, px, percent และอื่นๆ การเกริ่นนำ height: calc(5px + 5%) จะให้ผลตอบแทนเป็น LengthValue{px: 5, percent: 5} ใช้บ้าง พร็อพเพอร์ตี้ เช่น box-sizing จะยอมรับคีย์เวิร์ดบางคำ จึงมีค่า KeywordValue ประเภทค่า เพื่อตรวจสอบความถูกต้องของแอตทริบิวต์เหล่านั้น ขณะรันไทม์

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

พร็อพเพอร์ตี้และค่า

(ข้อกำหนด)

คุณรู้จักพร็อพเพอร์ตี้ที่กำหนดเองของ CSS (หรือนามแฝงที่ไม่เป็นทางการ "ตัวแปร CSS") ไหม และนี่ก็คือคำตอบประเภทต่างๆ! จนถึงตอนนี้ ตัวแปรสามารถมีได้เฉพาะค่าสตริงและ ใช้วิธีการค้นหาและแทนที่ที่ง่าย ฉบับร่างนี้จะช่วยให้คุณไม่ ให้ระบุเฉพาะประเภทสำหรับตัวแปร แต่ให้กำหนดค่าเริ่มต้นและ ส่งผลต่อพฤติกรรมการสืบทอดค่าโดยใช้ JavaScript API โดยทางเทคนิค จะช่วยให้คุณสมบัติที่กำหนดเองสร้างภาพเคลื่อนไหวเมื่อเปลี่ยน CSS มาตรฐาน และภาพเคลื่อนไหว ซึ่งก็ได้รับการพิจารณา

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

เมตริกแบบอักษร

เมตริกแบบอักษรมีหน้าตาแบบนี้ กรอบล้อมรอบคืออะไร (หรือ กรอบล้อมรอบ) เมื่อฉันแสดงผลสตริง X ด้วยแบบอักษร Y ที่ขนาด Z จะเกิดอะไรขึ้นหากฉันใช้ คำอธิบายประกอบ Ruby มีคนขอกันเข้ามาเป็นจำนวนมาก และในที่สุดฮูดินี่ก็ จงทำให้ความปรารถนาเหล่านี้เป็นจริง

แต่ยังไม่หมดเท่านี้!

ยังมีข้อกำหนดเฉพาะอื่นๆ อีกในรายการของฉบับร่างของ Houdini แต่ในอนาคตก็คือ ค่อนข้างไม่แน่นอน และไม่ได้เป็นเพียงตัวยึดตำแหน่งสำหรับไอเดีย เช่น ลักษณะการทำงานของส่วนเพิ่มเติมที่กำหนดเอง, API ส่วนขยายไวยากรณ์ CSS, ส่วนขยาย ของลักษณะการเลื่อนเนทีฟ และอะไรก็เป็นสิ่งที่ทะเยอทะยานเหมือนกัน ซึ่งทั้งหมดนี้ทำให้ บนแพลตฟอร์มเว็บ อย่างที่ไม่เคยทำได้มาก่อน

เดโม

ฉันทำให้โค้ดสำหรับการสาธิตเป็นโอเพนซอร์ส (การสาธิตแบบสดโดยใช้ polyfill)