عندما تقوم بالشراء من خلال الروابط الموجودة على موقعنا، قد نكسب عمولة تابعة. وإليك كيف يعمل.

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

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

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

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

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

سأركز على ميزة الاتجاه، والتي يمكن ضبطها إما على الوضع الرأسي أو الأفقي:

@media (orientation: portrait) {
.playfield { display: block; }
.overlay { display: none; }
}
@media (orientation: landscape) {
.playfield { display: none; }
.overlay { display: block; }
}

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

في حين أن قواعد CSS هذه تحقق التصميم المرئي الذي كنت أسعى إليه، إلا أن هناك عيبًا. باستخدام هذه الطريقة، ستستمر اللعبة في الانهيار عندما تكون ساحة اللعب مخفية. وخلصت إلى أنني بحاجة أيضًا إلى كتابة التعليمات البرمجية لإيقاف اللعبة مؤقتًا أو استئنافها عند تغيير الاتجاه.

أحداث تغيير الاتجاه

لقد اكتشفت خصائص وأحداث إضافية مثل window.orientation وorientationchange. ومع ذلك، أدركت لاحقًا أن لديهم عيبًا كبيرًا. من الناحية النظرية، يوفر window.orientation موضع الجهاز الحالي معبرًا عنه بزاوية قائمة (إما -90 درجة، 0 درجة، 90 درجة أو 180 درجة). من خلال تسجيل معالج الأحداث لتغيير الاتجاه باستخدام كائن window، يمكن إعلامك عندما تتغير قيمة هذه الخاصية:

window.addEventListener("orientationchange", function() {
if (window.orientation == 90 || window.orientation == -90) {
game.pause(); // landscape mode. } else {
game.resume(); // portrait mode. }
});

إذن أين المصيد؟ من المحتمل أن تفترض أن 0° تعني أعلى، و-90° يسارًا، و90° يمينًا، و180° رأسًا على عقب. وينطبق هذا على iPhone وiPad، حيث تتوقع Apple منك استخدام أجهزتها بشكل أساسي في الوضع الرأسي.

يقوم جهاز Samsung Galaxy S3 اللوحي في قبضة عمودية بتعيين اتجاه النافذة إلى 90˚، وهو ما يفسره الكود الخاص بي بشكل غير صحيح على أنه أفقي
يقوم جهاز Samsung Galaxy S3 اللوحي في قبضة عمودية بتعيين اتجاه النافذة إلى 90˚، وهو ما يفسره الكود الخاص بي بشكل غير صحيح على أنه أفقي

ومع ذلك، على الرغم من أن هواتف أندرويد تناسب النموذج المتوقع، إلا أن الأجهزة اللوحية تكشف قصة مختلفة. تبلغ درجة 0 عند حملها بشكل جانبي، لأن Google تفترض أن الأجهزة اللوحية تُستخدم لأغراض مختلفة عن الهواتف الذكية (مثل مشاهدة فيلم أثناء التنقل).

إذن، هذه هي الحقيقة المزعجة: اتجاه النافذة يتعلق بالاتجاه الأساسي الذي توفره الشركة المصنعة للجهاز، وبالتالي فهو غير متسق عبر الأجهزة. ولهذا السبب تحديدًا، فإن ما يبدو وكأنه تقنية واعدة للغاية لا يمكن الاعتماد عليه في الواقع. في رأيي، من الأفضل تجنبه.

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

في حالتي، للتحقق مما إذا كان الجهاز مثبتًا حاليًا في الوضع الأفقي، أقوم بتمرير السلسلة "(الاتجاه: أفقي)" إلى الدالة window.matchMedia()، ثم تحقق من خاصية التطابقات لكائن MediaQueryList الذي تم إرجاعه بالشكل يتبع:

var query = window.matchMedia("(orientation: landscape)"); console.log("Device held " + (query.matches? "horizontally": "vertically"));

لكي يتم إعلامي عندما يتغير اتجاه الجهاز، أقوم بتسجيل معالج الأحداث عن طريق استدعاء addListener() على كائن MediaQueryList الذي تم الحصول عليه في الكود أعلاه. سوف تتلقى وظيفة رد الاتصال هذا الكائن كوسيطة عند تشغيلها.

var toggleGame = function(query) {
if (query.matches) {
game.pause(); // landscape mode. } else {
game.resume(); // portrait mode. }
}
query.addListener(toggleGame);

عندما لم أعد بحاجة إلى أن يتم إعلامي، أقوم بتمرير نفس وظيفة رد الاتصال إلى RemoveListener() على كائن MediaQueryList:

query.removeListener(toggleGame);

أجد أن JavaScript matchMedia يكمل استعلامات وسائط CSS بشكل جيد. لقد ساعدوني معًا في تحقيق الفصل بين الاهتمامات: التخطيط مقابل التعليمات البرمجية. تتعامل استعلامات وسائط CSS مع التغييرات المرئية اللازمة عند تعديل الاتجاه، بينما تعالج JavaScript matchMedia تغييرات منطق اللعبة.

واجهة برمجة تطبيقات توجيه الجهاز

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

يقوم CSS بتحويل أيقونات الهاتف الذكي الدائرية وفقًا للزوايا الثلاث ألفا وبيتا وغاما، والتي يتم قياسها بواسطة واجهة برمجة تطبيقات توجيه الجهاز
يقوم CSS بتحويل أيقونات الهاتف الذكي الدائرية وفقًا للزوايا الثلاث ألفا وبيتا وغاما، والتي يتم قياسها بواسطة واجهة برمجة تطبيقات توجيه الجهاز

لقد تركت أحداث حركة الجهاز جانبًا لأن لعبتي لا تتطلب قياسات السرعة. وبدلاً من ذلك، ركزت فقط على أحداث توجيه الأجهزة. يتم تقديم بيانات الاتجاه في سلسلة من الدورات حول ثلاثة محاور: X وY وZ. عندما يفتقر الجهاز إلى الأجهزة اللازمة لقياس الزاوية، يتم تعيينه على قيمة خالية. يعتمد الإطار الذي يستخدم لتفسير عمليات التدوير هذه على ما إذا كانت قيمة DeviceOrientationEvent.absolute صحيحة أم خاطئة. عندما يكون صحيحًا، فإنه يستخدم الأرض: X يشير إلى الشرق، وY إلى الشمال، وZ إلى الأعلى. عندما تكون خاطئة، فهي مرتبطة بإطار تعسفي. على سبيل المثال، يمكن لأجهزة الكمبيوتر المحمولة Macbook Pro الإبلاغ عن مدى ميلها للأمام أو للخلف ومدى ميلها إلى اليسار أو اليمين. إنهم يفتقرون إلى أي إحساس باتجاه البوصلة.

  • ألفا هي زاوية الدوران حول Z، وتتراوح في اتجاه عقارب الساعة من 0 إلى 359 درجة. يشير إلى الاتجاه المعاكس لعنوان البوصلة
  • بيتا هي زاوية الدوران حول X، وتتراوح من -180 إلى 179 درجة. يقوم بالإبلاغ عما إذا كان الجهاز مائلًا للأمام أو للخلف (تواجهك الشاشة بزاوية 90 درجة بعيدًا عنك عند -90 درجة، ولأعلى عند 0 درجة ولأسفل عند -180 درجة)
  • جاما هي زاوية الدوران حول Y، وتتراوح من -90 إلى 89 درجة. يُبلغ عما إذا كان الجهاز مائلاً إلى اليسار أو اليمين
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', function(e) {
if (e.absolute) {
console.log('Compass heading:', Math.floor(e.alpha)); }
}); }

ليس من السهل دائمًا تفسير هذه القيم بشكل صحيح، لأنه عندما تقترب زاوية من قيمة زاوية قائمة، تتبدل المحاور (لذلك عندما تكون قيمة بيتا 90 درجة، يشير Y إلى الأعلى ويصبح Z، ويشير Z إلى الجنوب ويصبح -Y)، مما يؤثر على الجيروسكوب والبوصلة الرقمية قراءة٪ s. سوف تؤدي أدنى إيماءة إلى تأرجح الزوايا ذهابًا وإيابًا، مع تقلبات كبيرة في القيمة.

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

دعونا نلخص ما يلي: حتى الآن، تتفاعل لعبتي مع لاعب يحمل أجهزته في أوضاع غير مثالية، ولكن ماذا لو كان بإمكانها فرض اتجاهها المثالي بشكل استباقي؟

واجهة برمجة تطبيقات اتجاه الشاشة

التقنية التالية التي جربتها كانت واجهة برمجة تطبيقات اتجاه الشاشة. تمكنك واجهة برمجة التطبيقات هذه من القيام بثلاثة أشياء. يمكنك الاستعلام عن window.screen لاتجاه الشاشة الحالي، ويتم إعلامك عند تغيير الاتجاه، وفرض اتجاه معين أو إرجاع التحكم في الاتجاه إلى نظام التشغيل.

جهاز Nexus 6 في قبضة عمودية هنا تم قفل شاشته في الوضع الأفقي بواسطة Screen Orientation API
جهاز Nexus 6 في قبضة عمودية هنا تم قفل شاشته في الوضع الأفقي بواسطة Screen Orientation API

يمكنك التفاعل معها من خلال الخاصية window.screen.orientation (تصادف أن تكون الشاشة أيضًا متغيرًا عامًا، ويمكن الوصول إليها مباشرة). يحتوي كائن ScreenOrientation على خاصية للقراءة فقط تسمى النوع، ويقوم بإرجاع إما:

  • صورة أساسية
  • صورة ثانوية (مقلوبة)
  • صورة شخصية (إما مستقيمة أو مقلوبة)
  • أفقي أساسي (الجهاز جانبي، مع وجود الجزء السفلي من الجهاز على اليمين)
  • أفقي ثانوي (جانبي مع الجزء السفلي من الجهاز على اليسار)
  • أفقي (أسفل الجهاز إما على اليسار أو اليمين)
  • طبيعي (يعتبر الاتجاه الافتراضي للشركة المصنعة للجهاز)
  • أي (يفتح الاتجاه، مما يسمح بالوضعين الرأسي والأفقي)

يمكنك تسجيل معالج حدث لحدث تغيير على screen.orientation، ليتم إعلامك بتغييرات الاتجاه المستقبلية:

screen.orientation.addEventListener('change', function() {
console.log('new orientation is ', screen.orientation.type); });

يمكنك قفل الشاشة في اتجاه معين عن طريق استدعاء lock() بأحد أنواع الاتجاه المدعومة. تقوم الدالة lock() بإرجاع كائن الوعد الذي يمكنك إرفاق النجاح ومعالج الأخطاء به. لاحظ أنك تحتاج إلى أن تكون في وضع ملء الشاشة حتى تكون المكالمة ناجحة.

var onGameStart = function() {
document.documentElement.requestFullscreen(); screen.orientation.lock('portrait').then(null, function(error) {
document.exitFullscreen()
}); }

وبالمثل، يمكنك إلغاء قفل الشاشة للسماح لنظام التشغيل بتدويرها بالشكل الذي يراه مناسبًا:

document.exitFullscreen(); screen.orientation.unlock();

تعد واجهة برمجة تطبيقات اتجاه الشاشة جديدة إلى حد ما وما زالت تتطور. ومع ذلك، فهو الخيار الأكثر شمولاً من بين التقنيات الستة إذا كنت تريد التحكم البرمجي الكامل في شاشة الجهاز. عندما يكون المتصفح مدعومًا، فقد استخدمت Screen Orientation API لضمان تشغيل لعبتي في الوضع الرأسي.

بيان تطبيق الويب

الخيار الأخير الذي فكرت فيه هو بيان تطبيق الويب. لا ينبغي الخلط بين هذا وبين بيان تطبيق الويب غير المتصل، والذي يركز على تخزين الأصول مؤقتًا في الأوقات التي تكون فيها الشبكة غير متاحة.

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

أولا أضف أ علامة تشير إلى ملف JSON ذو علاقة واضحة:

ثانيًا، قم بإنشاء ملف JSON يحتوي، من بين أشياء أخرى، على الإدخالات التالية:

{
"display": "standalone", "orientation": "portrait"
}

يمكن أن يكون العرض أحد القيم بملء الشاشة أو مستقل أو الحد الأدنى من واجهة المستخدم أو المتصفح. يمكن أن يكون الاتجاه أيًا من أنواع الاتجاه الموضحة في قسم Screen Orientation API.

وأخيرًا، يمكنك فتح الصفحة في المتصفح وإضافتها إلى الشاشة الرئيسية (في Chrome لنظام Android، "إضافة إلى الشاشة الرئيسية" من قائمة الصفحة).

العرض: يعمل ملء الشاشة بشكل مستقل عن واجهة برمجة تطبيقات ملء الشاشة. من الممكن اكتشاف ما إذا تم تشغيل ملء الشاشة كنتيجة لبيان تطبيق الويب من خلال تقييم استعلام وسائط CSS (وضع العرض: ملء الشاشة) باستخدام JavaScript matchMedia.

if (window.matchMedia("(display-mode: fullscreen)").matches) {
console.log("page entered fullscreen mode through the Web Application Manifest"); } else if (document.fullscreenEnabled && document.fullscreenElement) {
console.log("page entered fullscreen mode through the Fullscreen API")
}

يعد تطبيق Web Application Manifest، الذي يتم تشغيله من الشاشة الرئيسية للجهاز، خيارًا بسيطًا للغاية إذا كنت تريد التحكم (ولكن ليس الاستعلام كثيرًا) عن اتجاه صفحات الويب. من المؤكد أن الحصول على صفحة الويب على الشاشة الرئيسية للجهاز يعد أمرًا غير ملائم من ناحية تجربة المستخدم، ولكن المتصفح الشركات المصنعة ملزمة بتحسين ذلك (تعمل Google على تقديم خيار إضافة الصفحات التي تتم زيارتها بانتظام إلى الشاشة الرئيسية).

يقوم بيان تطبيق الويب بتأمين لعبتي في الاتجاه الرأسي عند تشغيلها من الشاشة الرئيسية لهاتفي
يقوم بيان تطبيق الويب بتأمين لعبتي في الاتجاه الرأسي عند تشغيلها من الشاشة الرئيسية لهاتفي

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

خاتمة

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

  • أفضل سيناريو هو عندما تكون Screen Orientation API متاحة: فهي تقفل اللعبة في الوضع الرأسي ولا يتم تشغيل استعلامات وسائط CSS وJavaScript مطلقًا
  • ثاني أفضل حالة هي عندما يتم تشغيل اللعبة من الشاشة الرئيسية: تضمن Web Manifest API نفس النتيجة
  • بخلاف ذلك، تشجع استعلامات وسائط CSS اللاعبين على تصحيح الاتجاه، بينما تمنع JavaScript matchMedia فقدانهم عند إيقاف اللعبة مؤقتًا

تحقق من الرسم التوضيحي لـ CodePen الخاص بي هذه التقنيات، واسمحوا لي أن أعرف كيف يعملون من أجلك. أشعر بالفضول بشأن البدائل، لذا اتصل بي على تويتر إذا كنت تعرف أيًا منها!

كلمات: جيروم ليكومت

جيروم ليكومت هو مطور الواجهة الأمامية في OANDA Canada. ظهرت هذه المقالة في الأصل في العدد 270 من مجلة نت

أحببت هذا؟ اقرأ هذه!

  • كيف إنشاء تطبيق: جرب هذه الدروس الرائعة
  • برامج التصميم الجرافيكي المجانية متاح لك الآن!
  • تحميل الأفضل الخطوط المجانية