API การแสดงผล CSS

ความสามารถใหม่ๆ ใน Chrome 65

CSS Paint API (หรือที่เรียกว่า "การวาดภาพที่กำหนดเองของ CSS" หรือ "เวิร์กเลตการวาดภาพของ Houdini") จะเปิดใช้โดยค่าเริ่มต้นตั้งแต่ Chrome 65 เป็นต้นไป สิ่งนี้คืออะไร คุณใช้ชื่อช่องทำอะไรได้บ้าง วิธีการทํางานเป็นอย่างไร อ่านต่อเลย แล้วจะ...

CSS Paint API ช่วยให้คุณสร้างรูปภาพแบบเป็นโปรแกรมได้ทุกครั้งที่พร็อพเพอร์ตี้ CSS ต้องการรูปภาพ โดยปกติแล้ว พร็อพเพอร์ตี้อย่าง background-image หรือ border-image จะใช้งานร่วมกับ url() เพื่อโหลดไฟล์รูปภาพ หรือกับฟังก์ชันในตัวของ CSS เช่น linear-gradient() ตอนนี้คุณสามารถใช้ paint(myPainter) เพื่ออ้างอิงเวิร์กเลตการระบายสีแทน

การเขียนเวิร์กเลตการระบายสี

หากต้องการกำหนดเวิร์กเลตการวาดชื่อ myPainter เราต้องโหลดไฟล์เวิร์กเลตการวาด CSS โดยใช้ CSS.paintWorklet.addModule('my-paint-worklet.js') ในไฟล์นั้น เราสามารถใช้ฟังก์ชัน registerPaint เพื่อลงทะเบียนคลาสเวิร์กเลตการระบายสี

class MyPainter {
  paint(ctx, geometry, properties) {
    // ...
  }
}

registerPaint('myPainter', MyPainter);

ภายใน Callback paint() เราจะใช้ ctx ในลักษณะเดียวกับที่ใช้ CanvasRenderingContext2D อย่างที่เรารู้จักจาก <canvas> ได้ หากวาดใน <canvas> ได้ ก็จะวาดในเวิร์กเลตการวาดได้ geometry บอกเราเกี่ยวกับความกว้างและความสูงของภาพพิมพ์แคนวาสที่เราใช้ได้ properties ซึ่งฉันจะอธิบายภายหลังในบทความนี้

ตัวอย่างเบื้องต้นคือมาเขียนเวิร์กเลตการระบายสีตารางหมากรุกและใช้เป็นภาพพื้นหลังของ <textarea> (ฉันใช้ textarea เนื่องจากสามารถปรับขนาดได้อยู่แล้วโดยค่าเริ่มต้น):

<!-- index.html -->
<!doctype html>
<style>
  textarea {
    background-image: paint(checkerboard);
  }
</style>
<textarea></textarea>
<script>
  CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
  paint(ctx, geom, properties) {
    // Use `ctx` as if it was a normal canvas
    const colors = ['red', 'green', 'blue'];
    const size = 32;
    for(let y = 0; y < geom.height/size; y++) {
      for(let x = 0; x < geom.width/size; x++) {
        const color = colors[(x + y) % colors.length];
        ctx.beginPath();
        ctx.fillStyle = color;
        ctx.rect(x * size, y * size, size, size);
        ctx.fill();
      }
    }
  }
}

// Register our class under a specific name
registerPaint('checkerboard', CheckerboardPainter);

หากคุณเคยใช้ <canvas> มาก่อน โค้ดนี้น่าจะดูคุ้นเคย ดูการสาธิตแบบเรียลไทม์ได้ที่นี่

พื้นที่ข้อความที่มีลวดลายตารางหมากรุกเป็นภาพพื้นหลัง
กล่องข้อความที่มีลวดลายตารางหมากรุกเป็นภาพพื้นหลัง

ความแตกต่างจากการใช้ภาพพื้นหลังทั่วไปคือ ระบบจะวาดลวดลายอีกครั้งตามต้องการทุกครั้งที่ผู้ใช้ปรับขนาด textarea ซึ่งหมายความว่ารูปภาพพื้นหลังจะมีขนาดตามที่ต้องการเสมอ รวมถึงมีการชดเชยสำหรับจอแสดงผลที่มีความหนาแน่นสูง

เจ๋งดี แต่ค่อนข้างคงที่ เราจะเขียนเวิร์กเล็ตใหม่ ทุกครั้งที่ต้องการรูปแบบเดียวกันแต่มีสี่เหลี่ยมจัตุรัส ขนาดต่างกันไหม คำตอบคือไม่

การกำหนดพารามิเตอร์ของชิ้นงาน

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

<!-- index.html -->
<!doctype html>
<style>
  textarea {
    /* The paint worklet subscribes to changes of these custom properties. */
    --checkerboard-spacing: 10;
    --checkerboard-size: 32;
    background-image: paint(checkerboard);
  }
</style>
<textarea></textarea>
<script>
  CSS.paintWorklet.addModule('checkerboard.js');
</script>
// checkerboard.js
class CheckerboardPainter {
  // inputProperties returns a list of CSS properties that this paint function gets access to
  static get inputProperties() { return ['--checkerboard-spacing', '--checkerboard-size']; }

  paint(ctx, geom, properties) {
    // Paint worklet uses CSS Typed OM to model the input values.
    // As of now, they are mostly wrappers around strings,
    // but will be augmented to hold more accessible data over time.
    const size = parseInt(properties.get('--checkerboard-size').toString());
    const spacing = parseInt(properties.get('--checkerboard-spacing').toString());
    const colors = ['red', 'green', 'blue'];
    for(let y = 0; y < geom.height/size; y++) {
      for(let x = 0; x < geom.width/size; x++) {
        ctx.fillStyle = colors[(x + y) % colors.length];
        ctx.beginPath();
        ctx.rect(x*(size + spacing), y*(size + spacing), size, size);
        ctx.fill();
      }
    }
  }
}

registerPaint('checkerboard', CheckerboardPainter);

ตอนนี้เราใช้รหัสเดียวกันกับตารางหมากรุกทุกประเภทได้แล้ว แต่ที่ดีกว่านั้นคือตอนนี้เราสามารถไปที่เครื่องมือสำหรับนักพัฒนาเว็บและปรับค่าจนกว่าจะเจอลักษณะที่ถูกต้อง

Values API ของ Houdini เป็นอย่างมาก ซึ่งยังต้องดำเนินการบางอย่างก่อนจึงจะพร้อมใช้งาน

เบราว์เซอร์ที่ไม่รองรับเวิร์กเลตการวาด

ขณะเขียนบทความนี้ มีเพียง Chrome เท่านั้นที่ติดตั้งใช้งานเวิร์กเลตการทาสี แม้ว่าจะมีสัญญาณเชิงบวกจากผู้ให้บริการเบราว์เซอร์รายอื่นๆ ทั้งหมด แต่ก็ยังมีความคืบหน้าไม่มากนัก โปรดติดตามข้อมูลอัปเดตเกี่ยวกับHoudini พร้อมใช้งานหรือยังเป็นประจำ ในระหว่างนี้ โปรดใช้การเพิ่มประสิทธิภาพแบบต่อเนื่องเพื่อให้โค้ดทำงานต่อไป แม้ว่าจะไม่รองรับเวิร์กเล็ต Paint ก็ตาม คุณต้องปรับโค้ด 2 แห่ง ได้แก่ CSS และ JS เพื่อให้ทุกอย่างทำงานตามที่คาดไว้

คุณสามารถตรวจหาการรองรับเวิร์กเลตการวาดใน JS ได้โดยตรวจสอบออบเจ็กต์ CSS ดังนี้ js if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('mystuff.js'); } สำหรับฝั่ง CSS คุณมี 2 ตัวเลือก คุณใช้ @supports ในกรณีต่อไปนี้ได้

@supports (background: paint(id)) {
  /* ... */
}

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

textarea {
  background-image: linear-gradient(0, red, blue);
  background-image: paint(myGradient, red, blue);
}

ในเบราว์เซอร์ที่รองรับเวิร์กเลตการวาด การประกาศ background-image ครั้งที่สองจะเขียนทับครั้งแรก ในเบราว์เซอร์ที่ไม่มีการรองรับ Worklet สี การประกาศครั้งที่ 2 จะไม่มีผลและจะถูกยกเลิกทิ้ง โดยการประกาศครั้งแรกจะมีผล

CSS Paint Polyfill

สำหรับการใช้งานหลายอย่าง คุณยังใช้ CSS Paint Polyfill ได้ด้วย ซึ่งจะเพิ่มการรองรับ Paint Custom CSS และ Paint Worklet ลงในเบราว์เซอร์สมัยใหม่

กรณีการใช้งาน

เวิร์กเลตการระบายสีมีกรณีการใช้งานหลายกรณี ซึ่งบางกรณีเห็นได้ชัดกว่ากรณีอื่นๆ ตัวอย่างที่เห็นได้ชัดอย่างหนึ่งคือการใช้เวิร์กเลตการวาดเพื่อลดขนาด DOM บ่อยครั้งที่มีการเพิ่มองค์ประกอบเพื่อตกแต่งโดยใช้ CSS เท่านั้น เช่น ใน Material Design Lite ปุ่มที่มีเอฟเฟกต์กระเพื่อมจะมีองค์ประกอบ <span> เพิ่มเติม 2 รายการเพื่อใช้เอฟเฟกต์กระเพื่อม หากมีปุ่มจำนวนมาก องค์ประกอบ DOM ก็จะเพิ่มมากขึ้นและอาจทําให้ประสิทธิภาพในอุปกรณ์เคลื่อนที่ลดลง หากใช้เอฟเฟกต์กระเพื่อมโดยใช้เวิร์กเลตการระบายสีแทน คุณจะมีองค์ประกอบเพิ่มเติม 0 รายการและมีเวิร์กเลตการระบายสีเพียงรายการเดียว นอกจากนี้ คุณยังมีสิ่งที่ปรับแต่งและกำหนดพารามิเตอร์ได้ง่ายกว่ามาก

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

สำหรับผมแล้ว โอกาสที่น่าตื่นเต้นที่สุดคือ Paint Worklet ช่วยให้มีการใช้โพลีฟิลล์อย่างมีประสิทธิภาพสำหรับฟีเจอร์ CSS ที่เบราว์เซอร์ยังไม่มี ตัวอย่างหนึ่งคือการใช้การเติมเต็ม conic gradients จนกว่าฟีเจอร์ดังกล่าวจะพร้อมใช้งานใน Chrome โดยค่าเริ่มต้น อีกตัวอย่างหนึ่งคือ ในการประชุม CSS ได้มีการตัดสินใจว่าตอนนี้คุณจะมีเส้นขอบหลายสีได้ ขณะที่การประชุมนี้ดำเนินไป เพื่อนร่วมงานของฉัน Ian Kilpatrick ได้เขียน Polyfill สำหรับลักษณะการทำงานของ CSS ใหม่นี้โดยใช้ Paint Worklet

การคิดนอกกรอบ

คนส่วนใหญ่จะเริ่มคิดถึงภาพพื้นหลังและภาพขอบเมื่อได้เรียนรู้เกี่ยวกับเวิร์กเลตการระบายสี Use Case ที่ไม่ค่อยใช้งานง่ายอย่างหนึ่งสำหรับเวิร์กเลตการระบายสีคือ mask-image ทำให้องค์ประกอบ DOM มีรูปร่างตามต้องการ เช่น เพชร

องค์ประกอบ DOM รูปเพชร
องค์ประกอบ DOM รูปเพชร

mask-image ใช้รูปภาพที่มีขนาดเท่ากับองค์ประกอบ พื้นที่ที่รูปภาพมาสก์โปร่งใส องค์ประกอบจะโปร่งใส พื้นที่ที่รูปภาพมาสก์ทึบแสง องค์ประกอบจะทึบแสง

พร้อมให้ใช้งานใน Chrome แล้ว

Worklet สีอยู่ใน Chrome Canary มาระยะหนึ่งแล้ว ใน Chrome 65 ฟีเจอร์นี้จะเปิดใช้โดยค่าเริ่มต้น ลองใช้โอกาสใหม่ๆ ของฟีเจอร์วาดภาพนี้และแสดงให้เราเห็นสิ่งที่คุณสร้าง ดูแรงบันดาลใจเพิ่มเติมได้ในคอลเล็กชันของ Vincent De Oliveira