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

إمكانات جديدة في الإصدار 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) للإشارة إلى تطبيق رسم صغير.

كتابة عمليّة رسم

لتحديد وحدة عمل للرسم باسم 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. من خلال منح الفئة السمة 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);
}

في المتصفّحات التي تتوافق مع ميزة Paint Worklet، سيحلّ بيان 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، يتم تفعيل هذه الميزة تلقائيًا. يمكنك تجربة الإمكانات الجديدة التي يوفّرها لك ملفّ العمل المخصّص للرسم، وإطلاعنا على ما أنشأته. للحصول على مزيد من الإلهام، اطّلِع على مجموعة "فينسنت دي أوليفيرا".