API CSS Paint

Khả năng mới trong Chrome 65

CSS Paint API (còn được gọi là "CSS Custom Paint" hoặc "worklet sơn của Houdini") là bật theo mặc định kể từ Chrome 65. Giải pháp này là gì? Bạn có thể làm gì với nó không? Cách hoạt động của tính năng này Chà, đọc tiếp, bạn sẽ...

CSS Paint API cho phép bạn tạo hình ảnh theo phương thức lập trình bất cứ khi nào CSS thuộc tính mong đợi một hình ảnh. Các cơ sở lưu trú như background-image hoặc border-image thường được sử dụng với url() để tải tệp hình ảnh hoặc với CSS được tích hợp sẵn như linear-gradient(). Thay vì sử dụng những thành phần đó, giờ đây bạn có thể sử dụng paint(myPainter) để tham chiếu đến một tệp worklet sơn.

Viết worklet sơn

Để xác định một worklet sơn có tên là myPainter, chúng ta cần tải một hoạt động vẽ CSS tệp worklet bằng CSS.paintWorklet.addModule('my-paint-worklet.js'). Trong đó , chúng ta có thể dùng hàm registerPaint để đăng ký một lớp worklet sơn:

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

registerPaint('myPainter', MyPainter);

Bên trong lệnh gọi lại paint(), chúng ta có thể sử dụng ctx giống như cách chúng ta CanvasRenderingContext2D như chúng ta biết từ <canvas>. Nếu bạn biết cách vẽ trong <canvas>, bạn có thể vẽ trong một worklet sơn! geometry cho chúng tôi biết chiều rộng và chiều cao của canvas mà chúng tôi tuỳ ý sử dụng. properties Tôi sẽ chúng tôi sẽ giải thích ở phần sau của bài viết này.

Làm ví dụ giới thiệu, hãy viết một worklet sơn bàn cờ và sử dụng nó làm hình nền của <textarea>. (Tôi đang sử dụng vùng văn bản vì đây là có thể đổi kích thước theo mặc định.):

<!-- 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);

Nếu trước đây bạn đã sử dụng <canvas>, thì mã này trông quen thuộc. Xem trực tiếp bản minh hoạ vào đây.

Vùng văn bản có hoa văn bàn cờ làm hình nền
Vùng văn bản có hoa văn bàn cờ làm hình nền.

Điểm khác biệt so với việc sử dụng hình nền phổ biến ở đây là hoa văn sẽ được vẽ lại theo yêu cầu, bất cứ khi nào người dùng thay đổi kích thước vùng văn bản. Điều này có nghĩa là hình nền luôn chính xác kích thước cần thiết, bao gồm bù cho màn hình có mật độ điểm ảnh cao.

Thật thú vị nhưng cũng khá tĩnh lặng. Chúng ta có muốn viết một worklet mỗi khi muốn có cùng một mẫu nhưng có kích thước khác nhau hình vuông không? Câu trả lời là không!

Tham số hoá Worklet

May mắn thay, worklet sơn có thể truy cập vào các thuộc tính CSS khác, đây là nơi tham số bổ sung properties sẽ có hiệu lực. Bằng cách cung cấp cho lớp inputProperties, bạn có thể đăng ký nhận các thay đổi đối với bất kỳ thuộc tính CSS nào, bao gồm cả thuộc tính tuỳ chỉnh. Các giá trị sẽ được cung cấp cho bạn thông qua Tham số 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);

Giờ đây, chúng ta có thể sử dụng cùng một mã cho mọi loại bàn cờ. Nhưng ngay cả khi tốt hơn. Giờ đây, chúng ta có thể chuyển đến Công cụ cho nhà phát triển và tìm hiểu các giá trị cho đến khi chúng tôi tìm được giao diện phù hợp.

Các trình duyệt không hỗ trợ vẽ worklet

Tại thời điểm viết bài này, chỉ Chrome mới triển khai worklet vẽ. Trong khi ở đó là những tín hiệu tích cực từ tất cả các nhà cung cấp trình duyệt khác, không có nhiều tiến triển. Để biết thông tin mới nhất, hãy xem phần Is Houdini đã sẵn sàng chưa? thường xuyên. Trong thời gian chờ đợi, hãy nhớ sử dụng các tính năng nâng cao để giúp mã của bạn chạy ngay cả khi không hỗ trợ công cụ vẽ Worklet. Để đảm bảo mọi thứ hoạt động như mong đợi, bạn phải điều chỉnh mã của mình trong có hai vị trí: CSS và JS.

Bạn có thể phát hiện tính năng hỗ trợ worklet vẽ trong JS bằng cách kiểm tra đối tượng CSS: js if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('mystuff.js'); } Về phía CSS, bạn có 2 lựa chọn. Bạn có thể dùng @supports:

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

Một thủ thuật ngắn gọn hơn là sử dụng thực tế là CSS vô hiệu hoá sẽ bỏ qua toàn bộ phần khai báo thuộc tính nếu có một hàm không xác định trong đó. Nếu bạn chỉ định một thuộc tính hai lần — đầu tiên là không vẽ worklet trực tiếp, sau đó là worklet sơn – bạn sẽ nhận được tính năng cải tiến tăng dần:

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

Trong các trình duyệt hỗ trợ vẽ worklet, nội dung khai báo thứ hai của background-image sẽ ghi đè mục đầu tiên. Trong các trình duyệt không hỗ trợ đối với worklet sơn, nội dung khai báo thứ hai không hợp lệ và sẽ bị loại bỏ, để khai báo đầu tiên có hiệu lực.

Chất liệu polyfill của CSS

Đối với nhiều mục đích sử dụng, bạn cũng có thể sử dụng CSS Paint Polyfill, bổ sung tính năng hỗ trợ CSS Custom Paint và Paint Worklet cho các trình duyệt hiện đại.

Trường hợp sử dụng

Có nhiều trường hợp sử dụng công việc sơn, một số trường hợp rõ ràng hơn khác. Một trong những tính năng rõ ràng hơn là dùng worklet sơn để giảm kích thước của DOM. Thông thường, các thành phần đơn thuần được thêm vào để tạo điểm nhấn cho trang trí thông qua CSS. Ví dụ: trong Material Design Lite nút với hiệu ứng gợn sóng chứa 2 phần tử <span> bổ sung để triển khai gợn sóng. Nếu bạn có nhiều nút, số lượng nút này có thể lên tới phần tử DOM và có thể làm giảm hiệu suất trên thiết bị di động. Nếu bạn triển khai hiệu ứng gợn sóng bằng cách sử dụng worklet sơn thay vào đó, bạn sẽ có 0 phần tử bổ sung và chỉ có một worklet sơn. Ngoài ra, bạn có một thành phần nào đó dễ tuỳ chỉnh hơn nhiều và tham số hoá.

Một ưu điểm khác của việc sử dụng worklet sơn là giải pháp trong hầu hết các trường hợp sử dụng worklet sơn có kích thước nhỏ về mặt byte. Tất nhiên, bạn có thể đánh đổi: mã sơn của bạn sẽ chạy bất cứ khi nào kích thước của canvas hoặc bất kỳ tham số thay đổi. Vì vậy, nếu mã của bạn phức tạp và mất nhiều thời gian, mã đó có thể giới thiệu hiện tượng giật. Chrome đang nỗ lực di chuyển lớp vẽ ra khỏi luồng chính để ngay cả các worklet sơn lâu dài cũng không ảnh hưởng đến khả năng phản hồi của chuỗi.

Đối với tôi, triển vọng thú vị nhất là worklet sơn giúp người dùng chèn polyfill các tính năng CSS mà một trình duyệt chưa có. Ví dụ: thành hiệu ứng chuyển màu conic bằng polyfill cho đến họ truy cập Chrome ngay từ đầu. Một ví dụ khác: trong một cuộc họp CSS, đó là quyết định rằng giờ đây bạn có thể có nhiều màu đường viền. Trong khi cuộc họp này diễn ra vẫn tiếp tục, đồng nghiệp của tôi Ian Kilpatrick đã viết một đoạn mã polyfill cho CSS mới này bằng cách sử dụng worklet sơn.

Suy nghĩ sáng tạo

Hầu hết mọi người bắt đầu nghĩ đến hình nền và hình ảnh đường viền khi tìm hiểu về worklet sơn. Một trường hợp sử dụng kém trực quan hơn đối với worklet sơn là mask-image để tạo các phần tử DOM có hình dạng tuỳ ý. Ví dụ: kim cương:

Một phần tử DOM trong hình dạng một viên kim cương.
Một phần tử DOM trong hình dạng một viên kim cương.

mask-image chụp một hình ảnh có kích thước của phần tử. Các khu vực nơi hình ảnh mặt nạ trong suốt, phần tử trong suốt. Khu vực có khẩu trang hình ảnh mờ, phần tử mờ.

Hiện đã có trên Chrome

Worklet Paint đã có trong Chrome Canary một thời gian. Với Chrome 65, bật theo mặc định. Hãy tiếp tục và thử những khả năng mới Worklet bản vẽ đó sẽ mở ra và cho chúng tôi thấy những gì bạn đã xây dựng! Để có thêm nguồn cảm hứng, hãy xem bộ sưu tập của Vincent De Oliveira.