API การแสดงผล CSS

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

CSS Paint API (หรือที่เรียกว่า “CSS Custom Paint” หรือ “Houdini’s Paint Worklet”) คือ เปิดใช้โดยค่าเริ่มต้นใน Chrome 65 เป็นต้นไป สิ่งนี้คืออะไร สิ่งที่คุณทำได้ ด้วยไหม และทำงานอย่างไร อ่านต่อเลย แล้วจะ...

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

การเขียนชิ้นงานสี

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

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

registerPaint('myPainter', MyPainter);

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

สำหรับตัวอย่างเบื้องต้น เราจะมาเขียนเวิร์กเล็ตสีลายตารางหมากรุกและใช้ เป็นภาพพื้นหลังของ <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> มาก่อน โค้ดนี้น่าจะดูคุ้นเคย โปรดดู สด สาธิต ที่นี่

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

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

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

พารามิเตอร์ของ 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);

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

เบราว์เซอร์ที่ไม่รองรับ Worklet Paint

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

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

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

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

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

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

โพลีฟิลล์สำหรับสี CSS

สำหรับการใช้งานหลายอย่าง คุณอาจใช้ CSS Paint Polyfill ซึ่งเพิ่มการรองรับ CSS Custom Paint and Paint Worklets ในเบราว์เซอร์ที่ทันสมัย

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

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

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

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

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

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

วันที่ องค์ประกอบ DOM รูปเพชร
องค์ประกอบ DOM รูปเพชร

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

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

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