واجهة برمجة تطبيقات CSS Paint

إمكانات جديدة في الإصدار 65 من Chrome

يتم تفعيل واجهة برمجة التطبيقات CSS Paint API (المعروفة أيضًا باسم "CSS Custom Paint" أو "Houdini’s paint worklet") تلقائيًا اعتبارًا من الإصدار 65 من Chrome. ما هي التجارب المتاحة؟ ما هي الإجراءات التي يمكنك اتّخاذها بشأنه؟ كيف تعمل هذه الميزة؟ حسنًا، يُرجى المتابعة…

تتيح لك واجهة برمجة التطبيقات 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);

داخل دالة الاستدعاء 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>، من المفترض أن يكون هذا الرمز مألوفًا لك. يمكنك الاطّلاع على العرض التوضيحي الحيّ هنا.

مساحة نصية بنمط لوحة شطرنج كصورة خلفية
مساحة نصية تتضمّن نمطًا شبيهًا بشبكة الشطرنج كصورة خلفية.

يختلف هذا الإجراء عن استخدام صورة خلفية عادية، إذ سيتم إعادة رسم النمط عند الطلب، كلما غيّر المستخدم حجم نص النص. وهذا يعني أنّ صورة الخلفية تكون دائمًا بالحجم المطلوب تمامًا، بما في ذلك التعويض عن الشاشات ذات الكثافة العالية.

هذا رائع، ولكنّه ثابت جدًا. هل نريد كتابة قطعة عمل جديدة في كل مرة نريد فيها النمط نفسه ولكن باستخدام مربعات بأحجام مختلفة؟ الإجابة هي لا.

تحديد مَعلمات وحدات العمل

لحسن الحظ، يمكن لوحدة عمل الطلاء الوصول إلى سمات CSS أخرى، وهذا هو المكان الذي تُستخدم فيه المَعلمة الإضافية properties. من خلال منح الفئة سمة static 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);

يمكننا الآن استخدام الرمز نفسه لجميع أنواع لوحات الشطرنج المختلفة. والأفضل من ذلك، يمكننا الآن الانتقال إلى أدوات مطوّري البرامج وتعديل القيم إلى أن نعثر على المظهر المناسب.

المتصفحات التي لا تتوافق مع أداة عمل الطلاء

في وقت كتابة هذه المقالة، لم يتم تنفيذ وحدات عمل الطلاء إلا في Chrome. على الرغم من أنّه هناك إشارات إيجابية من جميع مورّدي المتصفّحات الآخرين، لم يتم إحراز الكثير من التقدّم. للاطّلاع على آخر الأخبار، يُرجى الاطّلاع بانتظام على هل Houdini جاهز؟. في هذه الأثناء، احرص على استخدام التحسين التدريجي للحفاظ على تشغيل الرمز البرمجي حتى في حال عدم توفّر وظائف paint worklet. للتأكّد من أنّ كل شيء يعمل على النحو المتوقّع، عليك تعديل الرمز في مكانَين: CSS وJS.

يمكن رصد مدى توفّر وحدات عمل الطلاء في JavaScript من خلال التحقّق من عنصر CSS: js if ('paintWorklet' in CSS) { CSS.paintWorklet.addModule('mystuff.js'); } بالنسبة إلى CSS، لديك خياران. يمكنك استخدام @supports:

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

من الحيل الأكثر إيجازًا استخدام حقيقة أنّ CSS تلغي تعريف سمة بالكامل ثم تتجنّبه إذا كانت هناك دالة غير معروفة فيه. إذا تحديد موقع مرتين، أولاً بدون وحدات عمل الطلاء، ثم باستخدام وحدات عمل الطلاء، ستحصل على تحسين تدريجي:

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

في المتصفّحات التي تتيح استخدام وحدات عمل الطلاء، سيؤدي البيان الثاني لسمة background-image إلى إلغاء البيان الأول. في المتصفّحات التي لا تتيح استخدام وحدات عمل الطلاء، يكون البيان الثاني غير صالح وسيتم تجاهله، ما يترك البيان الأول ساريًا.

CSS Paint Polyfill

في العديد من الاستخدامات، من الممكن أيضًا استخدام CSS Paint Polyfill، الذي يضيف دعمًا لـ CSS Custom Paint وPaint Worklets إلى المتصفّحات الحديثة.

حالات الاستخدام

هناك العديد من حالات استخدام وحدات عمل الطلاء، وبعضها أكثر وضوحًا مقارنةً بغيرها. ومن بين الإجراءات الأكثر وضوحًا استخدام أداة عمل الطلاء لتقليل حجم DOM. في كثير من الأحيان، تتم إضافة عناصر لإنشاء زخارف باستخدام CSS. على سبيل المثال، في Material Design Lite، يحتوي الزر الذي يضم تأثير التموج على عنصرَين إضافيَين من النوع <span> لتنفيذ التموج نفسه. إذا كان لديك الكثير من الأزرار، يمكن أن يؤدي ذلك إلى زيادة عدد عناصر DOM بشكل كبير، ما قد يؤدي إلى انخفاض الأداء على الأجهزة الجوّالة. إذا كنت تريد تطبيق تأثير التموج باستخدام أداة عمل الطلاء بدلاً من ذلك، لن تحصل على أي عناصر إضافية، بل على أداة عمل طلاء واحدة فقط. بالإضافة إلى ذلك، لديك عنصرًا أسهل بكثير في تخصيصه وتحديد مَعلماته.

من المزايا الأخرى لاستخدام أداة عمل الطلاء أنّ الحلّ الذي يتم إنشاؤه باستخدام أداة عمل الطلاء يكون صغيرًا من حيث عدد البايتات في معظم السيناريوهات. بالطبع، هناك مفاضلة: سيتم تشغيل رمز الطلاء عند تغيير حجم اللوحة أو أي من المَعلمات. لذلك، إذا كانت التعليمات البرمجية معقّدة وتستغرق وقتًا طويلاً، قد تؤدي إلى استخدام الطاقة بشكل غير فعّال. يعمل Chrome على نقل مهام الرسم من سلسلة المهام الرئيسية لكي لا تؤثر حتى مهام الرسم التي تستغرق وقتًا طويلاً في استجابة سلسلة المهام الرئيسية.

بالنسبة إليّ، إنّ أهم ميزة هي أنّ أداة "الرسم" تتيح تضمين ميزات CSS غير المتاحة في المتصفّح بعد. ومن الأمثلة على ذلك استخدام polyfill لإنشاء تدرّجات مخروطية إلى أن يتم طرحها في Chrome بشكل أصلي. مثال آخر: في اجتماع CSS، تم التصويت على إتاحة ألوان حدود متعدّدة. أثناء استمرار هذا الاجتماع، كتب زميلي "إيان كيلباتريك" polyfill لهذا السلوك الجديد في CSS باستخدام أداة paint worklet.

التفكير خارج الصندوق

يبدأ معظم المستخدمين في التفكير في صور الخلفية وصور الحدود عندما يتعرّفون على أداة "عملية الرسم". أحد حالات الاستخدام الأقل وضوحًا لوحدة عمل الطلاء هو mask-image لجعل عناصر DOM ذات أشكال عشوائية. على سبيل المثال، الماس:

عنصر DOM على شكل ماسة
عنصر DOM على شكل ماسة.

يأخذ العنصر mask-image صورة بحجم العنصر. تكون العناصر شفافة في المناطق التي تكون فيها صورة القناع شفافة. المناطق التي تكون فيها صورة القناع معتمة، يكون العنصر معتمًا.

متوفّرة الآن في Chrome

كانت أداة الرسم متاحة في Chrome Canary لبعض الوقت. في الإصدار 65 من Chrome، يتم تفعيل هذه الميزة تلقائيًا. يمكنك تجربة الإمكانات الجديدة التي يوفّرها لك ملفّ العمل المخصّص للرسم، وإطلاعنا على ما أنشأته. للحصول على مزيد من الإلهام، اطّلِع على مجموعة "فينسنت دي أوليفيرا".