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

نذير صغير

الأعضاء
  • المساهمات

    15
  • تاريخ الانضمام

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    6

كل منشورات العضو نذير صغير

  1. العديد من الناس يرغبون في بناء مواقع باستخدام ووردبريس، والأغلب قد لا يجيد الأمر ويلجأ إلى مطور مستقل للقيام للأمر، ولكنه يواجه مشكلة في معرفة الأسعار بشكل صحيح، البعض قد يطلب مبلغًا صغيرا يجعلك تبتعد عنه تماما والآخر يطلب مبلغا هائلا يجعلك تعيد التفكير في الأمر. أما بالنسبة للمطورين، فتحديد سعر ما لمشروع ووردبريس أمر صعب جدا، فالأمر تدخل فيه الكثير من الحسابات والأمور، وتحديد السعر الساعي صعب أيضا. ولكن لنقل أنك تحتاج أن تعطي العميل سعرا ثابتا (بعد تقدير عدد الساعات وضربها في سعر الساعة) فأنت تحتاج أن تعرف كم سيحتاج منك الأمر بالتحديد، فأنت لا تريد أن تُبخس حقك، ولا تريد أن ترفع السّعر فتأخذ أكثر من حقك أو تبعد العميل. الأرقام التالية ستكون مبنية على خبرتي، وهي مخصصة لمطور ووردبريس خبير ومتمرس في الأمر إلى جانب تمرسه في تركيب ووردبريس على استضافات. الوقت هو المال سنقوم في هذا المقال بتحديد قيمة العمل انطلاقا من الوقت المطلوب لتنفيذه، ولذا سنقوم بسرد مجموعة أعمال ووردبريس شائعة وتحديد الوقت اللازم لتنفيذها. الوقت والمال هما وجهان لعملة واحدة، فأنت ستُسعّر مشروعك انطلاقا من الوقت الذي تعتقد أنه سيتطلب منك إنهائه، لذا هذه المقالة ستكون مفيدة لكل من المطورين والعملاء لفهم كم من الوقت ستحتاجه لتنفيذ بعض مهمات ووردبريس. هذه الأوقات مبنية على خبرتي الشخصية ولذلك قد تختلف عنك كثيرا لكنها أقرب ما استطعت الوصول إليه، لكن قم أنت بتعديلها انطلاقا من الظروف العمل الذي تقوم به. وملاحظة أخيرة: “ساعة” أو “دقيقة” يقصد بها الوقت الصافي التي تم استغلاله في التفكير أو العمل على مشروع العميل فحسب ولا شيء غير هذا، لذا محادثة 30 دقيقة مع العميل تحتسب 30 دقيقة، لكن 5 دقائق لإعداد حاسوبك + 10 لإحضار القهوة+ 10 دقائق لحل مشكلة في الموقع تحتسب 10 دقائق فقط لأنّك لم تقم سوى بـ 10 دقائق من العمل الفعلي. الأوقات التقريبية لمهمات ووردبريس الشائعة هذه القائمة تحتوي على مجموعة من مهمات ووردبريس الشائعة، والوقت الذي معها هو الوقت المطلوب للقيام بالمهمة بتركيز تام، رغم أن بعض المهمات قد تزيد في الوقت بشكل غير محسوب. تسجيل الدخول وتحديث ووردبريس : 2 إلى 5 دقائق. تنصيب إضافة أو حل مشكلة تتمحور حول تنصيب إضافة (كتنصيب akismet لحذف spam) : 5 دقائق. إعداد بريد إلكتروني عبر نطاق الموقع : 5 دقائق. تسجيل الدخول إلى موقع وتعديل محتوى منشور أو إعداد وإعادة ترتيب روابط التصفح : 5 دقائق. مساعدة عميل في استعادة بيانات تسجيل الدخول، إضافة مستخدم جديد: 5 دقائق. تعديلات CSS بسيطة (تغيير لون عنصر ما، تغيير خط، تغيير مكان عنصر ما وإعطائه خواص جديد): 5 إلى 25 دقيقة. إعداد حساب تويتر للمدونة: 10 دقائق. تنصيب ووردبريس انطلاقا من استضافة محجوزة (إلى جانب إعداد قاعدة البيانات): بعض الوقت لرفع الملفات عبر FTP: حوالي 15 دقيقة عمل. تحديث ووردبريس وكل الإضافات والتأكد أن كل شيء يعمل كما هو مطلوب ولا شيء تعطل: 10 إلى 45 دقيقة. استخدام إضافة ما لبناء شيء ما في الموقع وإعداده (نموذج اتصّال، إعداد الأزرار الاجتماعية) : 10 إلى 30 دقيقة. شراء استضافة وإعدادها لتنصيب ووردبريس عليها (تحديد اسم مستخدم وكلمة مرور إلى جانب FTP وما شابه): 15 دقيقة. نقل موقع ووردبريس عبر استخدام إضافة، من البداية للنهاية إلى جانب الاختبار: 15 دقيقة. تحديد وإصلاح مشكلة في الاستضافة وما شابه (أمور لا علاقة لها بووردبريس مباشرة) : 15 دقيقة إلى ساعة. بناء صفحة فيسبوك للمدونة: 20 دقيقة. استقبال ثغرة أو خطأ عبر رسالة في البريد، إيجاد المشكلة الواضحة في PHP أو في JS، إصلاح المشكلة، رفع الإصلاح، التأكد من أنه يعمل، مراسلة العميل حول الأمر: 20 إلى 45 دقيقة. شراء اسم نطاق واستضافة وتنصيب ووردبريس عليها وإعداد النّطاق ليوجه لها: 30 إلى 45 دقيقة. البحث وإيجاد وإصلاح مشكلة غير واضحة وغير شائعة: 30 دقيقة إلى 5 ساعات لأغلب المشاكل. نقل موقع ووردبريس يدويا، من البداية للنهاية إلى جانب الاختبار: ساعة واحدة. أقصر مدة لتطوير موقع ووردبريس هذه أقصر مدة من وقت العمل الحقيقي لإعداد موقع ووردبريس قابل للاستخدام للعميل. هذه الأوقات إما تأتي عن تجربة سابقة أو تقدير نسبي لأقل وقت ممكن. هذه الأوقات تحتوي وقت العمل فقط، ولا تحتوي العمل الجانبي (الاستشارة الأولية، التخطيط، التحديد، التجريب من قبل العميل، إرسال دفعات العمل وما إلى ذلك). فهي ببساطة عبارة عن مجموعة من الأعمال المذكورة من قبل، مثل”اختيار استضافة وتنصيب ووردبريس عليها”، إضافة إلى بعض الأعمال، مثل تعديل واجهة الموقع بشكل بسيط. مدونة ووردبريس بسيطة جدا إلى جانب تنصيب قالب ووردبريس بسيط، من دون أيّة تعديلات: ساعتان. سيتضمن هذا تنصيب ووردبريس وتنصيب قالب ووردبريس على استضافة وإعداد النّطاق وإعداد اسم الموقع والروابط إلى جانب تنصيب إضافة أو اثنتان. موقع ووردبريس لشركة أو مشروع ما (صفحة رئيسية، صفحة عن الموقع، صفحة التواصل، وربما مدونة) على قالب مدفوع بتخصيص بسيط جدا: 8 ساعات. يتضمن هذا الوقت الأدنى لإطلاق موقع ووردبريس لشركة أو لخدمة ما، قد يتضمن هذا نموذج تواصل وقليلًا من التعديل على التصميم. متجر إلكتروني بسيط: 20 ساعة. سيتضمن هذا موقع ووردبريس بسيط يستخدم wooComerce وقادر على عرض وتصنيف منتجات ومعالجة خدمات الزبائن. العمل الجانبي على مشاريع العملاء العمل الجانبي، ويقصد به عدد ساعات العمل التي لم يتم فيها العمل مباشرة على تطوير الموقع، أيّ كل العمل غير التقني. العمل الجانبي قد لا يتم احتسابه (مكالمة أولية للاستشارة) أو يتم احتسابه (الرد على بريد عميل يحتوي ملاحظات على العمل). مجمل المحادثات الأولية والاستشارة قبل بدء العمل المدفوع : ساعة إلى 4 ساعات. الوقت لتقديم حجم المشروع: 45 دقيقة. تواصل جانبي، يتضمن التواصل اليومي لحالة المشروع، الملاحظات، الدفع وما شابه: 3 إلى 6 ساعات من أجل مشروع بحجم أقل من 40 ساعة. “المفاجآت” ويقصد بها أن العميل قد يملك استضافة مبهمة ومعقدة (استضافة باللغة الصينية مثلا)، مشاكل غير متوقعة، تدريب العميل على استخدام بعض خواص ووردبريس: 0 إلى 8 ساعات لمشروع أقصر من 40 ساعة. كل المشاريع تقريبا تملك هذه الأعمال الجانبية، والبعض منها قد يملك أكثر إذا واجهت مشاكل في التواصل مع العميل، أو أن العميل يصر على حضورك شخصيًا إلى مكتب الشّركة. طريقة مرور الوقت في مشروع ما أغلب المشاريع تعطيك الشعور بأنك “تقريبا انتهيت من العمل” في أغلب وقت المشروع. هذا لأن الانتقال من “بناء الموقع” إلى “وضع الموقع أمام الملأ” يكشف الكثير من التفاصيل الجديد والتعقيدات التي قد لا تظهر في بداية العمل، كمثال الاستضافة بطيئة جدا، أو لا تعمل مع بعض الإضافات أو حتى مع القالب بسبب قدم نسخة PHP فيها مما يجعلك تنقل المشروع لاستضافة أخرى، أو أنّ نموذج “تواصل معنا” قد لا يعمل بشكل صحيح مع خدمة البريد الخاصة بالعميل. بناء الموقع (معظم ما تمت تغطيته في تقديم المشروع الأولي): 60% من عمر المشروع. الجزء الذي تشعر فيه أن العمل “سأنهيه اليوم”، نقل موقع جاهز، اختبار الموقع مع العميل، إصلاح بعض المشاكل التي لم تظهر من قبل، وتحسينات لم يكن تم الاتفاق عليها من قبل، وإضافات جديدة: 40% من وقت المشروع. دورة عمر المشروع الفعلية هذا هو الوقت المتوقع الكامل لتطوير موقع كامل قابل للاستخدام إلى جانب العمل الإضافي إلى جانب الأخذ بالاعتبار أنّ المشروع يصبح أكثر تعقيدا مع نهايته. الوقت الفعلي المطلوب لبناء موقع ووردبريس: المدة من “أقصر مدة لتطوير موقع ووردبريس” مضروبة في 1.5 إلى 3. مُعامل تضخيم الوقت يختلف من عميل لآخر ومن مشروع لآخر ومن مستوى التواصل مع العميل ولحظات إيجاد حل ما لمشكلة معينة. المشاريع التي يصعب تحديد حجمها، الأعمال التقنية هنا سنتكلم بشكل موجز حول مشاريع ووردبريس التقنية التي تتطلب أكثر من “تنصيب ووردبريس وتعديل قالب جاهز”. نتكلم عن هذه المشاريع بشكل منفصل لأن حجمها وقيمتها يصعب تحديدها لأن حجم المشروع لا يتعلق بمدة التواصل مع العميل بل من الطلبات التقنية فيه. هذا التعقيد يصعب تحديده في البداية المشروع (إذا كنت تعرف قيمة التعقيد فأنت في الأغلب قد وصلت لنهاية المشروع) لذا المشاريع التقنية يصعب تحديد قيمتها. بناء قالب لصفحة ووردبريس انطلاقا من تصميم PSD جاهز: 3 إلى 10 ساعات على حسب تعقيد التصميم. بناء موقع ووردبريس متكامل الخيارات على قالب مدفوع، مع تعديل كبير على التصميم والعديد من الإضافات الخاصة (مثل رزنامة شخصية خاصة وعارض صور معقد): 40 إلى 100 ساعة للمشروع. ربط وإعداد إضافة خارجية لجعل ووردبريس يقوم بعمل خاص لم يتم بناؤه من أجله (عرض الدورات، عرض عقارات، حجوزات مطاعم، تمويل المشاريع وجمع التبرعات): 15 إلى 100 ساعة. تصميم وتطوير موقع ووردبريس بقالب خاص تماما: 60 إلى 250 ساعة. كتابة إضافة جديدة تماما تحل مشكلة فريدة من نوعها لم يتم حلها من قبل: 20 إلى 300 ساعة. الوقت المطلوب لكتابة ونشر مقالة في خبرتي الشخصية، هذا هو الوقت المطلوب لإخراج مقالة إلى العلن: مقالة سريعة تتكلم عن موضوع ما: 2 إلى 4 ساعات. مقالة جيّدة، مدققة ومفكر فيها بشكل جيد: 4 إلى 7 ساعات مقالة طويلة بشكل غير معهود، مفكر فيها، بجودة عالية (النوع الذي ينتشر بكثرة وبسرعة) : 7 إلى 20 ساعة. خاتمة الهدف من هذه المقالة هو تحديد أرقام مبدئية لمشاريع ووردبريس، مع التذكير بأن هذه الأرقام غير مثالية أو خالية من الخطأ بل مبنية على خبرات شخصية وخبرات مجمعة. والآن، كيف تبدو لك هذه الأرقام، منطقية؟ خارج المعقول؟ أخبرنا برأيك وبتجربتك ترجمة -وبتصرّف- للمقال: How Long Does Building a WordPress Site Take? حقوق الصورة البارزة محفوظة لـ freepik
  2. أضف الرابط الذي أتى منه في parameter في GET بمعنى عندما ترسله لصفحة تسجيل الدخول أضف معها الرابط الذي اتى منه post.php يعني يعرف إلى أين يتم تحويله بعد تسجيل الدخول
  3. لتعريف منصة Meteor.js فهي منصة تستخدم MongoDB لقاعدة البيانات و nodeJS لبرمجة في السيرفر و (Blaze || React || Angular) للواجهة، إضافة إلى أمور أخرى تجعل منها منصة تطويرية كاملة. الشيء المميز حقا في Meteor هو أنها تعمل ب Real-time فهي تسمح لك ببناء تطبيقات ومواقع Real-time ببساطة كبيرة جدا تخيل أنك تبني موقعا مثل Google Docs بخاصية التعاون، القيام بهذا بطريقة أخرى لوحدك أمر شبه مستحيل (إن لم أقل مستحيل تماما) فأنت تحتاج إلى فريق كبير، وفريق كبير من أفضل المبرمجين لتقوم بهذا، وهذا ما سمح لغوغل ببنائه، ولكن مع Meteor تستطيع بناء تطبيق شبيه به إلى حد بسيط في أقل من يوم. التطبيقات Real-time صعبة جدا، صعبة لدرجة أن الناس تتجاهلها تماما في أغلب الوقت، ولكن Meteor قامت بجلب أفضل الأمور حول هذا الأمر وجمعها في مكان واحد، هذا يعني أمور مثل socket.io, node.js, LunaScript وما شابه من أمور في هذا المجال. الشيء الذي يجعل Meteor قادرة على القيام بهذا هو استخدامها تقنية تسمح لها بإرسال جزء من قاعدة البيانات للمستخدم عند دخوله التطبيق لأول مرة، هذا ما يجعل من تطبيقات Meteor سريعة جدا، حيث أن كل التعديلات تتم أولا محليا على القاعدة المحلية أمام المستخدم ثم يتم إرسالها للقاعدة الرئيسية، السبب في هذا هو أن Meteor تتشارك الكود مع المتصفح. وتقوم بتحديث قاعدة البيانات في حال حصول أي تغيير في القاعدة الرئيسية بسرعة حتى تحصل على النتائج مباشرة مشاركة الكود مع المتصفح تجعل من البرمجة باستخدام Meteor أمر سهلا جدا، برمج وكأنك تبرمج بلغة في السيرفر ولكن باستخدام جافاسكربت، لا يوجد داعي لجلب البيانات عبر REST API و AJAX كل ما تقوم به هوو حقن المعلومات مباشرة. البدأ بالعمل والنقل أمر سهل جدا، حمل منصة Meteor وبسطر واحد تستطيع بدأ مشروع يعمل بشكل كامل، وبسطر أخرى تستطيع تحويل مشروعك إلى ملف tar لتفكه في السيرفر ويعمل مباشرة
  4. سيكون عليك تعلم جافاسكربت في البداية، ففهم المبادئ فيها أمر أساسي جدا. المرحلة الثانية هي تقدير كم من الوقت تملك وماهي قدرتك على التعلم. حاليا يوجد العديد من المصادر لـ AngularJS وهي أكثر بكثير من مصادر ReactJS هذا لأنه قبل سنة لم يكترث الكثير من الناس إلى ReactJS أما الآن فمطوروا ReactJS المحترفيين هم عملة نادرة. إن لم تكن تملك مشكلة في مصادر التعلم، بمعنى طالما لا تمانع قراءة الكتب وتوثيق اللغات لتعلم لغة ما فأنت للآن في مكان جيد لاختيار ReactJS لكن سيكون عليك لاحقا التضحية بالشعبية الحالية لـ angularJS مقابل الشعبية المتزاية لإطار ReactJS في وقت كتابة هذا الجواب، Angular تملك 42 ألف نجمة في github أما بالنسبة لReact فهي 28 ألف لكن شعبية React في تزايد مع الوقت، ومع وقت انتهائك من التعلم سيكونان في نفس المرتبة، لذا لا مشكلة هنا، الفرق سيكون كما قلنا من مصادر التعلم والإضافات. نقطة أخرى وهي، إن كانت لك خبرة في أيّ مكتبات أخرى مثل backbone أو ember أو knockout فتعلم React سيكون سهلا، والعكس صحيح، فهي شبيهة لهذه المكتبات، على عكس Angular التي تختلف عنهم في الكثير من الأمور، لذا الانتقال صعب في تلك الحالة. نقطة أخيرة أحب التنويه لها هي أنّ react تشكل جزء view فحسب من mvc بمعنى أنه إذا أردت التعامل مع بيانات خارجية فيجب عليك الاستعانة بمكتبات خارجية، مثل Flux. لكن React في حالة تقدم ممتاز مؤخرا، فـ facebook قدمت مؤخرا React Developer Tools وهي أداة رائعة لمساعدة التطوير ب React عبر المتصفح. ملاحظة أخيرة وهي أن react تكتب بواسطة JSX وهي نسخة مطورة قليلا من JS وسيكون عليك الاستعانة بمترجم لاستخدامها من المتصفح مباشرة. لا أحب أن يكون ردي حياديا، فالحيادية ليست مفيدة دوما، أنا أقترح عليك تعلم React ولكن أنصحك بقوة بإلقاء نظرة على كل من الإطارين وتجربة بناء شيء بسيط بهما (todo list) حتى تعرف أي واحد منهم سيساعدك أكثر
  5. ووردبريس هو منصة رائعة لإدارة المحتوى. إذا كنت تملك أيّ محتوى يأتي في شكل وحدات شبيهة بالمقالات (أو ما شابهها مثل منتجات) فلا أجد سببا يدفعك لعدم استخدام ووردبريس. قد يكون التعاون باستخدام سكربت ميديا ويكي سهل أيضا، واستخدام دروبال مع أنظمة الشركات يعد أمرا سهلا وشائعا، لكن ووردبريس له مكانته أيضا في هذا المجال، وهو في رأيي، يوفر تجربة تحرير أفضل. أحد الطرق لجعل المحتوى في ووردبريس يعمل بشكل أفضل هو إضافة معلومات إضافية له (metadata). قد يكون الأمر على شكل تصنيفات خاصة (taxonomies) أو على شكل بيانات تستخدم لهدف واحد (custom fields). ماهو الحقل المخصص في ووردبريس؟إذا أردت أن تستخدم معلومات محددة متغيرة لكل مقال ما (أو شيء شبيه بمقال كمنتج)، هنا تستطيع استخدام الحقول المخصصة في ووردبريس. "الحقول المخصصة" لها تسميتان مختلفتان في ووردبريس، غالبا ما يطلق عليها خصائص المنشور أو المعلومات الجانبية (post metadata) أو post_meta وعادة ما يطلق عليها باسم الحقول المخصصة، وهذه الترجمة الرسمية التي يستخدمها فريق ترجمة ووردبريس العربي. نحن نضيف الحقول المخصصة عندما نريد أن نخزن خصائص إضافية لمنشور ما. منشورات ووردبريس تأتي بالعديد من الخصائص الإضافية بشكل مسبق: تاريخ النشر، كاتب الموضوع، آخر وقت تّم التعديل عليهم. لكنك قد تريد المزيد، مثلا تريد أن تضيف عنوانا ثانويا للمنشور، أو تريد أن تضيف ملخص المنشور تصميم منفرد. ووردبريس يقوم بتخزين هذه المعلومات في قاعدة البيانات، وباستخدام دوال معينة نقوم بتحديدها وتخزينها واسترجاعها. الحقول المخصصة تنفرد عن خيارات الموقع site_settings حيث أنّ لهم علاقة بالمنشور وليس بالموقع ولكن كلاهما يعملان بنظام عنوان وقيمة key/value pair يتم استخارجهم من قاعدة البيانات عبر دوال محددة، لذا إن كانت لك تجربة بنظام خيارات الموقع Settings API فلن تواجه مشكلة في فهم الحقول المخصصة. كيف أضيف الحقول المخصصة لمنشور؟هناك العديد من الطرق التي تستطيع استخدامها لإضافة الحقول المخصصة، الواجهة الافتراضية للتعامل مع الحقول الخاصة في ووردبريس قديمة ولم يتم تحديثها منذ مدة، ورغم أنها تخدم الهدف إلا أنها بعيدة عن المثالية. الجزء المضاف في الأسفل "ما بعد الأساسيات" سيدخل في التفاصيل حول خيارات أخرى تستطيع اللجوء لها من أجل التحكم في الحقول الخاصة، لكن سنقوم الآن بفهم الواجهة الأصلية فحسب، لأنها ستكون موجودة دوما في كل المواقع. في شاشة التعديل على منشور ستجد صندوق "خصائص إضافية"، وستقوم أنت بتعديل الحقول المخصصة فيه. لا داعي لنمر على كامل معلومات تكوين الصندوق، ستقوم ببساطة باختيار الاسم (أو تضيف واحدا جديدا في حال لم تقم بالأمر من قبل). من ثم تقوم بإضافة القيمة، إضغط على الزر ولقد قمت بإضافة الحقل إلى منشورك، محفوظا مع بقية عناصرك. إظهار الحقول المخصصة في منشوراتكلتستخدم الحقول الخاصة في منشوراتك أمامك عدة دوال، وتسمياتهم تختلف حسب طريقة تكلم الناس عنهم، الدوال الأساسية هي كالتالي: ()the_meta: مثل كل دوال ووردبريس التي تبدأ بـ _the فدالة ()the_meta الهدف منها طبع المعلومات (echo) حتى لا تقوم بالأمر يدويا. تستطيع استخدامها عندما لا تريد أن تغير أيّ شيء بالمعلومات التي تريد طباعتها. لكنها تبدو لي غبر مفيدة لأنها لا تتيح لك أيّ تحكم بهيكلة المعلومات التي تحصل عليها، كما أنها تقوم بطبع كل المعلومات للصفحة.()get_post_meta: هي الدالة التي أستخدمها أنا طوال الوقت، المتغير الأول (parameter) الذي تحتاجه هو معرف (ID) المنشور، المتغير الثاني هو اسم الحقل الذي تريد جلبه، والثالث هو Boolean في حال كنت تريد القيمة على شكل string أو array مصفوفة (true من أجل string وfalse ل array).()get_post_custom: عمل بشكل شبيه جدا لـ ()get_post_meta لكنها تختلف في التسمية، الفرق أنك تقوم بتمرير ID المنشور له فحسب (بشكل اختياري أيضا) وسيقوم بإرجال كل القيم المخصصة للمنشور على شكل array.ما بعد الأساسيات: كيفية تحسين واجهة الحقول المخصصةأحد نقاط ضعف ووردبريس من ناحية الحقول المخصصة هو الصندوق الذي تستخدمه للتعديل عليها، فكما أسلفنا الذكر، الصندوق ليس مفيدا لتلك الدرجة، لذا أنت تملك الفرصة لتحسين التجربة لمستخدميك وزبائنك. الدوال التي تحتاجها للتعامل مع الحقول الخاصةحتى الآن، فقد تعلمنا كيف نسترجع الحقول الخاصة فحسب، مهمة أخرى ستقوم بها عند التطوير هي تعديل أو حذف المعلومات. من أجل هذه المهمة يقدم ووردبريس 3 دوال بسيطة للقيام بالأمر وهي: ()add_post_meta : هي الطريقة التي تستخدمها لإنشاء الحقل لأول مرة، تقوم بتمرير ID المنشور لها واسم الحقل المخصص (meta_key) والقيمة التي تريدها، وبشكل اختياري تستطيع تحديد أن يجعل ووردبريس تلك القيمة فريدة من نوعها. addpostmeta($postid, $metakey, $meta_value, $unique = false) ()update_post_meta : يمكن أيضا استخدام هذه الدالة لإنشاء حقل مخصص جديد، لذا هي تملك القدرة لتحل مكان ()add_post_meta في حال لم تكن واثقا أن الحقل جديد أو لا فتستطيع استعمالها، أول ثلاث خيارات هم نفس خيارات ()add_post_meta والخيار الأخير هو القيمة السابقة، وهو أمر لم استخدمه من قبل حقا ولكن قد يكون مفيدا في حال كنت تملك الكثير من القيم لاسم واحد (key). updatepostmeta($postid, $metakey, $metavalue, $prevvalue='') ()delete_post_meta : هي كما تتوقع تماما، وخياراتها مثل البقية تماما، عدى أن الخيار الأخير (قيمة الحقل) هي قيمة اختيارية تستطيع أن لا تحددها. deletepostmeta( $postid, $metakey, $meta_value = '' ) شرح كيفية استخدام هذه الدوال داخل لوحة التحكم هو خارج نطاق المقال، لكنك تستطيع استعمالها عبر إنشاء صندوق جديد، واستخدام الدوال اللازمة وحفظ المعلومات أثناء حفظ المنشور. استخدام إضافات مصممة لتحسين تجربة الحقول الخاصةهناك العديد من الإضافات الرائعة التي تقوم بتحسين واجهة الحقول الخاصة، أشهرها في نظري هي Pods و Advanced Custom Fields. تقوم هذه الإضافات باستخدام custom post type لإنشاء حقول جديد تعمل بمثابة حقل مخصص. أداة أبسط وأقوىالطريقة التي استخدمها عادة والتي تختلف عن البقية هي إضافة CMB2 فهي تتيح لك تحكم عبر الشفرة البرمجية (عكس الإضافات الأخرى التي تتطلب منك إنشاء الحقول عبر واجهة). استخدام هذه الطريقة للبناء بدل الطريقة التقليدية الذي يوفرها ووردبريس هو أمر مختلف تماما وتجربة رائعة. لن تحتاج لكتابة دوال كبيرة لبناء صناديق لحقول مخصصة ثم محاولة حفظها فهي تقوم بكل شيء بشكل أوتوماتيكي. كل ما عليك القيام به هو وضع الملفات في قالبك أو إضافتك أو تنصيب الإضافة والعمل مع دوالها من قالبك، لشرح أكبر لها اقرأ التوثيق المرفق لها. يجدر الذكر أنّ الإضافة مترجمة للعربية بنسبة 93% (بتاريخ هذا اليوم) ويعتبر هذا دعما ممتازا للعربية لذا الشكر لكل من ساهم في ترجمتها (تستطيع الانضمام لهم عبر موقع Transifex). قوة الحقول المخصصة في ووردبريسكما أسلفنا الذكر، الحقول المخصصة تعتبر جزءا مهما في تطوير استخدامك لووردبريس. استخدام الأمور المبنية في ووردبريس لنشر المحتوى أمر جيد، ولكن الحقول المخصصة هي ما تسمح لإضافات مثل WooCommerce و Easy Digital Downloads بإضافات مميزات قوية لووردبريس. ترجمة -وبتصرف- للمقال: Everything You Should Know about WordPress Custom Fields لصاحبه: DAVID HAYES.
  6. في هذا المقال القصير سوف نصنع تنبيها مؤقتا بسيطا عبر CSS animations. ما سنفعله بالتحديد هو إظهار تنبيه بسيط أو عبارة ما أسفل الشاشة لمدة معينة، ثم إخفائها. وسوف سنعمل شريط تقدم (progress bar) لنعرف كم تبقى من الوقت ليختفي التنبيه. ستكون تنبيهات هذا الدرس من الشكل التالي: بالنسبة للهيكلة فسوف نستخدم div يحتوي على الرسالة وبداخله div آخر من أجل شريط التقدم: <div class="tn-box tn-box-color-1"> <p>Your settings have been saved successfully!</p> <div class="tn-progress"></div> </div>سيملك التنبيه tn-box. و tn-box-color-1. من أجل تحديد اللون، سوف نثبت الصندوق أسفل النافذة حتى يرتفع عندما يظهر: .tn-box { width: 360px; position: fixed; bottom: 20px; left: 20px; padding: 25px 15px; text-align: right; border-radius: 5px; box-shadow: 0 1px 1px rgba(0,0,0,0.1), inset 0 1px 0 rgba(255,255,255,0.6); opacity: 0; cursor: default; display: none; transform: translateY(30px) } .tn-box-color-1{ background: #ffe691; border: 1px solid #f6db7b; }أما بالنسبة لشريط التقدم فسنعطيه التالي: .tn-progress { width: 0; height: 4px; background: rgba(255,255,255,0.3); position: absolute; bottom: 5px; right: 2%; border-radius: 3px; box-shadow: inset 0 1px 1px rgba(0,0,0,0.05), 0 -1px 0 rgba(255,255,255,0.6); }في البداية، سيكون عرض شريط التقدم 0. في هذا المثال، أنا أستخدم checkbox من أجل إطلاق animation عندما يتم الضغط عليه: <input type="checkbox" class="fire-check"> <section> <div class="tn-box tn-box-color-1"> <p>شريط التقدم الجميل!</p> <div class="tn-progress"></div> </div> </section>الزر يسبق صندوق التنبيهات لذا نستطيع استخدام محدد ~ من أجل تحديد العنصر الذي يأتي بعده. وإذا أردت أن تتحكم بالأمر عبر جافاسكربت (عبر إضافة tn-box-active. )، فاستخدم التالي: .tn-box.tn-box-active { display: block; animation: fadeOut 5s cubic-bezier(0.4, 0, 0.2, 1) forwards; } .tn-box.tn-box-active .tn-progress { animation: runProgress 4s linear forwards 0.5s; }أما بالنسبة للحركية (animation) فهي كالتالي: @keyframes fadeOut { 0% { opacity: 0; } 10% { opacity: 1; transform: translateY(0px);} 90% { opacity: 1; transform: translateY(0px);} 99% { opacity: 0; transform: translateY(30px);} 100% { opacity: 0; } } @keyframes runProgress { 0% { width: 0%; background: rgba(255,255,255,0.3); } 100% { width: 96%; background: rgba(255,255,255,1); } }ما ستقوم به الـحركية (animation) هو إظهار الصندوق (عبر رفعه ورفع درجة الشفافية) ثم تكبير عرض شريط التقدم. حددنا عرض شريط التقدم إلى 96% (لأنه يبعد عن يمين الصندوق بـ 2% لذا نريده أن يتوقف قبل 2% من اليسار أيضا). مثال حيSee the Pen ZbzMWQ by Hsoub Academy (@HsoubAcademy) on CodePen. ملاحظة: شيء إضافي وجدت أنه من الجميل إضافته هو إيقاف animation عند تمرير المؤشر على الصندوق. ولكن للأسف، الأمر لم ينجح في chrome بينما نجح في فيرفكس. .tn-box:hover, .tn-box:hover .tn-progress{ animation-play-state: paused; }ترجمة -وبتصرف- للمقال: Timed Notifications with CSS Animations لصاحبه Mary Lou. حقوق الصورة البارزة: Designed by Freepik.
  7. رؤوس الجداول الثابتة ليست بالأمر الجديد في مواقع الويب. على عكس الورق، حيث يستطيع القارئ نقل نظره بسرعة إلى أعلى الشاشة ليعرف في أي عمود هو، لكن أبعاد الشاشة تجعل من قراءة الجداول الطويلة أمر صعبا. رؤوس الجداول الثابتة، كما يشير اسمها، تبقى ثابتة في أعلى الجدول حتى وإن نزلنا أكثر في الجدول. يساعد الأمر في إبقاء أسماء الأعمدة دوما في متناول اليد، حتى لا يجبر المستخدم على الرجوع إلى أعلى الجدول كل مرة من أجل النظرة ثم الرجوع مجددا. يوجد العديد من سكربتات وإضافات jQuery التي تعمل بطريقة فعالة وخالية من الأخطاء، فهم ليسوا الحل المثالي لجميع المشاكل الممكنة، ففي بعض الحالات، على الجداول أن تتبع قواعد هيكلة لم تحسب لها الإضافات حساب، كالجداول التي تسمح بإظهار مؤشر التحرك (scroll bar) عندما لا تكفي المساحة لإظاهر الجدول. هذا المقال لن يكون الحل المثالي لجميع المواقف، ولكنه سيكون حلا لأغلب المشاكل الشائعة. حل باستخدام CSS فحسب عبر position: sticky؟تملك CSS حلا مناسبا لهذه المشكلة وهو عبر استخدام postion: sticky. لكن للأسف، الحل غير مدعوم في chrome رغم أنه كان مدعوما سابقا، إلا أنّ فريق التطوير قام بإلغاء الخاصية تماما منه إلى أجل غير معلوم. ولأننا لا نستطيع التضحية بكل مستخدمي متصفح chrome فعلينا إيجاد حل بديل للمشكلة. حل عبر استخدام jQueryحل jQuery هو بسيط جدا، لكن قبل أن نبدأ باستخدام، علينا أن نلقي نظرة على كيف يكون جدول ما صحيحا من حيث الهيكلة: <table> <thead> <tr> <th></th> <!-- more columns are possible --> </tr> </thead> <tbody> <tr> <td></td> <!-- more columns are possible --> </tr> <!-- more rows are possible --> </tbody> <tfoot><!-- هذا الجزء اختياري --> <tr> <td></td> </tr> </tfoot> </table>ما الذي نحاول تحقيقه؟سنحاول جعل السكربت يدعم أغلب المشاكل الشائعة والتي هي: الاستخدام الأساسي: رأس الجدول يكون ثابتا.رؤوس الجداول الأفقية والعمودية.الجداول العريضة:العمود الأفقي: إذا كان هنالك العديد من الأعمدة التي لا يمكن إظهارها في عرض الصفحة، فسنستخدم عمودا جانبيا ثابتا.الصف العمودي: وهو الاستخدام الأساسي، أن يكون الرأس العلوي ثابتا عند النزول بالجدول.كلا العمودين: حيث نثبت كل من العمود والصف.CSS من أجل البدءرغم أننا سنستخدم حلاّ عبر جافاسكربت، فإن CSS ضرورية من أجل تنفيذ الأمر: .sticky-wrap { overflow-x: auto; position: relative; margin-bottom: 1.5em; width: 100%; } .sticky-wrap .sticky-thead, .sticky-wrap .sticky-col, .sticky-wrap .sticky-intersect { opacity: 0; position: absolute; top: 0; left: 0; transition: all .125s ease-in-out; z-index: 50; width: auto; /* Prevent table from stretching to full size */ } .sticky-wrap .sticky-thead { box-shadow: 0 0.25em 0.1em -0.1em rgba(0,0,0,.125); z-index: 100; width: 100%; /* Force stretch */ } .sticky-wrap .sticky-intersect { opacity: 1; z-index: 150; } .sticky-wrap .sticky-intersect th { background-color: #666; color: #eee; } .sticky-wrap td, .sticky-wrap th { box-sizing: border-box; }ملاحظة: من المهم جدا نقل كل CSS الخاصة بوسم <table> إلى sticky-wrap. هذا حتى يتاح لنا التحكم بها مباشرة عبر jQuery. لنقل أنك تملك CSS التالي: table { margin: 0 auto 1.5em; width: 75%; }كل ما عليك فعله ببساطة هو نقلها إلى sticky-wrap. : .sticky-wrap { overflow-x: auto; /* Allows wide tables to overflow its containing parent */ position: relative; margin: 0 auto 1.5em; width: 75%; }استخدام جافاسكربتسوف نقوم بتنفيذ دالتنا على كل جدول موجود في الصفحة، الأهم من هذا سنتفقد إن كان الجدول يملك <thead> وإن كان هذا الأخير يحتوي على الأقل على <th> واحد. إن لم تتحق الشروط، فستتجاهل دالتنا هذا الجدول. $(function () { // هنا نقوم باختيار جميع الجداول في الصفحة // لكنك حر بتحديد الجداول التي تريدها $('table').each(function () { if($(this).find('thead').length > 0 && $(this).find('th').length > 0) { // بقية السكربت تكون هنا } }); });الخطوة 1: نسخ عنصر <thead>// تحديد المتغيرات وبعض الاختصارات var $t = $(this), $w = $(window), $thead = $(this).find('thead').clone(), $col = $(this).find('thead, tbody').clone();الخطوة 2: تغليف الجدول ونسخهمن أجل دعم الحالات التي يكون فيها الجدول أعرض من ماهو مسموح (أي عندما يكون عندما عدد كبير من الأعمدة، أو أعمدة طويلة، فنحوي الجدول في <div> حتى نسمح لك بأن يكون scrollable على المحور الأفقي: // احتواء الجدول $t .addClass('sticky-enabled') .css({ margin: 0, width: '100%'; }) .wrap('<div class="sticky-wrap" />'); // تفقد إن كنا قد حددنا بأن يكون الجدول قابلا للتمرير (scroll) على المحور الأفقي if($t.hasClass('overflow-y')) $t.removeClass('overflow-y').parent().addClass('overflow-y'); // صنع رأس جدول جديد بصنف .stiky-head $t.after('<table class="sticky-head" />') // إذا كان <tbody> يحتوي على <th> فنقوم بصنع عمود جديدة ليكون الخانة أعلى الجدول if($t.find('tbody th').length > 0) { $t.after('<table class="sticky-col" /><table class="sticky-intersect" />'); } // اختصارات var $stickyHead = $(this).siblings('.sticky-thead'), $stickyCol = $(this).siblings('.sticky-col'), $stickyInsct = $(this).siblings('.sticky-intersect'), $stickyWrap = $(this).parent('.sticky-wrap');الخطوة 3: وضع محتوى الجداول المنسوخةما سنقوم به الآن هو أخذ المحتوى المنسوخ من الجدول الأصلي ووضعه في الجداول الجديدة التي ستكون ملتصقة: رأس الجدول الجديد سيستلم كامل المحتوى من عنصر <thead> المنسوخ.الأعمدة الملتصقة ستستلم المحتوى من أول عنصر <th> من <thead> وكل عناصر <th> المتبقية من <tbody>.اندماج العمود مع الصف (أيّ الخانة المشتركة بين العمود والصف) ستأخذ محتوى من خلال أعلى خانة على يمين الجدول (بافتراض أننا نتعامل مع الصفحة على أساس RTL).// StickyHead يحصل على المحتوى من <thead> $stickyHead.append($thead); $stickyCol .append($col) .find('thead th:gt(0)').remove() .end() .find('tbody td').remove(); // StickyIntersect يحصل على المحتوى من <th> في <thead> $stickyInsct.html('<thead><tr><th>'+$t.find('thead th:first-child').html()+'</th></tr></thead>');الخطوة 4: الدوالهنا يأتي أهم جزء من السكربت الخاص بنا، سنحدد أيّ دوال يجب أن تنفذ من أجل أن يعمل السكربت بشكل صحيح: دالة من أجل تحديد عرض عناصر <th> في رأس الجدول المنسوخ، بما أننا نسخنا عنصر <thead> فحسب، فعرض رأس الصفحة المنسوخ الكلي لن يكون عرض رأس الصفحة الفعلي، لأن عرض <tbody> لم يتم إضافته حيث لا نعلم هل سيؤثر على رأس الصفحة أو لا.دالة من أجل تحديد مكان رأس الصفحة الثابت حتى نقوم بتحديث بُعد رأس الصفحة المنسوخ الأفقي، الذي قمنا بتحديد position: absolute عندما نبدأ بتمرير شريط التقدم داخل الجدول.دالة من أجل تحديد مكان العمود الجانبي الثابت ولها نفس حالة تثبيت رأس الصفحة.دالة من أجل حساب المساحة المتبقية وسنقوم بشرح هذه الدالة لاحقا بشكل أعمق. // Function 1: setWidths() // Purpose: To set width of individually cloned element var setWidths = function () { $t .find('thead th').each(function (i) { $stickyHead.find('th').eq(i).width($(this).width()); }) .end() .find('tr').each(function (i) { $stickyCol.find('tr').eq(i).height($(this).height()); }); // Set width of sticky table head $stickyHead.width($t.width()); // Set width of sticky table col $stickyCol.find('th').add($stickyInsct.find('th')).width($t.find('thead th').width()) }, // Function 2: repositionStickyHead() // Purpose: To position the cloned sticky header (always present) appropriately repositionStickyHead = function () { // Return value of calculated allowance var allowance = calcAllowance(); // Check if wrapper parent is overflowing along the y-axis if($t.height() > $stickyWrap.height()) { // If it is overflowing // Position sticky header based on wrapper's scrollTop() if($stickyWrap.scrollTop() > 0) { // When top of wrapping parent is out of view $stickyHead.add($stickyInsct).css({ opacity: 1, top: $stickyWrap.scrollTop() }); } else { // When top of wrapping parent is in view $stickyHead.add($stickyInsct).css({ opacity: 0, top: 0 }); } } else { // If it is not overflowing (basic layout) // Position sticky header based on viewport scrollTop() if($w.scrollTop() > $t.offset().top && $w.scrollTop() < $t.offset().top + $t.outerHeight() - allowance) { // When top of viewport is within the table, and we set an allowance later // Action: Show sticky header and intersect, and set top to the right value $stickyHead.add($sticktInsct).css({ opacity: 1, top: $w.scrollTop() - $t.offset().top }); } else { // When top of viewport is above or below table // Action: Hide sticky header and intersect $sticky.add($stickInsct).css({ opacity: 0, top: 0 }); } } }, // Function 3: repositionStickyCol() // Purpose: To position the cloned sticky column (if present) appropriately repositionStickyCol = function () { if($stickyWrap.scrollLeft() > 0) { // When left of wrapping parent is out of view // Show sticky column and intersect $stickyCol.add($stickyInsct).css({ opacity: 1, left: $stickyWrap.scrollLeft() }); } else { // When left of wrapping parent is in view // Hide sticky column but not the intersect // Reset left position $stickyCol .css({ opacity: 0 }) .add($stickyInsct).css({ left: 0 }); } }, // Function 4: calcAllowance() // Purpose: Return value of calculated allowance calcAllowance = function () { var a = 0; // Get sum of height of last three rows $t.find('tbody tr:lt(3)').each(function () { a += $(this).height(); }); // Set fail safe limit (last three row might be too tall) // Set arbitrary limit at 0.25 of viewport height, or you can use an arbitrary pixel value if(a > $w.height()*0.25) { a = $w.height()*0.25; } // Add height of sticky header itself a += $sticky.height(); return a; }; }والآن سنقوم بشرح ما قمنا به في الدالة الرابعة، نحن لا نريد من رأس الجدول أن يلحقنا إلى أسفل الجدول، فالأمر غير ضروري وقد يغطي لنا آخر سطر من الجدول، لذا من الضروري إبقاء مساحة فارغة في الأسفل. حسب ما جربت، فقد اكتشفت أننا لا نحتاج لرأس الجدول عندما نصل لأخر 3 سطور من الجدول لأن تركيزنا انتقل على المحتوى الآن. $t.find('tbody tr:lt(4)').each(function () { allowance += $(this).height(); });الخطوة 5: ربط كل شيءوالآن قد انتهينا من تعريف كل الدوال اللازمة، كل ما تبقى هو ربط المتفقدات أو (Event handlers) مع عنصر(window)$. عندما يجهز الـDOM نقوم بالحسابات الأولية للعرض.عندما تحمل كامل المعلومات نقوم بحساب الأبعاد مرة أخرى، هذه الخطوة مهمة لأن جدولك قد يحتوي على أشياء تحمل بعد الـ DOM مثل الصور وخطوط الويب.عندما يتم التمرير في الحاوي الرئيسي ولكن هذا سيحدث في حالة كان المحتوى أكبر من عرض الحاوي، حينها نريد إعادة تغيير مكان العمود الرئيسي.عندما يتم تصغير نافذة المتصفح نريد إعادة حساب العرض.عندم يتم النزول في المتصفح نريد أن نغير مكان رأس الجدول.يمكن تلخيص ما قلناه للتو في الكود التالي. يجدر الذكر أن أحداث التصغير والتمرير يتم التحكم بهما باستخدام إضافة throttle+debounce. // #1: DOMعندما يجهز الـ setWidths(); // #2: نراقب الحاوي في حال حدوث تمرير فيه $t.parent('.sticky-wrap').scroll($.throttle(250, function() { repositionStickyHead(); repositionStickyCol(); })); // الآن نربط ما قمنا بعنصر $(window) $w // #3: عندما يتم تحميل كامل المحتويات .load(setWidths) // #4: عندما يتم تصغير النافذة // قمنا باستخدام throttle هنا حتى لا يتم إطلاق الحدث أكثر من مرة (في الوضع الافتراضي يتم إطلاق الحدث من أجل كل جزء يتم تصغيره، هنا ننتظر حتى ينتهي التصغير كاملا ثم نطلق) .resize($.throttle(250, function () { setWidths(); repositionStickyHead(); repositionStickyCol(); }) // #5: عندما يتم النزول في النافذة // استخدمنا throttle حتى لا يتم إطلاق الدالة كثيرا .scroll($.throttle(250, repositionStickyHead);وانتيهنا، كان هذا كل شيء! النقاشنحن نعرف أن لاشيء كامل، لذا سنناقش الطرق الأخرى التي تملك محاسن على هذه الطريقة ومساوئها ولم استخدمنا هذه الطريقة. استخدام position: fixedاستخدام هذه الطريقة قد يبدو مغريا لسبيين: لا يوجد حاجة لحسابات من أجل رأس الجدول، لأن العنصر المثبت (fixed) يقع خارج الصفحة الفعلية وسيبقى ثابتا في مكانه.نتجنب البطء في الحسابات هذا لأن العناصر الثابتة تلاحق الجدول ولا تثبت معه، لأننا نقوم بالحساب في فترات ثابتة (عبر throttle) وبالتالي سيظهر أن العنصر الثابت غير متجاوب وبالتالي غير طبيعي.لكن المشكلة في هذه الطريقة هي أننا نزيل العنصر من رونق الصفحة، ففي حالة تجاوز عرض الجدول العرض المسموح وأصبح من الضروري إضافة scroll فإن رأس لن يلحق المحتوى على المحور الأفقي لأنه ثابت في الصفحة. وهذا سبب كبير لا يسمح لنا باستخدام أغلب إضافات jQuery التي تقدم هذه الخواص. وكتبت هذه الدورة من أجل إصلاح هذا الأمر بالتحديد. استخدام position: stickyالخاصية الجديدة مناسبة للأمر، في الواقع لقد بنيت من أجل هذا الأمر في الحسبان، المشكلة فيها أنها غير مدعومة من متصفح chrome (سبق وكانت مدعومة ولكن أزيل الدعم كليا) وبذلك تفقد كل الزوار من هذا المتصفح. مثال حي:See the Pen avovoo by Hsoub Academy (@HsoubAcademy) on CodePen. ترجمة -وبتصرف- للمقال: Sticky Table Headers & Columns لصاحبه Terry Mun.
  8. عند كتابة نص أو مقال ما، فأنت في الأغلب ستضيف له بعض الصور، أو الفيديو أو رسومات لتوضح المحتوى بشكل أكبر. والأغلب أنك ستضيف لكل منه نصا تقوم فيه بشرح مفهوم الصورة، وقد ترغب بترقيم الصور حتى لا يضيع القارئ، وهذا ما سنقوم به عبر استخدام عنصر <figure> مع المُرقمات (counters). عنصر figure إن عنصر <figure> صُمم ليستخدم جنبا إلى جنب مع <figcaption> لاحتواء الصور وما شابه. هذا هو شرح <figure> في وصف لغة HTML الرسمي: هكذا نقوم بإضافة figure : <figure> <img src="path/to/your/image.jpg" alt="" /> <figcaption>Here is the legend for your image<figcaption> </figure> هناك بعض الملاحظات بشأن العنصر: عنصر <figcaption> اختياري. تستطيع استخدام عنصر <figcaption> واحد فقط داخل عنصر <figure>. تستطيع إدراج أيّ عدد تشاء من العناصر داخل <figure>. إذا كنت ستدرج صورة فتستطيع ترك alt فارغة إذا كنت ستدرج <figcaption> حتى لا تقوم برامج قراءة الشاشة بقراءة نفس المحتوى مرّتين. للمزيد من المعلومات حول <figure> ألق نظرة على هذه المصادر: HTML5Doctor Mozilla Developer Network W3C Specification أمثلة: إذا أردت أن تظهر شيفرة برمجية ما، فتستطيع استخدامه بهذه الطريقة: <figure> <code>body { background: white; }</code> <figcaption>Some illustrated code with figure<figcaption> </figure> بدل إدراج صورك بهذه الطريقة: <img src="cute-kitty.jpg" alt="This is a cute kitty!" /> تستطيع إدراجها بهذه الطريقة: <figure> <img src="cute-kitty.jpg" alt="" /> <figcaption>This is a cute kitty!<figcaption> <figure> دعم المتصفحات عنصر <figure> يعتبر من أحد عناصر HTML5 الجديدة، ولذا فهو ليس مدعوما من قبل المتصفحات القديمة (IE 8) ولكن لا أحد يهتم صراحة. ولكن إن كنت مُهتمًا بدعم المُتصفّحات القديمة فتستطيع استخدام html5shiv ليظهر الوسم بشكل عادي. المُرقّمات في CSS أحد أكثر خصائص CSS ديناميكة وأقلها شهرة هي CSS Counter فهي تسمح لك بترقيم العناصر ديناميكيا عبر CSS فحسب، بدون الاستعانة بأيّ شيء آخر. استخدام المرقمات يكون عبر خاصيتين وقيمة وهما: counter-reset والتي تستخدم لتهيئة أو إعادة تهيئة مرقم أو أكثر. counter-increment والتي تستخدم لزيادة قيمة مرقم أو أكثر. ()counter وهي قيمة تستخدمها مع before:: أو after:: والتي تقبل اسم المرقم كقيمة من أجل أن تظهر القيمة. الأمر بسيط. كل ما تقوم به هو تهيئة عدّاد ما بالاسم الذي تريده، ثم تحدد لمجموعة عناصر ما أن تقوم بزيادة تلك القيمة كلنا ظهر أحدها. ويمكن إظهار هذه القيمة عبر CSS باستخدام before:: و after::. مثال بسيط للعداد: /* 1. نقوم بتهيئة المرقم (أو العداد) */ body { counter-reset: thisSuperCoolCounter; } /* 2. نحدد أنه في كل مرة يظهر فيها هذا العنصر نرفع قيمة المرقم */ .myAwesomeElement { counter-increment: thisSuperCoolCounter; } /* 3. نقوم بإظهار قيمة العداد قبل العنصر */ .myAwesomeElement:before { content: counter(thisSuperCoolCounter); } مثال بسيط حسنا نعود للموضوع الأساسي الذي يدور حوله الدرس، نريد ترقيم صورنا حتى تظهر قبلها Fig. 2 – … Fig. 1 – … وهكذا. .article { counter-reset: figures; } .figure { counter-increment: figures; } .figure figcaption:before { content: 'Fig. ' counter(figures) ' - '; } إعداد كل شيء الأساسيات بعد أن فهمنا كيف نستخدم عنصر <figure> وكيف تعمل المرقمات في CSS حان الوقت لاستخدامها في ترقيم الصور. نقوم بإعداد وسم <figure> ببعض الأمور البسيطة: .figure { padding: 0.9em; border: 3px solid #f5bca8; background: #fff; margin: 0 auto 1em; } ثم نريد أن نحاذي الصور في وسط عنصر <figure> ونمنعهم من الخروج عن حجم الحاوي لذا نضيف التالي: .figure img { margin: 0 auto; display: block; max-width: 100%; } الآن بالنسبة لوصف الصّورة (caption) وسنجعلها تبرز أكثر بتوسيطها وجعل الخط بارزًا. فقط تذكر أنّ الهدف من الوصف أن يضيف شرحًا بسيطا، وأن إزالته لن تشكل مشكلة في الفهم فلا داعي لأن تضيف فقرة هناك. .figure figcaption { font-weight: 700; font-size: 0.8em; padding: .5em; text-align: center; color: #fff; background: #f5bca8; } الترقيم حان الوقت لإضافة الترقيم للصور، وإضافته سهلة كما رأينا سابقا. .article { counter-reset: figures; } .figure figcaption { counter-increment: figures; } .figure figcaption:before { content: 'Fig. ' counter(figures) ' - '; } الإضافات البسيطة نريد أن نضيف طريقة سهل لجعل الصور تتمركز على يمين المحتوى أو على يساره، وسنقوم بذلك عبر إضافة التالي: .figure-left { float: left; margin: 0 1em .5em 0; width: -webkit-min-content; width: -moz-min-content; width: min-content; } .figure-right { float: right; margin: 0 0 .5em 1em; width: -webkit-min-content; width: -moz-min-content; width: min-content; } إنّ min-content هي قيمة صحيحة لكل من الخواص التالية min-height min-width max-height max-widthheight width. في حالتنا، نريد من figure أن يكون بأصغر قدر ممكن، أو بالأحرى نريد من عرضه أن يكون هو نفس عرض الصورة التي هي بداخله. لأن figure هو عنصر بحجم كامل (block) فسوف يتمد عرضه إلى كامل الحاوي (100%). نستطيع استخدام float: left أو display: inline-block لجعل عرضه يقل إلى أكبر عنصر داخله، ولكن ماذا سيحدث لو كان الوصف أكبر من حجم الصورة، فستحدث مشكلة. نستطيع أن نحدد عرض العنصر يدويًّا، ولكن الأمر غير منطقي وغير ديناميكي، لهذا استخدمنا قيمة min-content، فهي بكل بساطة تخبر عنصر figure أن يقلل من حجمه إلى حجم الصورة مثال: See the Pen pJLXde by Hsoub Academy (@HsoubAcademy) on CodePen. الخاصية مدعومة من قبل فيرفكس باستخدام -moz- و chrome باستخدام -webkit-. المتصفحات التي لا تدعم الخاصية ستتصرف كما هو متوقع منها، لن يتم تعيين أيّ عرض وسيكون عرضه هو عرض أكبر عنصر داخله. ملاحظة: يوجد قيم أخرى وهي max-content و fit-content و available. اطلع على التوثيق للمزيد من المعلومات. وأخيرًا وليس آخرا، نريد أن نغير أو نحذف العرض الأقصى الذي حددناه للصور التي ستميل لليمين أو لليسار، فإذا أردت أن تأخذ الصور حجمها الطبيعي فاستخدم max-width: none وإذا أردت عرضا أقصى فاستخدم التالي: .figure-right img, .figure-left img { max-width: 300px; /* عدل على حسب حاجتك */ } توافق الشاشات الصغيرة لنتأكد من العناصر التي نحاذيها لا تتصرف بغرابة في شاشات الهواتف الصغيرة سنقوم ببعض التعديلات حتى تأخذ العناصر كامل العرض وتتوسط الصفحة أفقيا: @media (max-width: 767px) { .figure-left, .figure-right { float: none; margin: 0 0 1em 0; width: 100%; } .figure img { max-width: 100%; } } الاستخدام استخدام ما قدمناه شيء بسيط، إما أن تستخدم صورا تستغل كامل المساحة عبر استخدام figure. أو تريد أن تحاذي الصور لليمين أو لليسار فتستخدم كل من figure. وfigure-left. أو figure-right. <figure class='figure'> <img src="path/to/your/image.jpg" alt="" /> <figcaption>Here is the legend for your image<figcaption> </figure> <figure class='figure figure-left'> <img src="path/to/your/image.jpg" alt="" /> <figcaption>Here is the legend for your image<figcaption> </figure> <figure class='figure figure-right'> <img src="path/to/your/image.jpg" alt="" /> <figcaption>Here is the legend for your image<figcaption> </figure> خاتمة هذا كان كل شيء، كل ما تبقى هو أن تطبقها في موقعك، جرب إلقاء نظرة على المثال لترى مثالا عمليا. ترجمة وبتصرّف للمقال: Automatic Figure Numbering with CSS Counters لصاحبه: Hugo Giraudel. جميع حقوق المقال محفوظة لموقع codrops.
  9. إنّ HTML و CSS من أفضل وأسهل الطرق لتقديم المحتوى وأكثرها مرونة. فهي سهلة التعلم وقوية. لكن شيئا واحدا تعجَز فيه هذه اللغات هو الهيكلة المعقدة.، فإذا أردت إنشاء موقع بسيط بهيكلة واضحة فالأمر سهل جدا، ولكن انتقل إلى محتوى متعدد الأعمدة مثلا وشيئا آخر تماما، فهنا تقع نقطة ضعف لغات هيكلة الويب، فيستلزم بنا استخدام طرق ملتوية لإصلاح المشاكل، ناهيك عن توافق هذه الطرق مع مختلف المتصفحات وطريقة ظهورها في كل متصفح. لمجابهة هذه المشكلة يقدم لنا الإصدار الثالث من CSS مجموعة من الحلول البسيطة والسهلة لهذه المشاكل، وهي كالتالي: Multi-column layout Module. Grid layout Module. Flexbox layout Module. وسنتكلم نحن اليوم عن Flexbox (المعروف عموما بـFlex) وهو أكثرهم شيوعا وأكثرهم دعما من قبل المتصفحات (لدى كتابة هذا المقال كل المتصفحات تدعم flex إلى جانب الإصدار العاشر من IE)، وما يقوم به Flexbox هو التحكم بهيكلة مجموعة من العناصر التي تقع تحت حاوي واحد، ويسمح لنا بـ: صف هذه العناصر في سطر واحد بدون تحديد عرض كل واحد منها (واستخدام float) كما يقوم بإضافة العناصر إلى سطر جديد إن لم تكفي المساحة. صّف هذه العناصر على شكل عمود بسهولة كبيرة. محاذات العناصر إلى اليمين أو اليسار أو الوسط (بالنسبة للحاوي). تغيير الترتيب الذّي تظهر به العناصر بدون التعديل على HTML. تحديد المساحة التي يأخذها كل عنصر بدون القلق في حال تغيير حجم الحاوي. والآن لنتفقد المزيد من المميزات. مثال بسيط للعمل به حتى نبدأ باستخدام Flexbox، علينا استخدام مثال بسيط لنشرح به، ومن أجل ذلك اخترنا العمل على هيكلة ذيل صفحة يحتوي على 3 عناصر تجدها في أيّ ذيل صفحة وسنقوم بالتجربة عليها. ما نريد إنجازه هو أن نقوم بصف العناصر الثلاثة بشكل أفقي، وأن نقوم بمحاذاتها عموديا إلى المنتصف وأن يستغل العنصر الأخير ضعف مساحة بقية العناصر، لنقوم بالأمر بالطريقة التقليدية سيتوجب علينا صف العناصر باستخدام float مع تحديد مساحة كل واحدة وحسابها بشكل دقيق حتى يكون هناك ما يكفي من مكان. هذه هي النتيجة النهائية. البدء باستخدام Flexbox الشيء الذي يجب أن نفهمه هو أن Flexbox ليس خاصية واحدة بل مجموعة من الخواص المختلفة، ونستعمل Flexbox عبر تطبيق هذه الخواص على الحاوي والبعض الآخر على العناصر التي نريد التحكم بها. ولنبدأ باستخدام Flexbox نقوم بتطبيق الخاصية التالية على الحاوي: footer { display: flex; } تستطيع أيضا استخدام خاصية flex-flow التي تسمح لك بأن تحدد هل تريد أن تصف العناصر على شكل صف أفقي (row وهي القيمة الإفتراضية )أو على شكل عمود (column) وهل تريد أن تحشر كل العناصر في سطر واحد (nowrap وهي القيمة الافتراضية) أو أن تضيف سطرا جديدا (أو عمودا جديدا) في حال نفاذ المكان (wrap). footer { display: flex; flex-flow: row wrap; } ملاحظة: flex-flow تجمع ما بين الخاصيتين flex-direction (وقيمها هي row , column row-reverse column-reverse) و flex-wrap (قيمها هي wrap no-wrap wrap-reverse). دورة تطوير واجهات المستخدم ابدأ عملك الحر بتطوير واجهات المواقع والمتاجر الإلكترونية فور انتهائك من الدورة اشترك الآن المحور الرئيسي والمحور الجانبي Flexbox تعتمد على مبدأ المحاور في العمل، فهي لا تعمل على أساس محور أفقي ومحور عمودي (حيث ستنعكس الأمور إذا صفننا العناصر عموديا عبر flex-direction : column) بل تستخدم محورا رئيسيا أو Main Axis وهو يتبع الإتجاه الذي حددناه في flex-direction بمعنى أنه من بداية الصفحة إلى نهايتها إذا حددنا flex-direction : row أو من أسفل الصفحة إلى أعلاها إذا حددنا flex-direction : column-reverse أما المحور الجانبي فهو يعامد المحور الرئيسي ويجري في نفس اتجاهه، هذه صورة توضح الأمر. محاذات العناصر يتيح لنا Flexbox محاذات العناصر بأكثر من طريقة، وعبر المحور الرئيسي والجانبي. المحاذات في المحور الجانبي للمحاذات على المحور الجانبي نستخدم خاصية align-items وقيمه هي: flex-start/baseline: تقوم بمحاذات أعلى نقطة من كل عنصر عند بداية المحور الجانبي. flex-end: تقوم بمحاذات نهاية كل عنصر عند نهاية المحور الجانبي. center: تقوم بمحاذات منتصف كل العناصر مع منتصف المحور الجانبي. stretch: تقوم بجعل العناصر تتمدد حتى تملأ مساحة كامل المحور الجانبي. كل هذه القيم واضحة، ولكن إن احتجت فهمها أكثر، جرب التعديل على المثال التالي: See the Pen jPzGPR by Hsoub Academy (@HsoubAcademy) on CodePen. خلاصة أتمنى أن تكون هذه المقالة واضحة وبسيطة لتشرح مجموعة الخواص الرائعة هذه، Flexbox تسمح لنا بالكثير من "المرونة" في التطوير وتتيح لنا أشياء لم نكن قادريين على القيام بها سابقا. ترجمة -وبتصرّف- للمقال Flexbox — Fast Track to Layout Nirvana.
  10. مواقع الويب الحديثة أصبحت أكثر ديناميكية مؤخرا، عبر استخدام Javascript لتزويد المستخدم بتحديثات مباشرة ومتحكمات أكثر سلاسة. أحد أكثر المميزات شيوعا هي إظهار وإخفاء المحتوى، سواءا كان على شكل تبويبات، مخفيا على جانب الصفحة، أو على شكل قائمة متعددة المستويات. عادة، هذه المميزات يتم تطبيقها عبر Javascript فحسب، ولكنك تستطيع القيام بنفس التأثيرات عبر CSS3 بدون اللجوء إلى Javascript. في هذه المقالة سنرى كيف يمكننا تحقيق ذلك، مع تضمين بعض الأمثلة. المحتوى مثال بسيط حل حقيقي الإخفاء والإظهار عبر CSS تحسين القائمة دعم المتصفحات مثال بسيط هذا مثال بسيط يظهر كيف يمكن إخفاء وإظهار المحتوى عبر CSS: See the Pen &amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io/assassinateur/pen/YXKgRz/' href='http://codepen.io/assassinateur/pen/YXKgRz/'&amp;amp;amp;amp;amp;amp;gt;YXKgRz&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt; by Nadir (&amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io/assassinateur' href='http://codepen.io/assassinateur'&amp;amp;amp;amp;amp;amp;gt;@assassinateur&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io' href='http://codepen.io'&amp;amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt;. عندما نضغط على زر إخفاء، سيختفي الزر إلى جانب القائمة في الأسفل، ويظهر زر "إظهار". وإذا شاهدت نسخة الطباعة من الصفحة، فستلاحظ أنّ الأزرار لن تظهر. الآن بعد مشاهدتنا للمثال، لنلقي نظرة على ما استخدمنا والتقنيات الكامنة خلف ذلك، ونبني قائمة بينما نحن نقوم بذلك. حل حقيقي نستطيع استخدام الحل الذي سنطوره في إحدى الحالات التالية: نريد أن تجعل محتوى معين يظهر ويختفي في مكان معين (مثل قوائم المحتوى في ويكيبيديا) لسبب ما، قد لا نريد استعمال جافاسكربت لنبدأ بمشاهدة حل يستخدم جافاسكربت؛ قسم المحتوى في مقالة ما في ويكيبديا See the Pen &amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io/assassinateur/pen/rVBbMR/' href='http://codepen.io/assassinateur/pen/rVBbMR/'&amp;amp;amp;amp;amp;amp;gt;rVBbMR&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt; by Nadir (&amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io/assassinateur' href='http://codepen.io/assassinateur'&amp;amp;amp;amp;amp;amp;gt;@assassinateur&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io' href='http://codepen.io'&amp;amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt;. المثال السابق مأخوذ من صفحة ويكيبيديا (هو مجرد HTML رغم هذا)، يعمل الجدول عبر إخفاء المحتوى، وتغيير الكلمة من "أخفي" إلى "أظهر" ويتم هذا عبر جافاسكربت. يتم إضافة تسجيل مراقب للزر (Event Listener)، عندما يتم الضغط على الزر، يقوم jQuery بإضافة class جديد للصندوق، يتم أيضا إَضافة واحد لحاوي الروابط، كما يتم تغيير محتوى الزر من "أخفي" إلى "أظهر". الإخفاء والإظهار عبر CSS سنحاول إعادة صنع قائمة ويكيبيديا، ولكن عبر CSS فحسب، فسنفقد بعض المميزات، ولكننا سنكسب بعض الأمور في نفس الوقت. يستطيع رابط ما أن يأخذك لأيّ جزء من الصفحة عبر تحديد ID الخاص به كمكان اتجاه للرابط. في المثال سنستخدم شيئا مشابها، ولكن ليس للتصفح، بل لإظهار وإخفاء المحتوى. نستخدم الكود في الأسفل ثم نشرحه. See the Pen &amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io/assassinateur/pen/oXvOZb/' href='http://codepen.io/assassinateur/pen/oXvOZb/'&amp;amp;amp;amp;amp;amp;gt;oXvOZb&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt; by Nadir (&amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io/assassinateur' href='http://codepen.io/assassinateur'&amp;amp;amp;amp;amp;amp;gt;@assassinateur&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io' href='http://codepen.io'&amp;amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt;. مثل قائمة ويكيبديا، نريد من قائمتنا أن تظهر مفتوحة بشكل افتراضي. نصنع class باسم .show و .hide. وبما أن القائمة ستكون مفتوحة، لا نريد من زر .show أن يظهر. .show { display: none; } والآن نريد أن نجعل زر الإظهار 'يظهر' ونخفي زر 'الإخفاء' عندما يتم الضغط عليه، يمكننا تحقيق هذا عبر شبه الصنف :focus والذي يعمل عندما يتم الضغط على الرابط بواسطة الفأرة أو التركيز عليه بواسطة لوحة المفاتيح. سنستخدم المحدد "+" والذي يعني العنصر الذي يأتي مباشرة بعد العنصر الأول. a.hide:focus + .show { display: inline; } a.hide:focus { display: none; } الآن، لنجعل الزر يعمل حقا! سوف نقوم بجعل القائمة #menu تختفي عندما يكون زر الإخفاء في حالة :focus بما أنّ القائمة لا تأتي مباشرة بعد الزر، سيكون علينا استخدام المحدد غير المباشر ~ من أجل تحديد القائمة. a.hide:focus ~ #menu { display:none; } والآن، لتعديل بسيط أخير. نريد أن نخفي أزرار الإخفاء والإظهار في حال طباعة الصفحة، أسرع طريقة للقيام بالأمر هي عبر استخدام media query والتي تتفقد هل يتم طباعة الصفحة، وإن كان كذلك تقوم بإخفاء الأزرار. @media print { .hide, .show { display: none; } } حتى الآن، ما قمنا به يعطينا التأثير المطلوب الذي رأيناه في أول المقال. القائمة التي لدينا تقوم بنفس عمل قائمة ويكيبيديا تماما، عدى بعض التأثيرات الخفيفة التي سنصل لها بعد قليل. يجب التنويه على أننا لم نستخدم جافاسكربت فحسب، بل استخدمنا مقدارا ضئيلا جدا من CSS من أجل تحقيق هذا، مقارنة ب3 دوال في جافاسكربت وحوالي 20 سطرا من الكود. تحسين القائمة الآن بعدما قمنا بصنع التأثير إخفاء المحتوى، نريد أن نضيف له بعض التأثيرات البصرية، وسنستخدم CSS أيضا. الاختفاء البطيء بدلا من الإظهار والإخفاء السريع، سيكون من اللطيف لو اختفت القائمة بشكل بطيء، وسنقوم بهذا عبر transition في CSS. سوف نحدد الوضع الافتراضي للقائمة (وهي أن تظهر بشكل كامل) ثم نخفيها ببطيء. #menu { opacity: 1; } a.hide:focus ~ #menu { opacity: 0; } بدل أن نضع التأثير خصيصا للعنصر، نستطيع إَضافته لأي عنصر عبر وضعه في class مستقل .tran1 { -o-transition: all 1s; -moz-transition: all 1s; -webkit-transition: all 1s; transition: all 1s; } الآن، تستطيع إضافة التأثير لأي عنصر تريد وذلك عبر إضافة class فحسب. النتيجة النهائية بعد إَضافة بعض التحسينات البسيطة، هذه هي النتيجة النهائية See the Pen &amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io/assassinateur/pen/pJzBWQ/' href='http://codepen.io/assassinateur/pen/pJzBWQ/'&amp;amp;amp;amp;amp;amp;gt;pJzBWQ&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt; by Nadir (&amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io/assassinateur' href='http://codepen.io/assassinateur'&amp;amp;amp;amp;amp;amp;gt;@assassinateur&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io' href='http://codepen.io'&amp;amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;amp;gt;. ملاحظة: حالما تضغط على شيء آخر، يعود كل شيء كما كان وهذا هو التصرف الطبيعي لشبه الصنف :focus ولكنه ليس الأمر الذي نريده نحن. هذه المشكلة ليست موجودة في مثال ويكيبيديا بكل تأكيد، كما أن ويكيبيديا تستخدم الـcookies لتتذكر آخر حالة للقائمة حتى بعد تحديث الصفحة، وهو شيء لا نستطيع تحقيقه للأسف. خاتمة استطعنا القيام ببعض التأثيرات البصرية باستخدام CSS لوحدها عبر تعلم كيفية إخفاء وإظهار العناصر، هناك محددات واعدة أكثر ستظهر مستقبلا، وستتيح لنا التحكم أكثر وأكثر في العناصر وتحديدها بسهولة، احدى الخدع التي يمكن استخدامها هي استخدام checkbox بدل الروابط من أجل تغيير حالة الصندوق، ولكن كان هذا ليجعل الأمر أكثر تعقيدا. حقوق الصورة البارزة محفوظة لـ Freepik
  11. في المقال الأول تكلمنا حول أساسيات صفحات الهبوط، وفي المقال الثاني صممنا صفحة هبوط في Photoshop باستخدام ما تعلمانه، الآن سنكمل ما بدأنا به ببناء صفحة الهبوط فعليا، سنمر على كل المراحل إنطلاقا من توزيع الملفات إلى صفحة جاهزة، هيا لننطلق. يمكنك تحميل الشِفرة المصدرية لهذا الدرس لمعاينة النتيجة النهائية. وهذا تذكير بواجهة الصفحة: الأساسياتفي البداية سنقوم بتوضيح ما سنقوم باستخدامه ولماذا سنستخدمه. أولا، لدينا الصور التي حصلنا عليها من ملف PSD الذي قمنا بتصميمه في درس التصميم، فلنستخدمها.لن نستخدم خط أيقونات لسبب وجيه وهو أنها ستكون مضيعة وقت وبدون فائدة فعلية فالصفحة مجرد صفحة واحدة لذا لا يوجد الكثير لنقلق بشأنه (بشأن عدد طلبات HTTP كمثال).سنستخدم هيكلة HTML5 Boilerplate وهو هيكل عمل مصغر لبناء صفحات HTML حيث يحتوي على تقسيم مجلدات ممتاز، ويوزدك ببعض الملفات المهمة مثل .htaccess و ملف index كامل يحتوي على كل شيء تحتاجه.سنستعمل بعض إضافات إطار عمل Bootstrap، وهم: Affix من أجل تثبيت قائمة التصفح عند النزول.إضافة Scrollspy من أجل تغيير لون الأيقونات كلما ممرنا على مرحلة.سنستخدم إضافة Owl carousel 2.0 من أجل جزء الشهادات، إذا كنت تملك إضافة أخرى فأنت حر باستخدامها.سنستعمل موقع TinyPNG من أجل ضغط الصور التي حصلنا عليها من ملف PSD.سنستخدم موقع Everything Font من أجل تحويل خط Cocon إلى نسخة الويب (woff) حتى نستخدمها.تقسييم الملفاتسيكون تقسيمنا للملفات على الشكل التالي: project/ ├── css/ │ ├── main.css │ ├── normalize.css │ └── owl.carousel.css ├── fonts/ │ └── CoconNextArabicLight.woff ├── js/ │ ├── main.js │ └── vendors/ │ ├── bootstrap.min.js │ ├── jquery-1.11.2.min.js │ └── owl.carousel.min.js ├── img/ ├── index.html └── favicon.icoعند تحميل إطار عمل H5BP فإنه يزودنا بالتقسييم بالتالي بشكل افتراضي، ما قمنا به نحن هو إضافة بعض الملفات في بعض الأماكن فحسب، مجلد img يحتوي على الصور التي حصلنا عليها من المرحلة السابقة عبر استخراجها من فوتوشوب، كما قمنا بإضافة bootstrap.js الذي يحتوي على كلٍ من affix وscrollspy. وقمنا بحذف بعض الملفات مثل modernizer وhtml5shiv لأننا لن ندعم المتصفحات القديمة. البدايةحسنا، نحتاج إلى أن نعد بعض الأمور قبل أن نبدأ، بعد تحميل كامل المكتبات المطلوبة نستطيع البدأ بإعداد بعض الأمور. نحن نملك خط Cocon بصيغة سطح المكتب (ttf). لا ضرر في هذه الصيغة إطلاقا، هي تعمل بشكل ممتاز في المتصفحات، ولكننا نستطيع تقليل الحجم إلى النصف عبر تحويل الخط إلى صيغة woff المخصصة للويب وذلك عبر موقع التحويل (ستجد الخط محولا في الشفرة المصدرية لهذا الدرس). نحتاج إلى ضغط الصور، هناك فائدة عظيمة نكسبها هنا، موقع TinyPNG سيقوم بتقليل حجم الصور إلى أكثر 70% مع الحفاظ على الجودة، وهذا حجم ممتاز لذلك سنقوم بذلك أيضا. الآن سنعد بعض الأمور الابتدائية في ملف CSS: @import url(owl.carousel.css); @font-face { font-family: Cocon; src: url(../fonts/CoconNextArabicLight.woff) format('woff'); } *, *:before, *:after { box-sizing: border-box; } body { font-family: cocon, sans-serif; background: #fff; position: relative; }سنقوم باستدعاء ملف owl.carousel من أجل تأثيرات الحركة في السكربت، سنقوم بإدراج خط Cocon للاستخدام، سنستعمل box-sizing من أجل احتواء العناصر بشكل أفضل. سنضيف بعض الأمور الافتراضية لوسم body. مكتبة scrollspy تحتاج إلى أن يكون وسم body بخاصية position:relative من أجل أن تعمل.هيكلة الصفحةفي سابق الأمر، كنُت قد خططت لبناء الصفحة عبر إطار عمل Bootstrap المعروف، وسبق وقلت هذا في المقال السابق، ولكني تراجعت عن الأمر لقلة الفوائد مقارنة بالسيئات، ووجدتها فرصة حسنة لاستخدام Flex module والتكلم عنه أكثر. أما بخصوص Bootstrap فلدي آرائي حوله، من بينها أنّه إطار مناسب تماما لإطلاق المشاريع بسرعة من أجل التجريب (لاحظ الاسم Bootstrap) كما أنّه إطار مناسب لبناء المشاريع الداخلية حيث لن يتم إطلاق المشروع لجمهور فعلي، إلا إذا كنت تنوي تخصيصه حتى النخاع فتغير مظهره، فذلك شأنك. الصفحة مكونة من 6 أجزاء أساسية: رأس الصفحة.روابط التصفح عبر الصفحة.مميزات التطبيق.الاقتباسات (أو الشهادات).الأرقام (أو التحليلات).التحميل والمشاركة.والهيكة الأساسية ستكون كالتالي: <header class="l-header"> <div class="l-app-preview"> </div> <div class="l-page-fold"> </div> </header><!-- .l-header --> <nav class="l-sticky-nav"> <div class="sticky-nav"> </div><!-- sticky-nav --> </nav><!-- l-sticky-nav --> <article id="features-section"> <section class="l-app-feature"> </section> </article><!-- #features-section --> <article id="testimonials-section"> </article><!-- #testimonials-section --> <article id="analysicts-section"> </article><!-- #analysicts-section --> <article id="download-section"> </article><!-- #download-section -->قمنا بتقسييم كل جزء من الصفحة إلى وسم article مستقل (ما عدى روابط التصفح ورأس الصفحة حيث يملكان وسوما افتراضية خاصة بهم من قبل). قمنا بتقسييم رأس الصفحة إلى جزئين، الأول سيحتوي بداخله صورة واجهة التطبيق، أما الثاني فسيحتوي على العنوان إلى جانب السطر الرئيسي وزر التحميل. روابط التصفح تملك جزئين، حاوي رئيسي وحاوي الروابط، وهناك سبب وجيه لهذا التكرار، بحيث عندما يتم تفعيل تثبيت الروابط على أعلى الشاشة، نرى أن يبقى هناك مكان فارغ (في المكان السابق الذي كانت الروابط موجودة فيه) حيث لا يحدث اختلال في الصفحة، الجزء المسؤول عن هذا سيكون l-sticky-nav، أيضا لاحظوا أنّ كل الروابط التي تحتوي على حرف L قبل اسمها (اختصارا لـ layout) ستكون مسؤولة عن الهيكلة بشكل خاص. رأس الصفحة<header class="l-header"> <div class="l-app-preview"> <img src="img/home-screen.png" alt=""> </div> <div class="l-page-fold"> <h1 class="display-title">اكتشف أشخاصا بنفس اهتماماتك</h1> <p class="display-content">تعرف على أشخاص يشاركونك الهوايات والاهتمامات شارك، اقرء، وتواصل مع الجميع عبر تطبيق اهتمامات</p> <a href="" class="display-badge"> <img src="img/badge.png" alt="حمل من متجر التطبيقات"> </a> </div> </header><!-- .l-header -->كان ذلك هو رأس الصفحة، بكل بساطة وكما أشدنا سابقا، الآن حان وقت إضافة بعض CSS له. .l-header { display: flex; justify-content: center; align-items: center; width: 100%; min-height: 100vh;/* used to make sure the header will cover the screen */ position: relative; padding: 48px 0; /* سيعطي هذا بعض المساحة للشاشات الصغيرة حيث المحتوى أكبر من ارتفاع الشاشة */ background: url(../img/background.png) center center no-repeat; background-attachment: fixed; background-size: cover; }الشفرة المصدرية مقسمة لثلاث أجزاء، كل جزء له مهمته المعينة. الجزء الأول مسؤول عن هيكلة رأس الصفحة، نحن نطلب منه أن يستخدم flex كنظام للهيكلة عبر display:flex وأن يقوم بوضع جميع العناصر في منتصف الصفحة أفقيا عبر justify-content:center والواقع أنها تقبل العديد من الخيارات الأخرى، منها flex-start التي تضع جميع العناصر في بداية الصفحة (اليمين في حالة العربية، أو اليسار في حالة اللاتينية، لكن الأمر لا علاقة له باتجاه الصفحة في واقع الأمر، بل باتجاه ترتيب العناصر عبر خاصية flex-direction التي تقبل 4 خيارات وهي ترتيب العناصر بشكل أفقي من بداية الصفحة لنهايتها عبر row ومن نهاية الصفحة إلى بدايتها عبر row-reverse أو من أعلى الصفحة إلى أسفلها عبر column أو العكس عبر column-reverse وسنتكلم عن هذا لاحقا) أو خيار flex-end الذي يقوم بالعكس، والخياران اللذان ستستخدمها كثيرا وهما space-around حيث يتم توزيع المساحة بين العناصر بالتساوي (وبالتالي في المنتصف ولكن مع مساحة بينهم وقبلهم وبعدهم) و space-between والتي تقوم بتوزيع المساحة بين العناصر بدون إضافة مساحة قبل العناصر وبعدهم (أيّ يتم تركيز كامل المساحة في المنتصف). الخيار الثالث يقول أننا نريد أن نضع العناصر في المنتصف عموديا وذلك عبر align-items:center والواقع أنّ الخاصية تملك أيضا خيارات كثيرة لا متسع لنا لشرحها كاملة الآن لأنها تحتاح لشرح بالصور في الغالب، ومنها flex-start التي تضع العناصر أعلى الصفحة (أو بالأحرى حسب الطريقة التي تم تحديد اتجاه المحور العمودي فيها عبر flex-direction كما بيّنا سابقا). الجزء الثاني، هو مسؤول عن جعل حجم رأس الصفحة بكامل أبعاد الشاشة، نستطيع جعله بكامل عرض الشاشة عبر width:100% أو بالمثل عبر width:100vw لا فرق بينهم لأنّ حاوي رأس الصفحة نفسه بكامل عرض الصفحة، تبقى المشكلة في الارتفاع، تحديد 100% لن ينفع وتحديد رقم معين لن ينفع إطلاقا مع كل الشاشات، الحل الوحيد هو استخدام وحدة القياس الجديدة vh والتي تقيم أبعاد الشاشة وليس العناصر، بحيث 100vh تعني كامل ارتفاع الشاشة. في الجزء الثالث سنقوم بإضافة خلفية، وضعها في المنتصف، نعطيها خاصية cover حتى تتمدد (مع المحافظة على الأبعاد ratio) على حسب الشاشة. .l-header:before { content: ""; position: absolute; top: 0; right: 0; height: 100%; width: 100%; background-color: rgba(0,0,0,0.64); }هذا الجزء مسؤول عن إضافة تأثير السواد فوق الصورة، البعض يقوم بإضافة عنصر (div) آخر داخل رأس الصفحة من أجل تحقيق هذا، ولكن هذا الحل أكثر نظافة، لاشيء فعلي لنشرحه هنا عدى أنّ عدم إدراج خاصية content (حتى ولو كانت فارغة) سيجعل الشفرة المصدرية السابقة غير فعالة، فأشباه الأصناف (pseudo-classes) لا تعمل بدونه. .l-app-preview, .l-page-fold { width: 50%; z-index: 10; position: relative; /* نحتاج إلى هذا الجزء لأن خاصية z-index لا تعمل مع static */ }هنا نقوم بإعطاء كل جزء منهم 50% من عرض الحاوي الخاص بهم، حتى يتم توزيع المحتوى بشكل عادل، خاصية z-index حتى نتأكد من أنّ المحتوى فوق تأثير السواد على الخلفية (لن يشكل هذا مشكلة في الأغلب لأننا استخدمنا شبه صنع before الذي سيضعه قبل العناصر أصلا). خاصية position:relative تم وضعها من أجل z-index لأنّه لا يعمل بدون تحديدها (في الواقع هو يعمل مع الجميع عدى static أيّ القيمة الافتراضية). مع إضافة بعض التأثيرات على العنوان، والقيام بتوسيط الصفحة، نخرج بهذه الشِفرة: .l-header { display: flex; justify-content: center; align-items: center; width: 100%; min-height: 100vh; position: relative; padding: 48px 0; background: url(../img/background.png) center center no-repeat; background-attachment: fixed; background-size: cover; } .l-header:before { content: ""; position: absolute; top: 0; right: 0; height: 100%; width: 100%; background-color: rgba(0,0,0,0.64); } .l-app-preview, .l-page-fold { width: 50%; z-index: 10; position: relative; } .l-app-preview img { display: block; margin: 0 auto; } .l-page-fold { padding-left: 24px; } .display-title { color: #fff; font-size: 55px; line-height: 1.2; margin-bottom: 36px; } .display-content { color: #fff; font-size: 28px; line-height: 1.7; margin-bottom: 128px; }تاليا سنعمل على روابط التصفح روابط التصفحالهيكلة كالتالي: <nav class="l-sticky-nav"> <div class="sticky-nav"> <div class="nav-element"> <a href="#features-section" class="nav-element--link active"> <img src="img/equalizer.png" alt="" class="nav-element--image"> </a> </div> <div class="nav-element"> <a href="#testimonials-section" class="nav-element--link"> <img src="img/id.png" alt="" class="nav-element--image"> </a> </div> <div class="nav-element"> <a href="#analysicts-section" class="nav-element--link"> <img src="img/globe.png" alt="" class="nav-element--image"> </a> </div> <div class="nav-element"> <a href="#download-section" class="nav-element--link"> <img src="img/download.png" alt="" class="nav-element--image"> </a> </div> </div><!-- sticky-nav --> </nav><!-- l-sticky-nav -->لاشيء لشرحه، هيا لنطلع على شِفرة CSS: .l-sticky-nav { margin-bottom: 128px; /* هذا الجزء منفصل عن روابط التحكم، بالأحرى عندما تلتصق الروابط في أعلى الشاشة سيبقى هذا في مكانه */ } .l-sticky-nav.fixed { padding: 50px; /* عندما يتم تثبيت التثبيت على روابط التصفح، سيبقى هذا في مكانه حتى لا تختل المساحة */ }سنعطي الحاوي الأول بعض المساحة في الأسفل، أيضا عندما يتم تثبيت الروابط سيصبح l-sticky-nav فارغا وبالتالي يكون ارتفاعه 0، مما يلغي فائدته، لذا في تلك الحالة سنجعل ارتفاعه 100px. الآن بالنسبة للحاوي الثاني: .sticky-nav { display: flex; justify-content: space-around; flex-wrap: wrap; padding: 24px; background-color: #fff; box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.1); }خاصية flex-wrap تحدد هل سيقوم الحاوي بوضع كامل العناصر في سطر واحد (عبر إعطائه no-wrap أيضا الخاصية الافتراضية) أو بوضع العناصر في سطر جديد إن لم يكن هناك متسع من المكان (عبر wrap)، عدى هذا كل شيء واضح، نقوم بتوسيط العناصر فحسب. .sticky-nav.affix { top: 0; right: 0; width: 100%; z-index: 10; position: fixed; }الآن عند تفعيل التثبيت سيتم (عبر Javascript) إضافة class إلى الحاوي الثاني، إنطلاقا منه سنقوم بتحديد ما نريده، وهو تثبيت العناصر في أعلى الشاشة، لكن في العلم أنّه عند إضافة خاصية fixed فالعنصر يخرج من نسق الصفحة، وشيء آخر وهو أنّ خاصية display:block لا تفيد بشيء حينها، لذا العنصر لن يأخذ كامل المساحة الأفقية التي يجدها (width:100%) بل يأخذ ما يحتاجه فحسب، لذا علينا تحديد الأمر بأنفسنا. .nav-element--image { filter: grayscale(100%); -webkit-filter: grayscale(100%); transition: all 200ms ease-out; } .nav-element--link.active .nav-element--image, .nav-element--link:hover .nav-element--image { filter: grayscale(0); -webkit-filter: grayscale(0); }نقوم بتحويل جميع الأيقونات إلى الرمادي عدى الأيقونات المفعلة (.active) أو التي يكون المؤشر فوقها. وهكذا نكون انتهينا من جزء آخر، الدور على جزء مميزات التطبيق. مميزات التطبيقالهيكلة كالتالي: <article id="features-section"> <section class="l-app-feature"> <div class="app-feature-preview"> <img src="img/feature-1.png" alt="" class="app-feature-image"> </div> <div class="app-feature-content"> <h2 class="app-feature-title">أضف، تابع، وتواصل مع من تشاركه الاهتمام</h2> <p class="app-feature-text">أضف إلى قائمة أصدقائك من تجدهم يشاركونك نفس الاهتمام، صنف أصدقائك على حسب اهتماماتك، وتواصل مباشرة معهم</p> </div> </section> <section class="l-app-feature"> <div class="app-feature-preview"> <img src="img/feature-2.png" alt="" class="app-feature-image"> </div> <div class="app-feature-content"> <h2 class="app-feature-title">شارك ما تجده مميزا، وعبر عن رأيك</h2> <p class="app-feature-text">أكتب المقالات لتشاركها مع دائرة أصدقائك، وأقرء مقالات الجديدة أو اكتشف اهتمامات جديدة</p> </div> </section> <section class="l-app-feature"> <div class="app-feature-preview"> <img src="img/feature-3.png" alt="" class="app-feature-image"> </div> <div class="app-feature-content"> <h2 class="app-feature-title">ابني حسابك الشخصي، وأحصل على متابعين</h2> <p class="app-feature-text">ابني حسابك الشخصي الخاص، شارك صورك وسيرتك، ودع الناس يقومون بمتابعتك</p> </div> </section> </article><!-- #features-section -->تم تقسييم كل جزء إلى section خاص به يحتوي بدوره على قسمين، واحد للصورة وواحد للعنوان والشرح، الأمر شبيه تماما برأس الصفحة، في الواقع سيعمل بنفس مفهوم رأس الصفحة. .l-app-feature { display: flex; justify-content: center; align-items: center; padding: 128px 0; } .l-app-feature:nth-child(even) { flex-direction: row-reverse; background: #13191C; } .l-app-feature:nth-child(even) .app-feature-title, .l-app-feature:nth-child(even) .app-feature-text { color: white; }الشيء الوحيد الجديد هنا هو (nth-child(even نحن هنا نقوم بتحديد كل العناصر التي تكون رتبتها رقما زوجيا (الثاني والرابع والسادس، يمكن أيضا القيام بالأمر عبر تمرير 2n+2 بدل evenمن أجل نفس النتيجة، في الواقع تستطيع تمرير أي معادلة من الشكلة an+b من أجل استهداف العناصر التي تريدها) قمنا بتمرير flex-direction:row-reverse من أجل عكس اتجاه المحور الأفقي حتى تبدأ العنصر من الاتجاه المعاكس، هذا سيجعل الصورة على اليسار والمحتوى على اليمين. وهذه كامل الشِفرة .l-app-feature { display: flex; justify-content: center; align-items: center; padding: 128px 0; } .l-app-feature:nth-child(even) { flex-direction: row-reverse; background: #13191C; } .l-app-feature:nth-child(even) .app-feature-title, .l-app-feature:nth-child(even) .app-feature-text { color: white; } .app-feature-preview, .app-feature-content { width: 50%; max-width: 600px; } .app-feature-preview img { display: block; margin: 0 auto; } .app-feature-title { font-size: 36px; color: #f85940; margin-bottom: 36px; } .app-feature-text { font-size: 28px; color: rgba(30,30,30,.9); line-height: 1.7; }جزء الشهاداتفي هذا الجزء قمنا باستخدام carousel من أجل عرض الشهادات والهيكلة كانت كالتالي: <article id="testimonials-section"> <h1 class="section-title">فلنسمع رأي البقية</h1> <section class="testimonials-carousel"> <div class="testimonial-item"> <div class="testimonial-text">أتمنى لو كان هذا التطبيق موجودا قبل سنة</div> <div class="testimonial-avatar"><img src="img/face-1-128.png" alt="" class="testimonial-image"></div> </div> </section> </article><!-- #testimonials-section -->أضفنا عنوانا، إلى جانب وضع الشهادات في حاوي خاص بهم من أجل تحديده عبر Javascript، ثم وضعنا لكل شهادة حاوي خاص بها testimonial-text يحتوي على محتوى الشهادة بالإضافة إلى صورة. .testimonial-item { display: flex; flex-direction: column; align-items: center; padding: 24px 0; margin-bottom: 48px; }هيكلة كل عنصر يتكون بسيطة، استخدما flex-direction:column لترتيب العناصر عموديا، كما استخدما align-items:center لتوسيط العناصر أفقيا (لاحظ أننا استخدمناها سابقا لتوسيط العناصر عموديا، ولكن لأن محور الترتيب اختلف الآن فهي ترتب العناصر أفقيا إلى الوسط) .testimonial-text:before, .testimonial-text:after { font-size: 48px; display: inline-block; padding: 0 16px; } .testimonial-text:before { content: "”"; } .testimonial-text:after { content: "“"; }قمنا هنا بإضافة علامتي تنصيص قبل وبعد الشهادة، قمنا بتكبير حجمهما ووضع بعض الفراغ بينهما وبين الشهادة. OwlCarousel (السكربت المستخدم من أجل عرض الشهادات) يعطينا أزرار التصفح بين الشهادات (على شكل نقاط) ولكنها بدون أيّ تأثير لذا سنقوم بذلك يدويا .owl-dots { text-align: center; } .owl-dot { height: 16px; width: 16px; border: 2px solid #E4523B; border-radius: 50%; display: inline-block; margin: 0 4px; } .owl-dot.active { background: #E4523B; }تحليلات الأرقاميحين وقت أرقام التحليلات، من أجل إطفاء التغيير وإضافة التركيز قمنا بإضافة خلفية لهم، هيكلة الجزء كانت كالتالي: <article id="analysicts-section"> <h1 class="section-title section-title__white">بعض الأرقام</h1> <div class="l-analysicts"> <div class="analysicts-item"> <div class="item-image"> <img src="img/articles.png" alt=""> </div> <h1 class="item-number">320</h1> <h2 class="item-title">مقالة نشرت</h2> </div> <div class="analysicts-item"> <div class="item-image"> <img src="img/groups.png" alt=""> </div> <h1 class="item-number">57</h1> <h2 class="item-title">مجموعة أنشئت</h2> </div> <div class="analysicts-item"> <div class="item-image"> <img src="img/users.png" alt=""> </div> <h1 class="item-number">+8000</h1> <h2 class="item-title">عضو مُسجل</h2> </div> <div class="analysicts-item"> <div class="item-image"> <img src="img/upload.png" alt=""> </div> <h1 class="item-number">450</h1> <h2 class="item-title">ملف رفع</h2> </div> </div> </article><!-- #analysicts-section -->منطق الهيكلة شبيهة بهيكلة مميزات التطبيق والشِفرة والتقسييم كانا بسيطان إلى أقصى حد: #analysicts-section { position: relative; padding: 48px 0; margin: 48px 0; background: url(../img/numbers-background.png) center center no-repeat; background-attachment: fixed; background-size: cover; } .l-analysicts { display: flex; justify-content: space-around; flex-wrap: wrap; } .analysicts-item { text-align: center; color: white; }جزء التحميل والمشاركةهذا الجزء بسيط إلى أقصى حد، عنوان بسيط مع زر للتحميل و 4 أزرار للدلالة على شبكات التطبيق الاجتماعية <article id="download-section"> <h1 class="section-title">إذا، هل قررت الانضمام؟</h1> <div class="cta-button"><img src="img/badge.png" alt=""></div> <div class="l-social-links"> <a href="" class="social-link"> <img src="img/facebook.png" alt="شارك في Facebook"> </a> <a href="" class="social-link"> <img src="img/twitter.png" alt="شارك في Twitter"> </a> <a href="" class="social-link"> <img src="img/pinterest.png" alt="شارك في Pinterest"> </a> <a href="" class="social-link"> <img src="img/google.png" alt="شارك في Google+"> </a> </div> </article> وبنفس البساطة أيضا .cta-button { margin: 36px 0; text-align: center; display: block; } .l-social-links { display: flex; justify-content: space-around; padding: 48px 0 64px; }Javascriptحان الوقت لإضافة Javascript إلى الصفحة، سنبدأ بإضافة Affix لروابط التصفح من أجل تثبيتهم. تنويه: في عالم مثالي كنا لنستخدم position:sticky لتقوم بالمهمة لنا، للأسف المتصفح الوحيد الذي يدعمها هو فيرفوكس، متصفح chrome كان يدعمها من قبل ولكنهم أزالوا الدعم في الوقت الحالي، لذا affix يعتبر أشبه بـِ polyfill. لدينا الشِفرة التالية التي سيتقوم بكل شيء لنا: $('.sticky-nav').affix({ offset: { top: $('.l-header').outerHeight() } }); $('.sticky-nav').on('affix.bs.affix', function () { $('.l-sticky-nav').addClass('fixed'); }); $('.sticky-nav').on('affixed-top.bs.affix', function () { $('.l-sticky-nav').removeClass('fixed'); });نقوم بتفعيل السكربت عبر إضافته إلى sticky-nav ثم نقوم بتحديد offset والذي يعني متى يتم تفعيل السكربت، نحن نريده أن يتفعل حالما يتم المرور عليه، نريد حساب كامل المسافة التي فوقه، وتلك المسافة ستكون حجم رأس الصفحة، لذا نضيفها عبر ()outerHeight التي تحسب الارتفاع الخارجي (من ضمنه padding). ثانيا نقوم بالاستماع إلى بعض الأحداث (events) والسكربت يوفر لنا 4 أحداث، سنستخدم اثنين فحسب، أول حدث ينطلق عندما يتم تفعيل السكربت مباشرة، وفي تلك اللحظة نضيف fixed إلى الحاوي من أجل أن يستغل المكان، تاليا نستمع للحدث الثاني والذي ينطلق حالما يتم إزالة السكربت (عند الرجوع للحالة العادية) في تلك اللحظة سنزيل fixed عن الحاوي ليعود إلى طبيعته. الآن سنتجه إلى scrollspy وهي تملك شروطا أكثر ازعاجا، مثل أنّها تعمل مع عناصر bootstrap فحسب لذا سنقوم ببعض التعديل في HTML و CSS أولا. <nav class="l-sticky-nav"> <ul class="nav sticky-nav"> <li class="nav-element"> <a href="#features-section" class="nav-element--link active"> <img src="img/equalizer.png" alt="" class="nav-element--image"> </a> </li> <li class="nav-element"> <a href="#testimonials-section" class="nav-element--link"> <img src="img/id.png" alt="" class="nav-element--image"> </a> </li> <li class="nav-element"> <a href="#analysicts-section" class="nav-element--link"> <img src="img/globe.png" alt="" class="nav-element--image"> </a> </li> <li class="nav-element"> <a href="#download-section" class="nav-element--link"> <img src="img/download.png" alt="" class="nav-element--image"> </a> </li> </ul><!-- sticky-nav --> </nav><!-- l-sticky-nav -->ما قمنا به هنا هو إضافة nav إلى الحاوي الثاني sticky-nav وقمنا بتغييره من div إلى ul ثم قمنا بتغيير العناصر nav-element من div إلى li. نقوم الآن بتعديل بعض CSS: .nav-element.active .nav-element--image, .nav-element:hover .nav-element--image { filter: grayscale(0); -webkit-filter: grayscale(0); }كل ما فعلناه هو أننا غيرنا nav-element–link إلى nav-element فحسب. الآن نستطيع استخدام الإضافة بشكل عادي تماما. $('body').scrollspy({ target: '.l-sticky-nav' });سوف نقوم بإضافتها إلى body هذا لأن عناصرنا (أقسام الصفحة) تقع مباشرة داخل وسم body وحددنا الهدف l-sticky-nav حيث يكون هو من يتم تعديل القيم فيه. تاليا سنقوم بإضافة carousel إلى الشهادات: if($('.testimonials-carousel').children().length > 1) { $('.testimonials-carousel').owlCarousel({ loop: true, nav: false, dots: true, rtl: true, items: 1 }) } ما نقوم به هو أننا نتفقد إن كان هنالك أكثر من شهادة، لأن OwlCarousel لا يعمل إذا كان هناك عنصر واحد في الصفحة (مشكلة على الأرجح سيتم إزالتها في النسخة الرسمية) بعد ذلك نقوم بتفعيله، وإعطائه بعض الخيارات، منها أننا لا نريد روابط للتقليب إلى اليمين واليسار، وأننا نريد نقاط التصفح فحسب، وأننا نريده أن يعمل من اليمين إلى اليسار (هذا السبب الوحيد الذي يدفعنا إلى استخدام النسخة 2.0 على النسخة الرسمية 1.3 وهو بسبب دعم اليمين إلى اليسار) وأننا نريد عنصرا واحدا كل مرة. هذا هو كامل شِفرة Javascript، لقد كانت بسيطة حقا: $(document).ready(function(){ $('.sticky-nav').affix({ offset: { top: $('.l-header').outerHeight() } }); $('.sticky-nav').on('affix.bs.affix', function () { $('.l-sticky-nav').addClass('fixed'); }); $('.sticky-nav').on('affixed-top.bs.affix', function () { $('.l-sticky-nav').removeClass('fixed'); }); $('body').scrollspy({ target: '.l-sticky-nav' }); if($('.testimonials-carousel').children().length > 1) { $('.testimonials-carousel').owlCarousel({ loop: true, nav: false, dots: true, rtl: true, items: 1 }) } })الخاتمةكانت هذه رحلة طويلة، انطلقنا من تعلم أساسيات ومكونات صفحات الهبوط إلى بناء واحدة لتطبيق وهمي، أول مقال ليس مخصصا للمطوريين أو المصممين بشكل خاص، أيّ مسوق أو مدير مشروع يستطيع أن يبني صفحة هبوط منتجه انطلاقا من ذلك الدليل على ورقة وإرساله لمطور ما، المقالان الآخيران كان أكثر تعمقا حيث في الواقع تطبيقا لما تعلمناه، الآن لكم المقدرة على إطلاق صفحات لمشاريعك، وجلب عملاء أكثر ومشتريين أكثر
  12. في المقال السابق تعرّفنا على ماهية صفحة الهبوط، أساسيات وأهم عناصر كل صفحة، كما ألقينا النظرة على بعض الصفحات الشائعة، الآن سنطبق ما تعلمناه في بناء صفحة خاصة بنا. الصفحة التي سنقوم ببنائها ستكون حول تطبيق وهمي، وهو شبكة تواصل تدعى "اهتمامات"، هيا لنبدأ. هذه هي النتيجة النهائية التي سنصل لها بعد تطبيق جميع خطوات الدّرس: الأساسياتسنقوم أولا بإعداد بعض الأمور من أجل العمل. علينا فتح صفحة عمل جديد بأبعاد 1920x6000px من أجل يكون لدينا المتسع للعمل عليه.سنستعمل خط خط Cocon العربي المجاني.سنضع صورة لرأس الصفحة، تستطيع الحصول على أيّ صورة تريدها من مواقع الصور المجانية مثل unsplash.سنستخدم بعض التصاميم الجاهزة من أجل الصفحات، احرص أن تحصل على صور حقيقية في حال كنت تبني تطبيقك، بالنسبة للتصاميم سنحصل عليها من Okilla.سنحتاج إلى إطار للهاتف من أجل أن نضع فيه صورة خاصة بنا في رأس الصفحة، تستطيع الحصول عليه من مجموعة عناصر iOS8 في موقع teehan lax.سنستعمل Grid جاهز من أجل البناء عليه حتى نستخدمه لاحقا في التطوير، من أجل هذا سنحصل على Grid الخاص بإطار Bootstrap وتستطيع تحميله من هنا.سنستعمل مجموعة من الأيقونات المجانية من أجل العمل، اسم المجموعة هي Retina Icons وهي 120 أيقونة مجانية تستطيعون تحميلها من هنا.رأس الصفحةسنبدأ بإعداد رأس الصفحة، وهذا بعد أن قمنا بوضع Grid في المكان المناسب حسنا بعد أن قمنا بهذا، سنقوم بجلب صورة الهيدر المناسبة ووضع overlay أسود شفاف فوقها بشفافية `50%`. سنقوم الآن بإحضار صورة التطبيق للغلاف، سبق وصممت هذه الصورة حتى نستعملها مباشرة. عبر Grid سنختار 6 أجزاء (النصف) ثم نضع الصورة في منتصف ذلك الجزء، نستطيع وضع الصورة في المنتصف عبر تحديد المساحة التي نريد أن نضعه فيها ثم نختار الأزرار المحددة في الأسفل سنختار الآن النصف الثاني، ونضع فيه عنوان الصفحة بخط كبير. أسفله سنضيف نبذة سريعة عن التطبيق، ثم أسفل ذلك سنضيف زر CTA والذي سيكون عبارة زر للتحميل من متجر التطبيقات، احرص على أن تستخدم دوما التصميم الرسمي الذي يتم إدراج في صفحة apple brand guidelines وهو متوفر ب50 لغة، سنستخدم نحن النسخة العربية. لسنا بحاجة لإضافة روابط للتصفح في الهيدر لأننا سنقوم بذلك في الأسفل عبر قائمة ثابتة. روابط التحكمالآن سنقوم ببناء روابط التحكم، وهو عبارة عن قائمة ثابتة في أعلى الصفحة، حيث تثبت بعدما تخرج من إطار الشاشة، القائمة ستكون عبارة عن 4 أيقونات نحصل عليهم من مجموعة Retina Icons سيستغل كل واحد منهم جزئين (السدس) ويتم تنصيفهم في الوسط. التقديم بالتطبيقفي هذا الجزء سنقوم ببناء التقديم بالتطبيق، سيكون عبارة عن 3 أجزاء، كل جزء منهم يتكون من صورة من التطبيق إلى جانب عنوان يصفها وشرح أكثر أسفل العنوان. التقسيم سيكون مماثلا لرأس الصفحة، الصورة تستغل نصف الصفحة، والمحتوى يتسغل النصف الآخر، لكن هذه المرة سيكون المحتوى أقل في الحجم. سنقوم بالأمر ثلاث مرة، في الجزء الثاني سنقلب الاتجاه بحيث يصبح المحتوى على اليمين كما سنغير الخلفية إلى شيء داكن. جزء بناء الثقةجزء بناء الثقة سيتكون من جزئين، وهما بعض شهادات المستخدمين، وبعض الأرقام فلا شيء يبني الثقة في محل الزبون كاستخدام الأرقام فهي شيء سهل القراءة وسريع الملاحظة ويسهل استخدامها للمقارنة. بالنسبة لجزء شهادات المستخدمين، سوف سنستخدم slider حيث أن كل لقطة ستحتوي على شهادة ومعها صورة لصاحبها، الصورة كما تكلمنا في المقال السابق تساعد في كسب الثقة لأنك تعرف مصدر الكلام. أما بالنسبة لجزء الأرقام، فسنستخدم خلفية أخرى (صورة) حتى نجذب الانتباه، سنقوم بتقسيم الصفحة إلى 4 أجزاء، مع كل جزء يحتوي على أيقونة تعبيرية، بالإضافة إلى الرقم وما نحاول نسب الرقم له (عدد الأعضاء، عدد التحميلات...) جزء التحويلفي هذا الجزء نحن لا نملك الكثير لنقدمه، لذا سوف نقوم بإضافة زر التحميل من متجر التطبيقات مجددا إلى جانب إضافة أزرار نشر التطبيق في شبكات التواصل الاجتماعي، سنستخدم أيقونات Entypo الاجتماعية الإعداد للمرحلة القادمةحسنا، عند النقطة نكون رسميا قد انتهينا من التصميم، لقد اتبعنا أهم المعايير المطلوبة منا، وحان الوقت لنحول التصميم إلى صفحة حقيقية، وهذا ما سنقوم به في المقال القادم، ولكن إلى ذلك الحين، نحن لدينا العديد من الصور، ونحتاج إلى استخراجها كلها، وأمامنا طريقان، أخذ كل صورة لوحدها ونسخها وفتح صفحة جديدة ولصق الصورة فيها ثم تغيير إعدادات الصفحة لتناسب أبعاد الصورة ثم حفظ الصورة، وهذه الطريقة كما استنتجت، بدائية. لذا نستطيع أن نستخدم الطريقة الذكية، والتي هي كالتالي، سنعود لكل طبقات الصور (صور التطبيق والأيقونات والخليفات) ونغير اسمها إلى اسم الملف الذي نريده إلى جانب الامتداد، مثلا أغير اسم خلفية رأس الصفحة إلى `background.png` بعد أن نقوم بكل هذا، سنذهب إلى `File>>Generate>>Image Assets` ونُفّلعه، وبعدها نقوم بحفظ العمل بصيغة PSD ليقوم فوتوشوب بحفظ كل الصور التي نريدها في مجلد جانبي (باسم ملف PSD الخاص بنا) وبداخله كل الصورة جاهزة، أوليس هذا رائعا؟ خاتمةفي الدرس القادم سوف نطلع على كيفية بناء الصفحة، مع تعلم بعض الأمور الجديدة واستعمال بعض المعايير في بناء الصفحات.
  13. سواءًا كنت تعمل على صفحة هبوط لمنتج، لخدمة أو على صفحتك الشخصية من أجل عملك الحر، فإن كل الصفحات تشترك في عدة أمور بينها. اليوم سنشاهد دور كل واحد منها، وأنواعاها ومتى نستعلمها وما الفائدة منها. في هذا الدرس سنتطرق إلى 6 أجزاء مهمة في كل صفحة، وهي على الترتيب كالتالي: رأس الصفحة (Header) التعريف القيمة أو الشيء المميز محل الثقة نقطة التحويل (Call to action) ذيل الصفحة (Footer) سنستعين برسوم تويضحية في الطريق لفهم وشرح كل نقطة وكيف نستخدمها على أتم وجه، وفي نهاية الدرس ستكون قادرا على إنشاء صفحة هبوط أو صفحة شخصية بكل سهولة. لكن تذكر، لا صفحة تشبه الأخرى، ولا منتج يشبه الآخر، لذا قد لا يفيدك هذا الأمر تماما ولا يغطي احتياجياتك. ماهي صفحة الهبوط؟حتى نعرف ما الذي نقوم به، علينا أن نعرف أولا ماهي صفحة الهبوط، حسب موقع unbounce فإن صفحة هبوط هي: إذا، حسب هذا المفهوم، صفحة الهبوط تستطيع أن تكون صفحة لبيع كتاب، لبيع منتج ما، للتسجيل في خدمة، لطرح فكرة، لتقديم خدمة... كل هذه الأمور مختلفة، ولكنها تشترك في شيء واحد وهي أنّها تريد أن تحول الزائر إلى زبون. صفحات الهبوط تنقسم إلى قسمين اثنين، صفحات التحويل (Click Through) وصفحات التجميع (Lead Generation). صفحات التحويلصفحات التحويل هي كل الصفحات التي تحول المستخدم إلى صفحة أخرى، صفحات مثل هذه تحول المستخدم إلى متجر، إلى منصة البيع، أو بشكل عام هذه الصفحات تقدم المعلومات الشاملة للشيء، وليست مسؤولة عن تحويل المستخدم إلى زبون بشكل مباشرة، ولكن لها علاقة كبيرة بالأمر. صفحات التجميعصفحات التجميع هي الصفحات الأخرى، وتكون هذه الصفحات للتسجيل، للبيع مباشرة، للاشتراك، أو لملأ استمارة ما، أو للتواصل المباشرة، للحصول على نسخة الكترونية من كتاب أو منتج ما أو للتعريف بمنتج ما (مع هدف مشاركة المستخدم له عبر حساباته في الشبكات الاجتماعية). 1. رأس الصفحة (Header)من بين كل الأجزاء الأخرى، رأس الصفحة يكاد يكون أهم جزء في أيّ صفحة، فهو يستغل منطقة fold وهي المنطقة التي يراها المستخدم فور وصوله للصفحة بدون التمرير للأسفل، نشر أحمد مجدي في معمل ألوان مقالا ممتازا عن هذه النقطة. بهذه المنطقة بالتحديد، على المصمم أن يستعرض بعض النقاط المهمة، وهذه النقاط تكون كالتالي: الفكرة الموجزة تكون هذه الفكرة عادة عنوانا كبيرا بخط عريض في وسط الصفحة ليدل المستخدم على ماهية المنتج أو الخدمة (برنامج، أو خدمة ويب). أو عنوانا لكتاب مع شرح بسيط له وغلاف الكتاب: أو الاسم ومجال التخصص في حال كانت صفحة شخصية لمستقل أو شركة: في الحالات السابقة يتم إضافة شعار فوق الفكرة الموجزة، وفي حال صفحة شخصية يتم إضافة صورة شخصية، في حال منتج ككتاب أو شيء مشابه، يتم إضافة الغلاف. نقطة التحويل (Call to action) يتم إضافة هذا الجزء للهيدر عادة لأهميته. سنتكلم عن التفاصيل أكثر في جزئه المخصص، أما هنا فنشرح أهم النقاط. عادة هذا الجزء يكون زرا، أو مُدخلا (input). الزر يسمح للشخص بالانتقال إلى جزء الشراء، أو إلى صفحة التسجيل، أو إلى استمارة التواصل: وعندما لا يوجد شيء ليقود له هذا الجزء، يتم استعمال زر للتنقل إلى الجزء الذي بعده. يمكن أن يكون مُدخلا للاشتراك في قائمة بريدية من أجل التنبيه، أو للتسجيل في الخدمة، أو للحصول عل المنتج عبر إرساله في البريد. روابط التصفح (navigation) تكون روابط التصفح عادة موجزة ومسؤولة عن التصفح داخل الصفحة وليس من أجل روابط لخارج الصفحة، تحتوي القائمة على أقسام الصفحة (مثل التعريف، نقطة التحويل، التسعير...) يستحسن أن تكون متلصقة (sticky أو fixed) من أجل أن تكون في متناول اليد دوما. يوجد أكثر من نوع لذلك الجزء، تستطيع مثلا وضع زر للتسجيل بداخله: لإبقاء الزر قريبا من المستخدم دوما، عادة يحدث هذا للصفحات التي تبيع منتجا أو تقدم خدمة، بحيث في أيّ نقطة ما يكون المستخدم قد حصل على ما يكفي من المعلومات وهو بالتالي مستعد للطلب أو التواصل. 2. التعريفالتعريف هو جزء مهم في بعض الحالات ولكنه أمر اختياري في حالات أخرى، مثلا في صفحات لمنتج ما أو خدمة فيمكن الاستغناء عن التعريف حيث أنّه سيكون مدمجا في جزء "القيمة"، في حالات أخرى قد يكون مفيدا، في حال كنت مستقلا أو شركة أو خدمة جديدة، فالتعريف سيعطي الزائر فكرة عن الموقع أو الخدمة، التعريف يكون نصيا، التعريف التي يستخدم الصور محله يكون في جزء "القيمة". كمثال تعريف لمستقل يجب أن يحتوي على اسم المستقل، ربما البلد (في حالات معينة) ومجال الاختصاص وما ستقوم به بالتحديد عادة، نبذة عن الشخص وعن مراكز عمله السابقة ستعطي ثقة أكثر للعميل، حيث سيدرك أنه لا يتواصل مع آلة بل مع انسان فعلي. نفس الأمر ينطبق على الشركات، حاول أن تجعل الجزء قصيرا ومباشرا، لا أحد يملك الوقت لقراءة نص طويل. إذا وجدت أن "الفكرة الموجزة' رأس الصفحة تكفي لتشرح الفكرة فلا داعي لوضع تعريف. كما قلنا التعريف أمر اختياري تماما والعديد من الأشخاص يختارون عدم استخدامه. 3. القيمةالقيمة أو الشيء المميز هي أهم جزء في أيّ صفحة هبوط، فهي تشرح الخواص والمميزات لمنتج ما، أو خدمة ما، تقدم شرحا وافيا للكتاب، أو تقدم مجالات خبرة المستقل أو خدمات الشركة. أحيانا يختار المستقل تجاهل هذه المرحلة وجعل العمل يتكلم عن نفسه في جزء "محل الثقة" لكن ليتم هذا على المستقل أو يصف كامل مهاراته في الجزء الأسبق وهو "التعريف". بالنسبة للتطبيقات فهي تستغل هذه النقطة في عرض مميزات للتطبيق مثلا: أما عن المواقع أو خدمات الويب فهي تعرض المميزات على شكل نقاط مع أيقونة لكل جزء: 4. محل الثقةلأنّك لا تستطيع أن تقفز على شخص في الطريق من اللامكان ثم تخبره أنّ عليه أن يشتري منتجك المذهل أو يستأجرك للعمل، أنت أيضا لا تستطيع أن تطلب من زائر دخل لتوه الموقع أن يشتري منتجك، لذا عليك أن تبني ثقة لدى الزائر، وهنا يأتي جزء محل الثقة. محل الثقة قد تعني أكثر من شيء، ولكنها بالمجمل العام المكان الذي يُكسب الزائر ثقة في المنتج أو المشروع أو الشخص. ويكون له أكثر من شكل: العملاء: عادة ما يستخدم هذا بكثرة مع المستقلين ومع البرامج والخدمات. جزء العملاء يكون بأن يتم وضع مجموعة من شعارات أهم العملاء الذين مروا على العميل/منتج [figure 11]. يكسب العميل ثقة مباشرة في المنتج في حال رؤية شعارات شركات معروفة، هذا يعني له أنّ المنتج جيد وبالتالي يستحق المال الذي سيصرفهالتغطية الإعلامية: التغطية الإعلامية تكون عندما لا يوجد عملاء لاستخدامهم، أو عندما لا يكون من المنطقي استخدام عملاء (كتاب مثلا). في هذه الحالات يتم إضافة شعارات المواقع الإخبارية التي قامت بتغطية المنتج ويكون شكلها شبيها بشكل العملاء السابقيين، التغطية الإعلامية تُكسب قدر جيد من الثقة أيضا.الشهادات: الشهادات هي الخيار الثالث ومن أكثر الخيارات شيوعا، ببساطة تعتمد طريقة الشهادات على إدراج شهادات حقيقية من العملاء السابقين أو أشخاص جربوا الخدمة. أن تقول جملة عشوائية لوحدك، وأن تقول نفس الجملة ثم تُرفق أنها من قول العالم الفلاني أمران مختلفان، فالأخير يكسب ثقة أكبر في الجملة وبالتالي يجعلها ذات مصداقية، لذلك شهادات العملاء يجب أن تتبع نفس النسق، لذا ينصح أن يتم إضافة اسم صاحب الشهادة، وكذى صورته، حيث الصورة تجعل الزائر يعرف أنّه يسمع من شخص ما ربما قد رآه من قبل. وإضافة منصب العمل قد يكون مهما أيضا، أنت ستثق بمسؤول التصميم في شركة ما إذا كان يتكلم حول برنامج تصميم مثلا.الشبكات الاجتماعية: في حال لم يتوفر شيء مما سبق، فخيار آخر هو الشبكات الاجتماعية، لكن الأمر لا يصلح دوما، فعدد قليل من الصفحات تستفيد من الشبكات، ولكن إن كانت خدمتك أو موقعك يملك جمهوريا جيدا على الشبكات الاجتماعية، فمن المستحسن أن تضيف عدد المتابعين أو المعجبين من الشبكات الاجتماعية.صاحب المنتج: قد يبدو الأمر غريبا بعض الشيء لأول وهلة، ولكن إذا قرر بيل غيتس إنشاء صفحة لمنتجه فالأغلب أنه سيضيف صورته أو يجعل الأمر واضحا أنّه هو المالك . الأمر لا ينجح كثيرا لأننا لست دوما مشاهير، ولكن ربما كنت تسوق كتابا لكاتب معروف، فإضافة صورته ونبذة عنه تولد بعض الثقة أيضا. المشاريع السابقة: الأمر مخطط للمستقلين أو الشركات والوكالات بشكل خاص. المشاريع السابقة أو معرض الأعمال (Portfolio) هو أهم جزء في صفحة هبوط لمستقل، أن تقول أنّك مصمم بارع، وأن تظهر للزائر أنّك مصمم بارع بعرض أمثلة حقيقية هما أمران مختلفان. النمط السائد في عرض في المشاريع هو على شكل مربعات (grid) ولكن أنت حر بعرضها بأيّ طريقة تشاء.5. نقطة التحويل (Call to action)يأتي أهم جزء في كل الصفحات، أو كما يقول المثل الشعبي (الزبدة). فكل ما سبق كان لتحضير الزائر لهذه النقطة بالتحديد. لقد عرفت المنتج، أعطيت قيمته الفعلية، وبنيت الثقة لدى الزائر، تأتي النقطة التي يحين فيها تحويل الزائر إلى زبون، عادة هذا الجزء يكون زرا يقود لصفحة للتسجيل، أو لتحميل ملف ما، لإدخال معلومات للتسجيل في نشرة، جدول للاشتراكات. دعنا نشاهد أشكاله المختلفة: الزر: هذا الشكل هو الأكثر شيوعا وهو يتكون من زر كبير نسبيا، ويكون واضحا ويملك لونا مختلفا عن بقية العناصر حتى يستقل عنهم، يجب أن يكون بعبارة واضحة وغير خادعة للزائر، كأن تعرض فترة تجريبية وعندما يسجل الزائر لا يجد شيئا. العبارة يجب أن تكون لطيفة وغير عدائية، عبارات مثل "اشتري الآن" أو "حمل الكتاب" أو "سجل معنا" أو "تواصل" هي عبارات معتادة ولا تقدم الكثير من الحماس أو الرغبة للزبون لذا عليك أن تجرب عبارات تبدو وكأنها صدرت من انسان أو أقل عدائية مثل "هيا لنبني شيئا معا". اللون شيء مهم في كل زر، إلا أذا كنت ملزما بلون واحد لهوية الموقع أو المنتج، فعليك أن تختار الألوان بحذر، في تجربة قام بها موقع Performable وُجد أن تغيير لون الزر من الأخضر إلى الأحمر رفع نسبة التحويل (وهي عدد الزبائن على عدد الزوار) بنسبة 21% حيث أنّ اللون الأحمر يصنع شعورا بالعجلة ويَبرز أكثرمن بقية الألوان، والقاعدة العامة هي أنّ كل الألوان الساخنة (أحمر، برتقالي، أصفر، بنفسجي محمر...) مرحب بها. استمارة: وهو النوع الثاني الأكثر شيوعا وهو يتكون من استمارة يملأها الزائر من أجل الاشتراك في نشرة بريدية، أو من أجل الاشتراك في الخدمة، أو من أجل التواصل الجداول: شكل آخر شائع هو الجداول، فهي تسمح لك بعرض خطط الاشتراك، الاستضافة، باقات الشراء، وأيّ شيء تستطيع أن تبيعه في أكثر من باقة بأكثر من سعر، عادة يتم التركيز على العرض أو الباقة الأكثر شيوعا ووضعه في المنتصف وتمييزه عن البقية. 6. ذيل الموقع (Footer)ذيل الموقع لا تكون له أهمية كبيرة في بعض الصفحات، بعض الصفحات تختار أن تزيله تماما لأنها تريد أن ينصب تركيز الزائر على جزء التحويل فحسب. إذا كانت الصفحة هي تقديما لموقع ما، فالأحرى أن تضيف الذيل لتضع فيه روابط ترسل إلى أماكن أخرى، إلى جانب الصفحات الاجتماعية نظرة على صفحات حقيقيةفي هذا الجزء سنلقي نظرة على صفحات هبوط من الواقع، وكيف طبقت القواعد البسيطة العامة. صفحة كتاب Zero to oneكتاب Zero to one كتاب رائع قد سبق وأن قرأته، وكتاب رائع كهذا لابد أنّه سيملك صفحة رائعة لبيعه: Zero to One book. رأس الصفحة مباشر ويحتوي أهم المعلومات المتوقعة، فهو يحتوي على روابط للتصفح داخل الصفحة مثل معلومات حول الكتاب وحول صاحبه، الواجهة تملك صورة لغلاف الكتاب إلى جانب سطر تشويقي للكتاب، مع وجود زرين، أول زر وهو أهمهم ويعمل بصفته زر Call to action من أجل شراء الكتاب، الزر الثاني هو من أجل قراءة مقتطف من الكتاب بشكل مجاني. عند النزول تحصل على شهادات حول الكتاب من شخصيات معروفة وهذا لبناء الثقة حول المنتج. الموقع مقسم إلى أكثر من صفحة للتوزيع الجيد للمحتوى، مع تواجد جزء التحويل (call to action) أسفل كل صفحة لضمان وجوده قرب المستخدم دوما. تطبيق التصميم InvisionInvision هو منصة وتطبيق لصنع التصاميم الأولية (prototype) جنبا إلى جنب مع فريقك. في الأغلب ستتوقع تصميما ممتازا من منصة للتصميم، وهذا ما ستحصل عليه مع صفحة هبوط تطبيق Invision. رأس الصفحة يقدم أهم العناصر اللازمة لأيّ زائر، جزء التصفح يملك روابطا تأخذك إلى أجزاء مهمة في المنصة إلى جانب زر بارز للتسجيل. تحتوي الصفحة على عنوان كبير يصف المنصة إلى جانب سطر آخر للشرح. مع وضع زر CTA. بالنزول نجد مميزات المنصة وإلى جانب كل واحدة منها شهادة أحد الزبائن إلى جانب شعار شركته من أجل بناء الثقة في كلامه. في الأسفل نجد جزء بناء الثقة حيث يقوم التصميم بعرض أهم العملاء وقصصهم مع التطبيق. أخيرا يتم التطرق إلى جزء التحويل حيث أنّه استمارة للاشتراك في التطبيق خاتمةفي هذه المقالة تطرقنا إلى مامعنى صفحة هبوط، وإلى أهم الأساليب والعناصر في كل صفحة، كما عرضنا بعض الأمثلة الناجحة من الحياة اليومية. في المقالين القادمين سنقوم بتصميم وبناء صفحة هبوط خاصة بنا باتباع ما تكلمنا عنه هنا.
  14. لربما لاحظت مُؤخّرا أنّ CSS في تطور مستمر، وإلى الأفضل بالطبع. فمن جهة لدينا العديد من المُميّزات الجديدة (مثل القواعد الجديدة @rules وأشباه الأصناف المطورة) ونظم بناء الصّفحات وتقسيمها (مثل flexbox و Grid system). ومن جهة أخرى لدينا بعض الأدوات التي تُتيح لنا التّلاعب بالأشكال والصور مباشرة من المتصفح، وأنا أحب هذه الأمور، ومتأكد من أنّك تُحبّها أيضًا، وفي هذه المقالة سنعرض بعضا منها. سنتحدث عن بعض الأمور التي لا تحظى بالكثير من الشّهرة عادة، هذه الأمور المجهولة ستزيد من إنتاجيتك بشكل مُعتبر، وستجعلك تُفكّر بطرق مُختلفة لحلّ المشاكل اليومية. بعض هذه الأمور هي المُحدّدات Selectors الجديدة الخاصة باللغة، والبعض الآخر عبارة عن دوال، وأشباه أصناف pseudo-classes جديدة. وحدات القياس النّسبيةبحكم أنّنا في 2015 فلابد وأنّك قد تعاملت من قبل مع الوحدات النّسبية em والنّسب المئوية. ولذا فأنا واثق من أنّك وقعت في المُشكلة الشّائعة والتي تكمن في استخدام هذه الوحدات ضمن الوراثة. سأشرح الأمر بمثال بسيط. من الشّائع مُؤخّرًا أن يتمّ استعمال حجم خط ثابت في الصّفحة، ومن بعدها استعمال وحدات القياس النّسبية لتحديد حجم الخطّ لبقية العناصر في الصفحة. في CSS سيبدو الأمر كالتالي: html { font-size: 10px; } p { font-size: 1.4em; }إلى غاية هذه اللحظة، كل شيء يسير على ما يرام. لكن تظهر المشكلة عندما تريد أن تحدد حجم خط مُختلف لعنصر ما داخل العُنصر السّابق. لنجرب المثال التالي: The cat sat on the <span>mat</span>.إذا أردت أن يكون حجم خط span أصغر مثلا، وليكن مثلًا 1.2em، فما الذي ستفعله؟ تحضر الآلة الحاسبة وتحسب نتيجة 1.2/1.4؟ لتحصل على شيء كهذا: p span { font-size: 0.85714em; }مشكلة الوراثة ليست محدودة في em فحسب. فإذا كُنت تستخدم النّسب المئوية فالقيمة عادة منسوبة إلى العنصر الحاوي (الأب) وليس إلى حجم الصّفحة. لنضرب مثالًا بسيطًا، ولنقل أنك تملك عنصرًا بارتفاع يُقدّر بـ75% من الصفحة، وهذا العنصر يملك بداخله عنصرًا آخر، ونحن نريد من العنصر الابن أن يكون بارتفاع 40% من الصفحة، في هذه الحالة عليك أن تعطيه قيمة 53.33333%. الأمر ليس مثالّيًّا إطلاقًا. القيم المنسوبة إلى أساس ثابتكالعادة، لكل مشكلة حل. في حالتنا تم تقديم وحدة جديدة تُدعى rem. هذه الوحدة هي وحدة نسبية، ولكنها منسوبة إلى قيمة ثابتة وليس إلى حاويها. هذه القيمة هي حجم الخط في العنصر الأساسي في الصفحة (في حالة HTML فهذا العنصر هو دوما وسم html ). في مثالنا السابق، استعملنا 10px كحجم الخط في الصفحة، سنرى كيف يمكن لـrem أن تساعدنا: p { font-size: 1.4rem; } p span { font-size: 1.2rem; }الآن كلاّ من قيمة التصريحين منسوبة إلى حجم الخط المبدئي، وهذا أفضل من ناحية التّحكم والاستخدام. خُصوصًا إذا كنت تملك حجمًا مبدئيًّا بسيطًا مثل 10px أو 12px. الأمر شبيه باستخدام وحدة البكسل مُجدّدًا، عدى أنها قابلة للتوسع. هذه الخاصّيّة مدعومة بشكل جيّد من المُتصفّحات. كل المُتصفّحات المُتطوّرة إلى جانب IE9 تقوم بدعمها. لكن هناك مشاكل بسيطة في الدعم، فمُتصفّح IE لا يدعمها في حال ما إذا استخدمتها داخل الخاصّيّة المُختصرة font ويتم تجاهل التّصريح كاملًا. تستطيع قراءة المشاكل المعروفة هنا في خانة Known Issues في الأسفل Can I use rem. وحدات القياس المنسوبة إلى النّافذة (Viewport)إلى جانب وحدة rem، هناك وحدات جديدة أخرى. هذه الوحدات أتت لتحلّ مُشكلة النّسب المئوية والوراثة. هذه الوحدات تعمل بطريقة مُشابهة لـrem عدى أنّ الأساس التي تعتمد عليه هو أبعاد النّافذة أو شاشة الجهاز. الوحدات الرّئيسية هي vh (التي ترمز إلى viewport height) و vw (التي ترمز إلى viewport width) وهي منسوبة إلى ارتفاع وعرض النّافذة. الوحدتان منسوبتان إلى أبعاد النّافذة حيث أن قيمة واحدة تقدر بـ 1 بالمئة من أبعاد الشّاشة. أيّ `1vw = 1%’. هذا مثال بسيط لنشرح به الأمر: div { height: 50vh; }في هذا المثال، ارتفاع العنصر سيكون بالتّحديد نصف ارتفاع النافذة، حيث أنّه -كما أسلفنا- 1vh = 1% أيّ أن 50vh = 50%من ارتفاع النّافذة. قيمة الوحدة -كما سبقت الإشارة إليه- منسوبة إلى أبعاد النّافذة، فإذا تغيّر حجم النافذة ستتغير معه قيمة الوحدة. أُنشئت هذه الوحدة لتحل مشكلة النّسب المئوية في الوراثة، حيث أنّ10vw ستبقى دومًا منسوبة إلى حجم النّافذة مهما كان حجم الحاوي. هناك أيضا وحدة vmin والتي تُساوي أصغر قيمة من أيّ من vh أو vw، إلى جانب وحدة vmax التي تقوم بالعكس أيّ أكبر قيمة من أيّ منهما. دعم المتصفحات جيد، فكل المتصفحات إلى جانب IE9 تقوم بدعم كل من vh وvw. دعم وحدة vmin جيّد أيضًا، على عكس وحدة vmax فهي غير مدعومة في كل إصدارات IE. هناك بعض المشاكل في chrome في الإصدارات التي سبقت 34 (عند استعمال الوحدة داخل border وبعض التصريحات الأخرى) Can I use Viewport units. القيم المحسوبةخلال عملك على موقع مُتجاوب، ستصادفك مشكلة شائعة وهي الخلط بين الوحدات. كمثال على ذلك: أنت تريد أن تُسند إلى عنصر ما حجمًا بالنّسب المئوية، ولكنك تريد أن تُضيف له حاشيّة بقيمة ثابتة (عبر البكسل)، شيء كهذا مثلا: div { margin: 20px; width: 33%; }إن كنت تستخدم قيم padding و border فحسب في تقسيم عناصرك في الصّفحة، فتستطيع تخطّي المُشكلة السّابقة عبر استخدام box-sizing: border-box ولكن هذه الخاصّيّة لن تُساعدك في حال كنت تستخدم الحواشي margins. لذا تم توفير دالة تُدعى بـ calc(). هذه الدّالة تسمح لك بالقيام بعمليات حسابية على مختلف الوحدات. شاهد هذا المثال: div { margin: 20px; width: calc(33% - 40px); }تستطيع استعمال الخاصّيّة في أيّ مكان تريد، ولو داخل نفسها. انظر للمثال في الأسفل: width: calc(calc(50% - 4em) + 4vmin);هذه الخاصّيّة مدعومة بشكل جيد، كل الإصدارات الحديثة من المُتصفّحات إلى جانب الإصدار 9 من IE تدعمها (هناك بعض الاستثناءات التي يمكنك قراءتها في خانة known issues على Can I use calc()). تحميل مجموعة مُعيّنة من الأحرفالأداء هو عامل رئيسي في بقاء الزّائر في موقعك من عدمه. وسرعة تحميل الموقع هي أحد هذه العوامل. والآن مع انتشار الهواتف الذّكيّة وشبكات الإنترنت اللاسلكية (شبكات 3G التي من مشاكلها التّدفّق البطيء) تدفع المطور للتّحسين من سرعة الموقع أكثر وأكثر. القاعدة الرئيسية في تقليل وقت التحميل هي التقليل من حجم وعدد الملفّات الخارجية، والخاصيّة التّالية تقوم بهذا الأمر. الخاصية الجديدة تُدعى unicode-range وهي تأخذ مجالًا مُعيّنًا من unicode كقيمة (unicode هو إعطاء كل محرف قيمة له على مجال ما، مثلا الأحرف العربية تقع في المجال 0600—06FF وتقدر بحوالي 255 رمز، وكل ترميز يخصّ محرفًا). هذه الخاصّيّة تُضاف إلى تصريح @font-face. وعندما يقوم المُتصفّح بجلب الخط، سيقوم بجلب الحُرُوف المُحدّدة فحسب، ويتم التّخلّص من الحروف غير المرغوب فيها. الأمر مُفيدٌ جدًّا في الخطوط الكبيرة جدًّا مثل Helvetica الذي يُقدّر حجمه بـ500kbs ويحتوي أغلب لغات العالم. في هذا المثال سنقوم بسحب الحروف “عـ ، ـلـ، ـم” (يجب التّنويه إلى أنّ حرف العين المُنفصل ‘ع’ يملك رمزًا مُستقلّا عن حرف العين في أول الكلمة ‘عـ’ والذي يملك رمزًا مُستقلًّا عن نفس الحرف في نهاية الكلمة أو في وسطها، وهذا الأمر ينطبق على كلّ الحروف. تستطيع معرفة ترميز كل حرف من هنا). @font-face { font-family: foo; src: url('helvetica.ttf'); unicode-range: U+FECB,U+FEE0,U+FEE2; }في هذا المثال سنقوم بسحب الحروف العربية فقط عبر مجال كامل: @font-face { font-family: foo; src: url('helvetica.ttf'); unicode-range: U+0600-06FF; }سيُقلّل هذا من حجم الخط من 500kb إلى حوالي 30kb وهذا تحسن مُمتاز جدًّا. دعم المُتصفّحات ليس جيّدًا بما فيه الكفاية حاليًّا، الخاصية مدعومة من طرف chrome و من طرف Safari ومتصفح فيَرفُكس سيدعم الخاصية ابتدءًا من الإصدار 36، كما أنّها مدعومة من طرف IE9+ لكن يتم تجاهلها إذا استُخدمت u على شكل صغير (lowercase). Can I use Font unicode-range subsetting أشباه الأصناف الجديدة (pseudo-classes)إلى جانب كل تلك الأمور الجميلة التي رأيناها، فأنا أجزم أنّ أشباه الأصناف هي أجمل ما تم إصداره، عبر تحديد أنماط مُعيّنة من خلالها أصبحنا نملك القدرة على تحديد عناصر تتبع نمطًا مُعيّنًا وهذا من شأنه تقليل كمية الجافاسكربت المُستخدمة. شبه صنف التّجاهل (negation pseudo-class)شبه صنف التجاهل الجديد not() هو صنع رائع جدا إذا عرفت أين تستخدمه. لتستخدمه عليك أن تُمرّر مُحدّدًا (على شرط أن لا يكون مُركّبًا). سيتم تطبيق كل التأثيرات المُرادة على مجموعة العناصر هذه عدى العُنصر الذي تمّ تمريره للصّنف. فلنلق نظرة على المثال التّالي: لنقل أن لديك مجموعة من العناصر، وتريد أنّ تغيّر لون كل عنصر ذي مرتبة زوجية ما عدى العنصر الأخير، ستقوم بشيء كهذا: li { color: white;} li:nth-child(even) { color: red;} li:last-child { color: white;}لكن عبر مُحدّد التّجاهل تستطيع القيام بهذا عبر الشكل التالي li { color: white;} li:nth-child(even):not(:last-child) { color: red;}الخاصّيّة ليست عجيبة، فكما رأيت تستطيع أن تعيش بدونها، ولكنك ستقع في حالات تكون فيها الخاصية مُفيدة جدًّا. الخاصّيّة مدعومة بشكل جيد من طرف المُتصفّحات الحديثة ومن طرف IE9+. شبه صنف المُطابقة (matches-any pseudo-class)شبه صنف matches() يقبل مُحدِّدًا (selector)، أو مُحدِّدًا مُركّبًا، أو مجموعة من المُحدّدَات. لكن ما الذي يفعله؟ إنّه مفيد للقيام بتأثير ما على مجموعة من العناصر. كمثال، تخيل أنّه لديك مجموعة من وسوم الفقرات <p> في أماكن مختلفة من الصّفحة، وأنت تريد التّأثير على مجموعة مُعيّنة منها، قد تقوم بالأمر التّالي: .home header p, .home footer p, .home aside p { color: #F00; }لكن مع matches() تستطيع اختصار الأمر السّابق عبر إيجاد الأمور المشتركة في ما سبق. في مثالنا كل سطر يبدأ بـ .home وينتهي بـ p، لذا نستطيع استخدام matches() لتحديد كل العناصر الموجودة بينهما. لم تفهم كيف سنقوم بذلك؟ لابأس، هذا ما سنفعله: .home :matches(header,footer,aside) p { color: #F00; }شبه الصنف هذا هو جزء من CSS4 لذا دعمه ليس قويًّا كالبقية. حاليًّا تستطيع استخدامه مع chrome و safari بشكل عادي وفي IE9+ تحت الاسم matchesSelector وفي فيَرفُكس أيضًا، من الأفضل أخط الحيطة واستخدامه مع -moz- و -webkit- قبل اسمه. Can I use matches() DOM method إذًا، ما رأيك في ما سبق؟الرائع بشأن هذه الخواص أنها تحل مشاكل فعلية في حياتنا اليومية، انطلاقًا من المُحددّات المُتكرّرة المُزعجة في CSS إلى طرق أكثر رُقيًّا في بناء المواقع التجاوبية. سبق وأن استخدمت العديد من هذه الخواص كثيرا وسأستخدمها مُجدّدًا. الميزات الجديدة الأخرى مثل المُرشِّحات (filters) الخاصّة بالصّور قد تكون أجمل ولكن استخدامها محدُود على عكس الميزات التي استعرضناها. كل واحدة منها تستطيع جعل حياتك أسهل بشكل أكثر، ولكن لا تتوقّف هنا. هناك الكثير لتتعلمه فلا تتوقف عن البحث. ترجمة -وبتصرّف- للمقال Learning to Love the Boring Bits of CSS لصاحبه Peter Gasston
×
×
  • أضف...