اذهب إلى المحتوى

كيفية اكتشاف دعم المتصفحات للميزات أثناء اختبار مشاريع الويب


Ola Abbas

يتضمن اكتشاف الميزات Feature Detection معرفة ما إذا كان المتصفح يدعم كتلةً معينةً من الشيفرة البرمجية ويشغّل شيفرةً مختلفةً اعتمادًا على ذلك، بحيث يمكن للمتصفح دائمًا توفير تجربة عمل ناجحة بدلًا من التعطل أو ظهور الأخطاء في بعض المتصفحات، ويوضح هذا المقال بالتفصيل كيفية كتابة شيفرة اكتشاف المتصفحات للميزات البسيطة وكيفية استخدام مكتبة لتسريع التطبيق والميزات الأصيلة Native لاكتشاف الميزات مثل الميزة ‎@supports.

مفهوم اكتشاف الميزات

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

لنطّلع على المثال الذي تطرقنا إليه في مقال معالجة المشاكل الشائعة للتوافق مع المتصفحات المختلفة في شيفرة جافاسكربت، إذ كان لدينا واجهة Geolocation API التي تعرض بيانات الموقع المتاحة للجهاز الذي يعمل عليه متصفح الويب، ولهذه الواجهة نقطة دخول رئيسية لاستخدامها وهي الخاصية geolocation التي يوفرها الكائن العام Navigator، لذا يمكنك اكتشاف ما إذا كان المتصفح يدعم تحديد الموقع الجغرافي أم لا باستخدام الشيفرة البرمجية التالية مثلًا:

if ("geolocation" in navigator) {
  navigator.geolocation.getCurrentPosition(function(position) {
    // اعرض الموقع على الخريطة باستخدام‫ واجهة Google Maps API مثلًا
  });
} else {
  // اجعل المستخدِم يختار من بين الخرائط الساكنة بدلًا من ذلك
}

لاكتشاف ميزة واحدة، تكفي تعليمة if ولكن يُفضَّل استخدام مكتبة اكتشاف ميزات مُنشَأة مسبقًا من أجل التطبيقات المعقّدة بدلًا من كتابة مكتبتك طوال الوقت، إذ تُعَدّ مكتبة مودرنيزر Modernizr المعيار القياسي لاختبارات اكتشاف الميزات وسنتطرق إليها لاحقًا.

لا تخلط بين اكتشاف الميزات والتعرف على المتصفح Browser Sniffing -أي اكتشاف المتصفح المُحدَّد الذي يصل إلى الموقع- الذي يُعَدّ ممارسةً سيئةً يجب عدم استخدامها، وراجع فقرة استخدام شيفرة التعرف على المتصفح السيئة من مقال معالجة المشاكل الشائعة للتوافق مع المتصفحات المختلفة في شيفرة جافاسكربت للتعرف على مزيد من التفاصيل.

كتابة اختباراتك الخاصة لاكتشاف الميزات

سنتعرّف في هذا القسم على تطبيق اختباراتك الخاصة لاكتشاف الميزات في كل من شيفرة CSS وجافاسكربت.

شيفرة CSS

يمكنك كتابة اختبارات لميزات CSS من خلال اختبار وجود خاصيات element.style.property -مثل الخاصية paragraph.style.transform- في شيفرة جافاسكربت.

يمكن أن يكون المثال التقليدي لذلك هو اختبار دعم قيمة subgrid ضمن التخطيط الشبكي Grid في المتصفح، إذ يمكننا استعمال القيمة subgrid التخطيط الشبكي الفرعي مع grid-template-columns و grid-template-rows في المتصفحات التي تدعم ضمن التخطيط الشبكي أما في المتصفحات التي لا تدعهما فنستخدم التخطيط الشبكي العادي ولكن لن تكون كما نريد مع subgrid.

بناء على المثال السابق، يمكن أن نضيف ملف تنسيق stylesheet ضمن الترويسة head في ملف HTML الأول فيه تنفيذ كل subgrid وذلك إن كانت مدعومة في المتصفح والآخر يستعمل التخطيط الشبكي العادي إن لم تكن مدعومة وذلك لتعويض نقص الدعم الحاصل وتجنب اختلال التنسيق، بالشكل التالي مثلًا:

<link href="basic-styling.css" rel="stylesheet" />
<link class="conditional" href="grid-layout.css" rel="stylesheet" />

يضيف هنا الملف basic-styling.css كل تنسيقات الصفحة المشتركة والمتوافقة لكل المتصفحات، وبالإضافة له يوجد ملفين CSS آخرين الذين أشرنا إليهما قبل قليل، الأول grid-layout.css والثاني subgrid-layout.css وسنضمن ملفًا منهما بناءً على دعم subgrid في المتصفح وسنستعمل لغة جافاسكربت JavaScript لاختبار دعمها ثم نُحدِّث قيمة href الذي يشير إليه العنصر <link> الثاني في الشيفرة السابقة أي ذي الصنف class="conditional"‎ بناء على دعم المتصفح.

نضيف وسم <script></script> إلى ملف HTML في الجزء السفلي من العنصر body قبل وسم الإغلاق <‎/body> مباشرة يحوي الشيفرة التالية:

const conditional = document.querySelector(".conditional");
if (CSS.supports("grid-template-columns", "subgrid")) {
  conditional.setAttribute("href", "subgrid-layout.css.css");
}

اختبرنا في الشيفرة السابقة إن كانت الخاصية grid-template-columns تدعم القيمة subgrid باستعمال التابع CSS.support()‎.

‎@supports

استخدَمتْ لغة CSS في الآونة الأخيرة آليةً لاكتشاف ميزاتها الأصيلة وهي ‎@supports باستخدام القاعدة @ التي تعمل بطريقة مشابهة لاستعلامات الوسائط Media Queries باستثناء أنها تطبّق شيفرة CSS بطريقة انتقائية بناءً على ما إذا كانت ميزة CSS مدعومة، بدلًا من تطبيق شيفرة CSS بطريقة انتقائية اعتمادًا على ميزة وسائط مثل الدقة أو عرض الشاشة أو نسبة العرض إلى الارتفاع aspect ratio.

يمكننا إعادة كتابة مثالنا السابق باستخدام ‎@supports كما يلي:

@supports (grid-template-columns: subgrid) {
  main {
    display: grid;
    grid-template-columns: repeat(9, 1fr);
    grid-template-rows: repeat(4, minmax(100px, auto));
  }

  .item {
    display: grid;
    grid-column: 2 / 7;
    grid-row: 2 / 4;
    grid-template-columns: subgrid;
    grid-template-rows: repeat(3, 80px);
  }

  .subitem {
    grid-column: 3 / 6;
    grid-row: 1 / 3;
  }
}

تطبّق كتلة قاعدة @ تنسيق CSS فيها فقط إذا دعم المتصفح الحالي التصريح grid-template-columns: subgrid;‎. ويجب تضمين تصريح كامل (وليس مجرد اسم خاصية فقط) وعدم تضمين فاصلة منقوطة في النهاية لكي يعمل كل شرط.

يتوفر لدى ‎@supports العبارات المنطقية OR و NOT و AND، فمثلًا ستطبق الكتلة التالية تنسيق التخطيط الشبكي grid العادي إن لم يكن المتصفح يدعم subgrid:

@supports not (grid-template-columns: subgrid) {
  /* ضع القواعد هنا */
}

يمكن أن يبدو ذلك ملائمًا أكثر من المثال السابق، إذ يمكننا تطبيق اكتشاف الميزات في CSS دون الحاجة إلى شيفرة جافاسكربت، ويمكننا التعامل مع جميع العبارات المنطقية في ملف CSS واحد مع تقليل طلبات HTTP، لذا هذه هي الطريقة المفضلة في اكتشاف الميزات دون اللجوء إلى جافاسكربت.

شيفرة جافاسكربت

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

ضع في بالك أن بعض الميزات معروفة بعدم قابليتها للاكتشاف، ارجع إلى صفحة Undetectables بدءًا من عام 2016.

إليك بعضًا من الأنماط الشائعة للميزات القابلة للاكتشاف:

عضو في كائن

تحقق مما إذا كان هناك تابع أو خاصية معينة (تكون عادةً نقطة دخولٍ إلى استخدام واجهة برمجة تطبيقات API أو ميزة أخرى تريد اكتشافها) موجودةً في الكائن الأب Object.

رأينا في مثال سابق استخدامًا لهذا النمط عند اكتشاف دعم واجهة Geolocation وذلك بفحص وجود العضو geolocation في الكائن navigator:

if ("geolocation" in navigator) {
  // navigator.geolocation الوصول إلى الواجهة
}

خاصية في عنصر

أنشئ عنصرًا في الذاكرة باستخدام التابع Document.createElement()‎ ثم تحقق من وجود خاصية فيه، ويوضح هذا المثال طريقةً لاكتشاف دعم الواجهة Canvas API:

function supports_canvas() {
  return !!document.createElement("canvas").getContext;
}

if (supports_canvas()) {
  // ‫ إنشاء عناصر canvas واستخدامها
}

ملاحظة: استخدمنا !! في المثال السابق وذلك لتحويل أي نوع بيانات إلى قيمة منطقية true أو false.

تابع في عنصر يعيد قيمة

أنشئ عنصرًا في الذاكرة باستخدام Document.createElement()‎ ثم تحقق من وجود تابع فيه، فإذا كان موجودًا، فتحقق من القيمة التي يعيدها.

اطلع على اختبار اكتشاف تنسيقات الفيديو في HTML5

خاصية في عنصر تحتفظ بقيمة

أنشئ عنصرًا في الذاكرة باستخدام التابع Document.createElement()‎ ثم اضبط خاصيةً على قيمة معينة، ثم تحقق من الاحتفاظ بالقيمة.

ملاحظة: تُعَدّ قيمة NOT المُضاعفَة في المثال السابق (!!) طريقةً لإجبار القيمة المُعادة لتصبح قيمة منطقية مناسبة بدلًا من القيمة true أو false التي يمكن أن تؤدي إلى تحريف النتائج.

اطّلع على مقال اكتشاف دعم المتصفحات لميزات HTML5 للعثور على مزيد من المعلومات، وضَع في الحسبان أنه توجد بعض الميزات التي لا يمكن اكتشافها بالرغم من كل ذلك.

الميزة matchMedia

تتيح ميزة جافاسكربت Window.matchMedia تشغيل اختبارات استعلام الوسائط ضمن شيفرة جافاسكربت، وتبدو كما يلي:

if (window.matchMedia("(max-width: 480px)").matches) {
  // شغّل شيفرة جافاسكربت هنا
}

يستخدِم تطبيق Snapshot مثلًا هذه الميزة لتطبيق مكتبة جافاسكربت Brick بطريقة انتقائية ويستخدِمها للتعامل مع تخطيط واجهة المستخدم لتخطيط الشاشات الصغيرة فقط (480 بكسل أو أقل)، كما نستخدِم أولًا السمة media لتطبيق مكتبة Brick CSS على الصفحة إذا كان عرض الصفحة 480 بكسل أو أقل فقط:

<link
  href="dist/brick.css"
  rel="stylesheet"
  media="all and (max-width: 480px)" />

نستخدِم بعد ذلك matchMedia()‎ في جافاسكربت عدة مرات لتشغيل دوال التنقل في مكتبة Brick مع تخطيط الشاشة الصغيرة فقط، ويمكن رؤية كل شيء دفعةً واحدةً في تخطيطات الشاشة الأوسع، لذلك لا نحتاج للتنقل بين العروض المختلفة.

if (window.matchMedia("(max-width: 480px)").matches) {
  deck.shuffleTo(1);
}

استخدام مكتبة Modernizr لتطبيق اكتشاف الميزات

يمكن تنفيذ اختبارات اكتشاف الميزات باستخدام تقنيات مثل التقنيات التي أوضحناها سابقًا، ويمكنك استخدام مكتبة مخصَّصة لاكتشاف الميزات لأنها تسهّل الأمور كثيرًا. تُعَد مكتبة Modernizr أساس جميع مكتبات اكتشاف الميزات، ويمكنها اكتشاف كل ما تحتاجه في أي وقت، ولنلقِ نظرةً على كيفية استخدامها.

يمكنك استخدام بناء التطوير الذي يتضمن كل اختبار ممكن لاكتشاف الميزات عندما تجرّب مكتبة Modernizr، لذا نزّل بناء التطوير كما يلي:

  1. انقر على رابط بناء التطوير.
  2. انقر على زر "البناء Build" الوردي الكبير على الصفحة التي تظهر.
  3. انقر على رابط "التنزيل Download" الأعلى في مربع الحوار الذي يظهر.

احفظه في مكان ما مثل المجلد الذي تنشئ أمثلتك الأخرى فيه.

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

شيفرة CSS

لنلقِ نظرةً على كيفية عمل مكتبة Modernizr من حيث التطبيق الانتقائي لشيفرة CSS.

أنشئ أولًا نسخةً من الملفين supports-feature-detect.html و supports-styling.css ثم احفظهما بالاسم modernizr-css.html و modernizr-css.css.

ثانيًا، عدّل العنصر <link> في شيفرة HTML بحيث يشير إلى ملف CSS الصحيح، ويجب تعديل العنصر <title> إلى شيء أكثر ملاءمةً:

<link href="modernizr-css.css" rel="stylesheet">

ثالثًا، أضِف العنصر <script> قبل عنصر <link> لتطبيق مكتبة Modernizr على الصفحة، إذ يجب تطبيق ذلك على الصفحة قبل أيّ شيفرة CSS (أو جافاسكربت) تستخدِمها.

<script src="modernizr-custom.js"></script>

رابعًا، عدّل وسم الفتح <html> بحيث يبدو كما يلي:

<html lang="en-us" class="no-js"></html>

جرّب تحميل صفحتك، وستحصل على فكرة عن كيفية عمل مكتبة Modernizr مع ميزات CSS، فإذا ألقيت نظرةً على فاحص DOM الخاص بأدوات المطور في متصفحك، فسترى أنّ مكتبة Modernizr قد حدّثت قيمة صنف class العنصر <html> كما يلي:

<html
  class="js no-htmlimports no-proximity sizes no-flash transferables applicationcache blobconstructor blob-constructor no-contextmenu (and loads of more values)"></html>

يحتوي هذا العنصر الآن على عدد كبير من الأصناف التي تشير إلى حالة دعم ميزات التقنيات المختلفة، فإذا لم يدعم المتصفح الميزة التخطيط الشبكي grid مثلًا على الإطلاق، فسيُعطَى العنصر <html> اسم الصنف no-cssgrid، كما هنالك عدة أصناف أخرى متعلقة مثلًا بالتخطيط grid مثل cssgridlegacy أو no-cssgridlegacy بناء على دعم المتصفح للإصدار القديم legacy من التخطيط الشبكي.

ملاحظة: يمكنك الاطلاع على قائمة الأصناف الكاملة وما تعنيه أسماؤها وما تقوم به بالرجوع إلى صفحة Features detected من Modernizr.

لسوء الحظ لا تفحص مكتبة Modernizr دعم بعض ميزات CSS الجديدة مثل subgrid التي رأيتها للتو وغيرها ولو كانت تفعل ذلك، لكنا عدلنا مثال ‎@support السابق بالشكل التالي:

main {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: repeat(4, minmax(100px, auto));
}
.item {
  display: grid;
  grid-column: 2 / 7;
  grid-row: 2 / 4;
  grid-template-rows: repeat(3, 80px);
}
/* ‫خاصيات المتصفحات مع خاصية subgrid الحديثة */
.csssubgrid .item {
  grid-template-columns: subgrid;
}
.csssubgrid .subitem {
  grid-column: 3 / 6;
  grid-row: 1 / 3;
}
/* ‫الإجراءات الاحتياطية للمتصفحات التي لا تدعم خاصية subgrid الحديثة */
.no-csssubgrid .subitem {
  display: flex;
  flex: 33%;
}

يمكنك استهداف المتصفحات التي تدعم أو التي لا تدعم ميزة معينة باستخدام محددات أحفاد معينة بسبب وضع جميع أسماء الأصناف في العنصر <html>. لذلك طبّقنا هنا المجموعة العليا من القواعد فقط على المتصفحات التي تدعم subgrid ومجموعة القواعد السفلية فقط على المتصفحات التي لا تدعمها.

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

شيفرة جافاسكربت

مكتبة Modernizr مُهيَّأة جيدًا لتطبيق اكتشاف ميزات جافاسكربت من خلال توفير كائن Modernizr العام للصفحة التي تُطبَّق عليها، ويحتوي هذا الكائن على نتائج اكتشاف الميزات بوصفها خاصيات true أو false.

حمّل المثال modernizr-css.html في متصفحك، ثم حاول الانتقال إلى طرفية جافاسكربت واكتب Modernizr.‎ متبوعةً ببعض أسماء هذه الأصناف كما يلي:

Modernizr.flexbox
Modernizr.xhr2
Modernizr.fetch

ستعيد الطرفية قيم true أو false للإشارة إلى ما إذا كان متصفحك يدعم هذه الميزات أم لا.

لنلقِ نظرةً على مثال لتوضيح كيفية استخدامك لتلك الخاصيات:

أنشئ أولًا نسخةً محليةً من الملف modernizr-js.html.

ثانيًا، اربط مكتبة Modernizr بشيفرة HTML باستخدام العنصر <script> كما فعلنا سابقًا ثم ضع هذا العنصر قبل العنصر <script> الموجود مسبقًا الذي يربط واجهة Google Maps API بالصفحة.

املأ بعد ذلك نص العنصر البديل YOUR-API-KEY في عنصر <script> الثاني بمفتاح Google Maps API صالح، ويمكنك الحصول على مفتاح من خلال تسجيل الدخول إلى حساب Google، والانتقال إلى صفحة الحصول على مفتاح أو المصادقة ثم انقر على الزر الأزرق "الحصول على مفتاح Get a Key" واتبع التعليمات.

أخيرًا، أضِف عنصر <script> آخر في الجزء السفلي من العنصر <body> وقبل وسم الإغلاق <‎/body> مباشرةً ثم ضع السكربت التالي ضمن الوسوم:

if (Modernizr.geolocation) {

  navigator.geolocation.getCurrentPosition(function(position) {

    let latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
    let myOptions = {
      zoom: 8,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.TERRAIN,
      disableDefaultUI: true
    }
    let map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
  });

} else {
  const para = document.createElement('p');
  para.textContent = 'Argh, no geolocation!';
  document.body.appendChild(para);
}

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

الخلاصة

لقد غطينا في هذا المقال اكتشاف دعم المتصفحات للميزات وعرضنا المفاهيم الرئيسية ووضحنا كيفية تطبيق اختبارات اكتشاف ميزاتك واستخدام مكتبة Modernizr لتطبيق الاختبارات بسهولة أكبر، وسنوضح في المقال التالي الاختبارات الآلية.

ترجمة -وبتصرُّف- للمقال Implementing feature detection.

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...