البحث في الموقع
المحتوى عن 'css3'.
-
مستطيلات داخل مستطيلات هذا هو التصميم المعتمد عند الغالبية في بناء صفحات الويب الخاصة بنا، ولكننا نحاول الآن كسر هذه الصورة النمطية عن أشكال CSS من خلال استخدام أشكال هندسية جديدة، ولكن هذه الأشكال Shapes لا تتفاعل أبدًا مع محتوى الشكل أو مع العناصر الأخرى داخل الصفحة. يتم الآن وضع تخصيصات جديدة للأشكال في CSS لتغيّر من هذا الجمود في الأشكال. ففي منتصف عام 2012 وضعت شركة Adobe هدفًا جديدًا أمامها ألا وهو تزويد مصممي الويب بطريقة جديدة تغير من الطريقة النمطية في انسياب المحتوى داخل وحول الأشكال المعقدة - وهو أمر جديد تمامًا لم نكن قادرين في تطبيقه حتى باستخدام JavaScript. على سبيل المثال، ستلاحظ في التصاميم الجديدة التي تعتمد على الأشكال المتعددة انسياب النص حول الصور الدائرية بشكل سلسل وجميل، ولكن بدون هذه الأشكال سيتوضع النص بشكل مستطيل من دون أي تأثيرات إضافية، وبالتالي نجد أن هذه الطريقة الجديدة في التعامل مع الأشكال ستأخد التصاميم إلى مستوى جديد من التطور. دعم المتصفحات إن المتصفحات التي تدعم الأشكال CSS Shapes Module 1 بالنسبة لنسخة الحاسب حتى نهاية عام 2017 كانت Chrome، Firefox، Opera و (Safari(WebKit، بينما لايقدم متصفح Internet Explorer هذا الدعم. ويختلف الأمر بالنسبة لنسخة المتصفحات الخاصة بالموبايل حيث أن متصفح Safari هو فقط من يدعم خاصية الأشكال. ومع ذلك فقد وصلت تقنية الأشكال في CSS المرحلة الأولى منها إلى أن جميع المتصفحات تتعرف على طريقة كتابة تعريف الأشكال Syntax الخاصة بها وتخصيصها وبالتالي تعتبر برمجة الأشكال مستقرة جدًا ولن يكون الوقت طويلًا حتى يتم تنفيذها بشكل كامل على جميع المتصفحات. إن المرحلة الأولى من تطوير الأشكال في CSS يركز على الخصائص التي تغير من طريقة انسياب المحتوى حول الشكل أي أنها تركز على خاصية shape-outside بالإضافة إلى الخصائص الأخرى المتعلقة بها. ومن المتوقع أن استخدام هذه الميزة الجديدة في الأشكال عند CSS ودمجها مع الميزات الأخرى المتطورة مثل الإخفاء والقص Clipping and Masking، طريقة معالجة العنصر قبل عرضه CSS Filters، و مزج وتركيب العناصر معًا Compositing and Blending سيسمح لنا ببناء الأشكال وتصميمها بشكل احترافي متطور من دون الحاجة إلى المحررات المستخدمة في التصميم كالفوتوشوب و InDesign. سيركّز بناء الأشكال في CSS مستقبلًا على طريقة التفاف المحتوى داخل الشكل نفسه أيضًا. فعلى سبيل المثال، من السهل اليوم بناء المعين باستخدام CSS حيث يتوجب علينا فقط تدوير العنصر بزاوية 24 درجة ثم تدوير المحتوى داخله وبالتالي يعود المحتوى ليتوضع أفقيًا ضمن الصفحة. ولكن المعين لن يكون هو الأب الحاوي container للمحتوى، وبالتالي سيبقى المحتوى مستطيل الشكل. ولحل هذه المشكلة يمكن استخدام الخاصية shape-inside والتي تقوم بجعل المحتوى يأخذ شكل معين داخل التصميم أيضًا. بناء شكل باستخدام CSS يمكن تطبيق شكل على أي عنصر element من خلال استخدام خاصية الأشكال shape property. حيث نمرر خاصية الشكل كتابع shape function يمرر مجموعة من المعاملات parameters التي تعرف الشكل الذي نريد تطبيقه مثل نقطة المركز ونصف القطر إذا كان الشكل دائرة أو مجموعة من النقاط على المحيط إذا كان الشكل مضلعًا. من الأشكال التي يمكن بناؤها باستخدام التوابع التالية ()circle ()ellipse ()inset ()polygon حيث يعرف كل شكل من خلال مجموعة من النقاط. فبعض التوابع تمرر هذه النقاط كمعاملات، وبعضها الآخر يمرر نقطة واحدة ومقدار الإزاحات ولكن في النهاية جميعها ترسم الأشكال من خلال مجموعة من النقاط. حيث سنقوم بتعريف هذه المتحولات الممررة عند بنائنا للأشكال في المثال القادم من خلال هذه التوابع. كما يمكن تعريف الشكل من خلال استخراجه من صوة باستخدام قناة ألفا وذلك عند تمرير الصورة لخاصية الشكل حيث سيقوم المتصفح باستخراج الشكل بالاعتماد على shape-image-threshold. يُعرف أي شكل من خلال البكسلات التي تحوي قيمة ألفا أكبر من القيمة البدائية كما أن الصورة يجب أن تكون متوافقة مع شروط CORS وبالتالي في هذه الحالة إذا لم يتم إظهار الصورة في الصفحة لأي سبب (مثل أن تكون غير موجودة أو محذوفة) عندها ستيم إظهار شكل الإطار الخاص بها. خصائص الشكل shape proprties التي تقبل أن تمرر التوابع التي ذُكرت في الأعلى كقيمة لها هي: shape-outside: تقوم هذه الخاصية بتخصيص طريقة التفاف المحتوى حول الشكل من الخارج. shape-inside: تقوم هذه الخاصية بتخصيص طريقة التفاف المحتوى داخل الشكل. كما يمكن استخدام خاصية shape-outside بالتزامن مع استخدام خاصية shape-margin من أجل إضافة هامش حول الشكل الذي نخصص طريقة انسياب المحتوى حوله وبالتالي بناء فراغ صغير بين المحتوى والشكل. وبنفس الطريقة يمكن استخدام خاصية shape-padding مع خاصية shape-inside من أجل إضافة هامش داخلي بين المحتوى داخل الشكل وحدود الشكل. باستخدام خصائص الشكل وتوابعه يمكن تعريف الشكل كعنصر element من خلال إضافة سطر واحد من تعليمات CSS. .element { shape-outside: circle(); /* content will flow around the circle defined on the element */ } أو من خلال التعليمة التالية حيث ندخل لها رابط الوصول إلى الشكل الذي ستستخرج منه الشكل المطلوب. .element { shape-outside: url(path/to/image-with-shape.png); } ولكن عند تطبيق هذا السطر من تعليمات CSS على الشكل لن يظهر الشكل المطلوب إلا إذا تحقق الشرطين التاليين: يجب أن يكون العنصر element عائمًا floated حيث أنه من الممكن مستقبلًا أن نحدد الأشكال على العناصر غير العائمة ولكن ليس الآن. يجب أن يكون العنصر لديه أبعاد واضحة لأنه سيتم استخدام الارتفاع والعرض لبناء العنصر ضمن نظام الإحداثيات. يتم تعريف الأشكال من خلال مجموعة من النقاط لأنها تملك إحداثيات ديكارتية حيث أن نظام الإحداثيات الديكارتية هو الذي يُعرف من خلاله مواقع العناصر ضمن المتصفح لذلك عند تعريف العنصر element في المثال في الأعلى يتوجب علينا إضافة الارتفاع والعرض بشكل محدد. .element { float: left; height: 10em; width: 15em; shape-outside: circle(); } مع العلم أن إضافة هذه الأبعاد لا تؤثر على طريقة استجابة الشكل نفسه. وبما أن كل شكل يتم تعريفه بواسطة مجموعة من النقاط التي يتم وضعها باستخدام زوج من الإحداثيات فإن تغيير إحداثيات نقطة ما سيؤثر بشكل مباشر على الشكل الذي تم إنشاؤه. فمثلًا يمكننا إنشاء مضلع مسدس الشكل من خلال استخدام تابع ()polygon حيث يتكون الشكل من ست نقاط ولكن عند تغيير إحداثيات إحدى النقاط الأفقية (النقطة الملونة باللون البرتقالي) عندها سيتغير الشكل الناتج إلى شكل آخر وبالتالي سيؤثر على طريقة تدفق المحتوى داخل الشكل وخارجه. المربع المرجعي للأشكال يتم تعريف وبناء أي شكل يُرسم باستخدام CSS داخل ما يسمى بالمربع المرجعي الذي يستعمل لرسم الشكل على العنصر. يمتلك أي عنصر ارتفاع وعرض بالإضافة إلى مربع هامش الذي يحدد المسافة بين العنصر وباقي العناصر في الصفحة margin-box، مربع المحتوى content-box، مربع الهامش الداخلي الذي يحدد المسافة بين المحتوى وحدود الشكل padding-box، مربع الحدود border-box. حيث تُستخدم إحدى هذه المربعات كمرجع لرسم الشكل على العنصر. افتراضيًا يُستخدم مربع الهامش margin-box كنقطة البداية الأساسية لأي عنصر وبالتالي إذا أردنا تطبيق الشكل على العنصر سيتم أولًا إزاحة الشكل إلى الأسفل ثم تمديده من أسفل زاوية الهامش إلى باقي مربع الهامش margin-box. كما يمكن استخدام قيمة مربع أخرى كمرجع بالإضافة إلى مربع الهامش ويتم ذلك من خلال تمرير اسم المربع بجانب تابع الشكل ()circle إلى خاصية الشكل المُستخدمة shape-outside. shape-outside: circle(250px at 50% 50%) padding-box; الكلمة المفتاحية padding-box هي التي خصصت بأن الشكل سيتم تطبيقه على العنصر بالنسبة إلى منطقة الهامش الداخلية للعنصر، أما تابع ()circle فعرّف الشكل الدائري المراد رسمه من خلال ذكر حجمه ومكان توضعه. تعريف الأشكال باستخدام التوابع سنبدأ بمثال عن طريقة التفاف النص حول صورة شخصية لمستخدم دائرية الشكل مثل تلك الصور المستخدمة في الصفحات التعريفية عن الأشخاص حيث ستكون التعليمات في ملف HTML لبناء الصورة وكتابة المحتوى <img src="http://api.randomuser.me/0.3.2/portraits/men/7.jpg" alt="profile image" /> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum itaque nam blanditiis eveniet enim eligendi quae adipisci?</p> <p>Assumenda blanditiis voluptas tempore porro quibusdam beatae deleniti quod asperiores sapiente dolorem error! Quo nam quasi soluta reprehenderit laudantium optio ipsam ducimus consequatur enim fuga quibusdam mollitia nesciunt modi.</p> أما ضمن ملف CSS فسنستخدم تابع ()circle من أجل تطبيق الشكل الدائري على الصورة الشخصية التي وضعناها في ملف HTML. سنستخدم من أجل تدوير الصورة الخاصية border-radius حيث لا تمتلك هذه الخاصية أي تأثير على طريقة انسياب المحتوى داخل أو حول الصورة التي نطبق عليها الشكل. وبمعنى آخر لا تمتلك هذه الخاصية التأثير على منطقة المحتوى content area المتواجدة داخل العنصر element الذي قمنا ببنائه ولا على المحتوى الخارجي حول العنصر، وإنما يكون تأثيرها فقط على شكل الحدود الخاصة بالعنصر وخلفيته إن وُجدت. أي سيبقى المحتوى داخل العنصر مستطيل الشكل والمحتوى الموجود خارج العنصر سينظر ويتعامل مع العنصر نفسه كما لوكان مستطيل الشكل. أي أننا نقوم باستخدام الخاصية border-radius من أجل جعل الصورة فقط دائرية الشكل. img { float: left; width: 150px; height: 150px; border-radius: 50%; margin-right: 15px; } تبين الصورة السابقة الشكل الذي سيظهر به المحتوى حول الصور الدائرية في المتصفحات القديمة التي التدعم الأشكال في CSS، ولتغيير هذا الشكل المربع في الانسياب حول الصورة الدائرية سنقوم بتعديل التعليمات بما يتوافق مع الشكل الذي أضفناه من خلال استخدام خصائص الشكل img { float: left; width: 150px; height: 150px; border-radius: 50%; shape-outside: circle(); shape-margin: 15px; } حيث سنرى في صفحة الويب عند استخدام هذه التعليمات شكلًا دائريًا مُطبّقًا على الصورة وسيظهر المحتوى ملتفًا حول الدائرة كما في أول صورة شاهدناها في المثال. الطريقة الأساسية في استخدام تابع الدائرة هي circle() = circle( [<shape-radius>]? [at <position>]? ) إن علامة الاستفهام ? في التعليمة السابقة تشير إلى أن هذه المعاملات الممررة اختيارية ولكن في حال عدم تمريرها سيأخذ التابع القيمة الافتراضية الموجودة في المتصفح وهي رسم الشكل ابتدءًا من مركز العنصر الذي نطبق عليه الشكل. يتم تحديد طول نصف قطر الدائرة بأحد وحدات الطول (البكسل px، النقطة pt…) ويقوم المتصفح برسمه ابتداءً من نقطة المركز وصولًا إلى إحدى أضلاع المستطيل المرجع ويحدد ذلك الخاصية خاصية closest-side: وهي الخاصية الافتراضية وتعني رسم نصف القطر وصولًا إلى أقرب ضلع من أضلاع المستطيل. خاصية furthest-side: وتعني أن المتصفح سيرسم نصف القطر وصولًا إلى أبعد ضلع من أضلاع المستطيل يمكن تحديد هذه الخاصية وتمريرها كمعامل لتابع رسم الدائرة عند خاصية shape-outside shape-outside: circle(farthest-side at 25% 25%); /* defines a circle whose radius is half the length of the longest side, positioned at the point of coordinates 25% 25% on the element’s coordinate system*/ shape-inside: circle(250px at 500px 300px); /* defines a circle whose center is positioned at 500px horizontally and 300px vertically, with a radius of 250px */ يعمل تابع رسم الإهليلج (القطع الناقص) ()ellipse فهو يعمل بنفس الطريقة التي يعمل فيها تابع ()circle وبنفس القيم ماعدا أنه بدلًا من تمرير تابع واحد لنصف القطر يجب تمرير اثنين أحدهما من أجل طول نصف القطر على محور الإحداثيات X والآخر لنصف القطر على محور الإحداثيات Y ellipse() = ellipse( [<shape-radius>{2}]? [at <position>]? ) في حيث أن تابع ()inset يُستخدم لرسم شكل مستطيل مدور الزوايا ويمكن أن نجعل المحتوى ينساب حول هذه الزوايا بشكل دائري أيضًا. ونمرر لتابع ()inset: أربع قيم إزاحة تحدد قيمة إزاحة الحواف بالنسبة لصندوق المرجع نحو داخل العنصر. معامل اختياري وهو قيمة تدوير الزوايا round حيث يتم تحديد القيمة من خلال border-radius بنفس طريقة استخدامها في تدوير الدائرة التي شرحناها سابقًا، ولكن هنا يجب تمرير أربع قيم. inset() = inset( offset{1,4} [round <border-radius>]? ) من خلال التعليمات التالية سنقوم برسم مستطيل دائري الزاويا على عنصر عائم floated element .element { float: left; width: 250px; height: 150px; shape-outside: inset(0px round 100px) border-box; } تابع الأشكال الأخير الذي سنتحدث عنه هو ()polygon الذي يعرف مجموعة معقدة من الأشكال الهندسية من خلال تحديد عدد من النقاط المعرفة بإحداثياتها الديكارتية (point(x,y والتي من خلالها يتحدد موقع النقطة ديكارتيًا على المتصفح. في المثال التالي نشاهد صورة عائمة في يمين الصورة وتغطي ارتفاع كامل مساحة العرض المتاحة لها، ونريد أن نظهر النص الذي على يسارها بشكل انسيابي حول الساعة الرملية الموجودة داخل الصورة ولذلك سنستخدم تابع ()polygon من أجل تعريف هذا الشكل غير المنتظم على الصورة. تعليمات CSS التي ستقوم بهذه العملية هي img.right { float: right; height: 100vh; width: calc(100vh + 100vh/4); shape-outside: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%); } يمكن تعيين إحداثيات النقط التي تعرف الشكل من خلال وحدات الطول أو من خلال النسب المئوية التي استخدمتها. ستُنتج التعليمات السابقة الشكل الذي شاهدناه في الأعلى حيث أنها لا تؤثر على باقي أجزاء الصورة الموجودة خارج الشكل المرسوم كما نلاحظ، لأن تطبيق شكل العنصر فقط يؤثر على منطقة تدفق المحتوى من دون أن يغيّر أي شيء في الخلفيات والحدود. ومن أجل إظهار شكل المضلع الذي رسمناه فإننا بحاجة إلى قص أجزاء من الصورة خارج الشكل وذلك من خلال استخدام خاصية clip-path الموجودة في نموذج الإخفاء CSS Masking Module. تقوم خاصية clip-path على أخذ نفس شكل التابع المستخدم والقيم الممررة له. وبالتالي إذا استخدامنا نفس الشكل المضلع الذي مررناه للخاصية shape-outside فإن هذه الخاصية ستعمل على قص كل أجزاء الصورة خارج الشكل المحدد img.right { float: right; height: 100vh; width: calc(100vh + 100vh/4); shape-outside: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%); /* clip the image to the defined shape */ clip-path: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%); } وستكون النتيجة النهائية لهذه التعليمات كما في صورة في الوقت الحالي يتم دعم خاصية clip-path من خلال إضافة بادئة إليها أولًا، مثلًا ستعمل هذه الخاصية مع Chrome إذا أضفنا لها -webkit-. إن خاصية clip-path هي أفضل إضافة مع خصائص الأشكال الأخرى لأنها تساعد في إظهار الأشكال المُنشأة من خلال قص أي جز من العناصر خارج الشكل. تابع()polygon يأخذ أيضًا خيارًا آخر هو إما nonzero أو evenodd والتي تحدد كيفية التعامل مع المناطق داخل الشكل المضلع التي تتقاطع مع نفسها ولمعرفة المزيد عن هذه الخصائص يمكن الإطلاع على SVG fill-rule تعريف شكل باستخدام صورة لتعريف شكل باستخدام صورة نحتاج إلى صورة من نمط ألفا والتي يمكن للمتصفح أن يحللها. يُعرّف الشكل بأنه مجموعة من البكسلات التي تمتلك قيمة ألفا أكبر من القيمة الحدّية والتي هي افتراضيًا القيمة 0 (أي شفافة تمامًا) أو يمكن تحديد قيمتها صراحة من خلال الخاصية shape-image-threshold.وبالتالي سيتم استخدام أي بكسل ليس شفافًا كجزء من الشكل المُعرّف من قبل الصورة. في مراحل قادمة من تعريف أشكال CSS قد يتم استخدام بيانات الإضاءة من الصورة بدلًا من استخدام بيانات ألفا. وفي حال حدوث هذا فإن خاصية shape-imgae-threshold سيتم توسيعها لتستخدم مع الإضاءة أو ألفا. الآن سنقوم باستخدام الصورة التالية من أجل تعريف شكل على عنصر ومن ثم تحديد طريقة التفاف النص حول الشكل: باستخدام الخاصية shape-outside قيمة()url التي تشير إلى الصورة نستطيع جعل المحتوى ينساب حول العنصر الذي يحمل شكل الورقة. .leaf-shaped-element { float: left; width: 400px; height: 400px; shape-outside: url(leaf.png); shape-margin: 15px; shape-image-threshold: 0.5; background: #009966 url(path/to/background-image.jpg); mask-image: url(leaf.png); } وبالطبع في حال أردنا تطبيق الصورة كخلفية في العنصر فإنه يجب قص الصورة الموجودة خارج الشكل من خلال الخاصية mask-image حيث أنه لايمكن استخدام خاصية clip-path مع الصور صاحبة القيمة ألفا، والنتيجة ستكون بالشكل التالي وفي حال قمنا ببناء أشكال معقدة ونريد تعريفه باستخدام صورة. فإنه يمكن استخدام الصور ذات قناة ألفا من خلال الفوتوشوب بدلًا من تعريفها يدويًا. كما يمكن استخدام الصورة بدلًا من تابع الشكل عندما يكون لديك عدة مناطق عائمة أو مناطق مستبعدة داخل العنصر نفسه ولكنه لايمكن تعريف عدة أشكال في العنصر نفسه ولكن إذا كانت الصورة تحوي على عدة مناطق يقوم المتصفح باستخراج هذه المناطق من الصورة واستخدامهم. تفاعل الأشكال في CSS مع التصميم المُتجاوب هل تستطيع الأشكال المبنية باستخدام CSS تتناسب مع التصميم المتجاوب؟ التخصيص الحالي لخاصية shape-outside تستطيع العمل مع التصميم المتجاوب وذلك لأنه يسمح بتحديد أبعاد العنصر من خلال النسب المئوية أو أحد وحدات الطول، ويمكن تحديد نقاط الشكل الممررة كمعاملات لتابع الشكل. وهذا يعني أن خاصية العنصر shape-outside ستكون متجاوبة responsive بشكل كامل ولكن خاصية shape-inside ليست متجاوبة responsive إلى الآن ولكن سيتم إدخالها في المرحلة الثانية حتى يتم حل بعض الحدود. الأدوات المستخدمة لبناء أشكال CSS إن بناء الأشكال المعقدة بالاعتماد على تابع Shape يعد مهمة شاقة خصوصًا عند بناء العديد من الأشكال المضلعة المعقدة من خلال تمرير الإحداثيات الديكارتية لعدة نقاط من الشكل باستخدام التابع ()polygon ولكن لحسن الحظ فإن Adobe وفرّت العديد من الأدوات التفاعلية التي تقوم بهذا العمل بشكل أسهل. هنا يوجد عدة أدوات تسمح لنا ببناء الأشكال المضلعة من خلال الرسم ثم تتولى الأداة توليد تابع الأشكال الخاص بها. ولكن يوجد بعض المحدوديات في هذه البرامج إذا أردنا رسم الشكل بالاعتماد على صورة محددة لأنه لايوجد طريقة لإدخال الصورة إلى الأدوات ومن ثم إنشاء الشكل من خلالها. الأداة الأكثر تطورًا في هذا المجال لرسم الأشكال التفاعلية المتطورة بناها فريق تطوير الويب التابع لمنصة Adobe وتم وضعها كإضافة لمحرر brackets المجاني الخاص بالشركة. مستقبل الحالات المبعدة من المعالجة في CSS لبناء أي شكل في CSS يجب أن يكون خاضعًا لعدد من المواصفات المحددة، فمثلًا لا يمكن تعريف الخاصيتين shape-inside و shape-outside إلا لأشكال مخصصة ولكن الحالات المقصاة هذه سيتم تعريف خصائص تسمح بالتفاف المحتوى حول العناصر مهما كان شكلها حتى لو لم تكن عائمة في المرحلة التالية من تطوير الأشكال في CSS وسيصبح بالإمكان التفاف النص على كامل الشكل من اتجاهات مختلفة كما في المثال الموضح بالصورة ترجمة –وبتصرّف- للمقال CSS Shapes 101 لصاحبته Sara soueidan
-
كُنّا في درس سابق قد تحدثنا عن كيفية تخطيط صفحات الويب باستعمال CSS2 وكيف أنّ ذلك لم يكن بالأمر السهل، لذلك في هذا الدرس سوف نقوم بنفس التخطيط ولكن باستعمال تقنيات CSS3 الجديدة. تٌقدّم لنا CSS3 مجموعة من التقنيات والتحسينات لتساعدنا على تخطيط صفحات الويب بشكل أفضل وأسهل ودون الحاجة إلى الكثير من الأكواد كما كان الحال في CSS2. كما أنها مُصممة لتدعم السلوكات المتغيرة/الديناميكية وبالتالي يمكننا القول بأنها " لغة قابلة للبرمجة". دعونا إذًا نرى بعض الخصائص والتقنيات الجديدة التي توفرها هذه اللغة ونحاول استخدامها لدعم حالة الاستخدام التي كنّا قد بدأنا بها في الدرس السابق. دالة ()calc الخاصة بلغة CSS3تُستخدم دالة ()calc الجديدة لحساب القيم بشكل ديناميكي (ضع في الحسبان أن دعم هذه الدالة يختلف من متصفح لآخر). وفي داخل هذه الدالة يمكنك كتابة أي معادلة/تعبير (expression) باستخدام المعاملات الحسابية المعروفة (+، -، *، /). سوف يساعدنا استخدام هذه الدالة على التخلص من الكثير من الأكواد التي كان لا بد منها في CSS2، وفي حالتنا هذه فإنها سوف تساعدنا في تمدد العناصر بشكل أفضل (سوف يصبح استخدام تقنية CSS Expansion التي ذكرناها سابقًا أكثر سهولة). أنظر للكود الموجود في الأسفل: #nav, #subnan { position: fixed; height: calc(100% - 10em); /* replaces */ z-index: 20; }لاحظ أننا استخدمنا الدالة ()calc في الخاصية height وهذا سوف يساعدنا بالحصول على نفس النتيجة التي حصلنا عليها باستخدام CSS2 عندما استخدمنا الخاصيتين top: 6em و bottom: 4em، وبهذا يمكن للأمور أن تصبح أكثر مرونة وسوف نحتاج إلى خاصية واحدة (height مع ()calc) بدل اثنتين (top وbottom). استخدام CSS3 Flexbox في تخطيط الصفحاتتُعتبر Flexbox من الخصائص والتقنيات الجديدة التي ظهرت في CSS3 وهي تجعل من تخطيط الصفحات وترتيب عناصرها أمرًا سهلًا ومتشابهًا في مختلف أحجام الشاشات والأجهزة، وبالتالي فهي مفيدة جدًا عند القيام بتصميم مواقع متجاوبة. وهذه بعض الخصائص والميزات التي تتمع بها Flexbox: تمكننا من موضعة العناصر الأبناء (child elements) بشكل أسهل ويصبح تخطيط الصفحات المعقدة أبسط وأسهل ودون الحاجة إلى الكثير من الأكواد فيصبح لدينا كود أنظف وقابل للقراءة بشكل أفضل.يمكن وضع العناصر الأبناء بأي إتجاه نريده وتصبح أبعاد تلك العناصر مرنة أكثر بحيث يمكنها التجاوب مع مساحة العرض.تستطيع العناصر الأبناء أن تتمدد وتتقلص تلقائيًا لتشغل المساحة الفارغة.كما أنّ Flexbox يقدم مجموعة خاصة به من المفاهيم والمصطلحات، ونذكر بعض منها: Flex container: العنصر الذي يحتوي على الخاصية display بالقيمة flex أو inline-flex بحيث يصبح هذا العنصر هو العنصر الحاوي (الأب) للعناصر التي نريد التعامل معها.Flex item: هو أي عنصر موجود في الـFlex container. (ملاحظة: أي نص موجود بشكل مباشر داخل الـFlex container سيتم احتواؤه داخل anonymous flex item).Axes: أي flexbox يجب أن يحتوي على الخاصية flex-direction بحيث تُحدد هذه الخاصية المحور الرئيسي (main axis) الذي سوف تتموضع حوله الـflex items. ويوجد أيضًا المحور العرضي (cross axis) ويكون هذا المحور عموديًا على المحور الرئيسي.Lines: يمكن للـflex items أن تصطف/تتموضع في خط واحد أو خطوط متعددة وذلك ما تحدده الخاصية flex-wrap.Dimensions: يحتوي flexbox على main size و cross size كبديل عن height وwidth بحيث تُحدد هاتين القيمتين حجم المحور الرئيسي (main axis) والعرضي (cross axis) على التوالي.بعد هذه المقدمة القصيرة عن flexbox يمكننا الآن استخدامها في تخطيط الصفحات. <body class="layout-flexbox"> <header id="header"></header> <div class="content-area"> <nav id="nav"></nav> <aside id="subnav"></aside> <main id="main"></main> </div> <footer id="footer"></footer> </body>نريد في حالة الاستخدام التي نعمل عليها أن تكون العناصر الرئيسية (header ،content ،footer) مصفوفة بشكل عمودي، وبالتالي سوف نستخدم القيمة column في الخاصية flex-direction كما يلي: .layout-flexbox { display: flex; flex-direction: column; }ومع أنّ العناصر الرئيسية يجب أن تكون مصفوفة بشكل عمودي إلّا أنّ العناصر في منطقة المحتوى (nav ،subnav ،main) نريدها مصفوفة بشكل أفقي. وبما أنّ كل flex container يمكن أن يحتوي على خاصية flex-direction واحدة فقط فإننا سنقوم بتعريف العديد من flex containers داخل بعضها البعض حتى يمكننا التحكم في تخطيط الصفحة كما نشاء (أي حتى يصبح بإمكاننا أن نجعل العناصر تصطف كما نريد وألّا نصبح مقيدين باتجاه واحد فقط). ولهذا السبب قمنا بإضافة حاوي (container) آخر (<div class="content-area">) ليحتوي على عناصر nav ،#subnav# و main#. وبهذا يمكن للعناصر الرئيسية أن تصطف بشكل عمودي بينما تصطف عناصر منطقة المحتوى بشكل أفقي. نريد الآن أن نقوم بموضعة الـflex items لذلك سوف نستخدم الخاصية flex وهي اختصار(shorthand) للخصائص flex-grow ،flex-shrink وflex-basis. وهذه الخصائص تُحدد كيف تقوم الـflex items بتوزيع المساحة الفارغة المتبقية بينها، وهذا تعريف بسيط بهذه الخصائص: flex-grow: تُحدد كم يمكن للعنصر (flex item) أن ينمو/يتمدد نسبة للعناصر الأخرى في نفس الحاوي.flex-shrink: تُحدد كم يمكن للعنصر (flex item) أن يتقلص نسبة للعناصر الأخرى في نفس الحاوي.flex-basis: يُحدد الحجم الافتراضي للعنصر (أي حجمه قبل أن ينمو أو يتقلص). عندما نقوم بإعطاء الخاصيتين flex-grow وflex-shrink القيمة "صفر" فإننا نقوم بمنع العنصر من أن يتقلص أو ينمو حتى لو كان هناك مساحة فارغة (أي أنّ حجم العنصر يبقى ثابتًا). وهذا ما سوف نقوم به للترويسة (header) والتذييل (footer) لأننا نريد أن يبقى حجمهما ثابتًا: #header { flex: 0 0 5em; } #footer { flex: 0 0 3em; }وإذا أردنا لعنصر أن يستغل أي مساحة ثابتة فإننا نعطي الخاصيتين flex-grow وflex-shrink القيمة "1" ونعطي الخاصية flex-basis القيمة auto. وهذا ما نريده بالنسبة لمنطقة المحتوى (نريدها أن تستغل أي مساحة فارغة). وكما ذكرنا سابقًا فإننا نريد للعناصر الموجودة داخل <div class="content-area"> أن تصطف بشكل أفقي، لذلك سوف نعطيها الخاصية display: flex حتى يصبح هذا العنصر عبارة عن flex container وسوف نعطيها أيضًا الخاصية flex-direction: row حتى نجعل العناصر الموجودة في داخله (nav ،#subnav# و main#) تصطف بشكل أفقي، وبالتالي نحصل على تنسيقات CSS التالية: .content-area { display: flex; flex-direction: row; flex: 1 1 auto; margin: 1em 0; min-height: 0; }في منطقة المحتوى نريد أن يكون حجم كلا العنصرين nav# وsubnav# ثابت وبالتالي سوف نعطيها الخاصية flex بقيم مناسبة: #nav { flex: 0 0 5em; margin-right: 1em; overflow-y: auto; } #subnav { flex: 0 0 13em; overflow-y: auto; margin-right: 1em; }لاحظ أنني استعملت الخاصية overflow-y: auto وذلك حتى نتعامل مع المحتوى إذا ما تجاوز ارتفاع الحاوي. متصفح Firefox هو من يحتاج لهذه الخاصية. سوف يأخذ العنصر main# المساحة الفارغة المتبقية: #main { flex: 1 1 auto; overflow-y: auto; }كل شيء يبدو جيدًا إلى الآن، لذلك دعونا نقوم بإضافة السلوك المتغير/الديناميكي ونرى ما يحصل. سوف تكون أكواد الجافاسكربت مشابهة لما استخدمناه سابقًا باستثناء أن اسم الـclass للعنصر الحاوي سيكون layout-flexbox بدلًا من layout-classic: $('.layout-flexbox #nav’).on('click', 'li.nav-toggle', function() { $('#nav').toggleClass('expanded'); });سوف نضيف "class expanded" إلى تنسيقات CSS كما يلي: #nav { flex: 0 0 5em; /* collapsed size */ margin-right: 1em; overflow-y: auto; &.expanded { flex: 0 0 10em; /* expanded size */ } }لاحظ أننا هذه المرة لم نحتج إلى أن ندع العناصر الأخرى تعلم بشأن تغير العرض وذلك لأنّ flexbox تعالج الأمر دون تدخل منا. الشيء الوحيد المتبقي هو إخفاء القائمة الفرعية، ولكن احزر ماذا؟ لن نحتاج لكتابة أي أكواد إضافية لأن flexbox سيعلم بشأن المساحة الفارغة وسوف يتكفل بجعل كل شيء يعمل كما هو مطلوب. يوفر لنا flexbox أيضًا مجموعة من الطرق التي تمكننا من توسيط العناصر في الاتجاهين العمودي والأفقي. يمكننا الآن معرفة أهمية وجود مثل هذه التقنية في لغة CSS وكيف أنّها تساعد على جعل الكود أفضل وله القابلية للتطور والتوسع. ولكن على الناحية الأخرى فإنّ هذه التقنيات تحتاج إلى وقت أكثر لإتقانها مقارنة بخصائص CSS الأخرى. تخطيط الصفحات باستخدام CSS3 Gridإذا كنت تعتقد أن flexbox شيء جديد فأنت حتمًا لم تسمع عن CSS3 Grid، فهي ما زالت في مرحلة مبكرة (مرحلة draft) ودعم المتصفحات لها شبه معدوم (يمكنك تفعيلها في متصفح Google Chrome عن طريق الدخول إلى chrome://flags واختيار "experimental Web Platform features"). وفائدتها هي أنها تعمل في طبقة العرض (presentation layer) وبالتالي لن نحتاج إلى معرفة كيفية ظهور العناصر في التوصيف (markup) الخاص بملفات HTML (أي أنّ كل شيء سيتم باستخدام CSS بعض النظر عن ترتيب العناصر في HTML). الفكرة العامة هي أن يكون هناك شبكة تخطيط (grid) مرنة ومُعرّفة بشكل مسبق يمكن أن نستخدمها لموضعة العناصر بداخلها. وكما هو الحال في flexbox فإنها تعمل على مفهوم المساحات الفارغة وتسمح لنا بتعريف إتجاهين (عمودي وأفقي) في نفس العنصر مما يؤدي إلى تقليل حجم الكود وزيادة مرونته. يُقدّم لنا Grid Layout نوعين من الـgrids وهما explicit وimplicit، ولجعل الأمور بسيطة سوف نركز على explicit فقط. وكما هو الحال مع flexbox فإنّ Grid يقدم مجموعة خاصة به من المفاهيم والمصطلحات، ونذكر بعض منها: Grid container: هو أي عنصر يملك الخاصية display بالقيمة "grid" أو "inline-grid" بحيث تتموضع العناصر داخله ويتم محاذاتها بناءً على grid مُعرّف مسبقًا (explicit mode). والـgrid هو عبارة عن مجموعة من الخطوط العمودية والأفقية المتقاطعة والتي تفصل الـGrid container إلى مجموعة من الخلايا (cells). وهناك مجموعتين من الخطوط؛ الأولى لتعريف الأعمدة (columns) والثانية تكون عمودية على هذه الأعمدة لتعريف الصفوف (rows).Grid track: هي المسافة بين خطّين متجاورين، وكل Grid track يتم إعطاؤه دالة تحجيم (sizing function) للتحكم بكيفية نمو كل عمود أو صف وبالتالي التحكم في البعد بين الخطوط المحيطة بكل خط.Grid cell: هي المسافة بين صفّين متجاورين وعمودين متجاورين من خطوط الـgrid، وهو أصغر وحدة من الـgrid يمكن الرجوع والاستناد إليها عندما نقوم بموضعة عناصر الـgrid.Flexible length: هو بُعد يتم تحديده بوحدة fr وهو يُمثّل جزء من المساحة الفارغة في الـGrid container. إليك عناصر HTML التي سوف نستخدمها: <body class="layout-grid"> <header id="header"></header> <nav id="nav"></nav> <aside id="subnav"></aside> <main id="main"></main> <footer id="footer"></footer> </body>لاحظ بأننا في تخطيط الصفحة هذا لن نحتاج إلى عنصر إضافي يعمل كحاوٍ لمنطقة المحتوى كما كان الحال مع flexbox، وذلك لأنّ هذا النوع من تخطيط الصفحات (Grid layout) يسمح لنا بتعريف مساحة كل عنصر في كلا الإتجاهين وبنفس الـGrid container. لنبدأ الآن بإضافة تنسيقات CSS: .layout-grid { display: grid; grid-template-columns: auto 0 auto 1em 1fr; grid-template-rows: 5em 1em 1fr 1em 3em; }قمنا باستخدام الخاصية display: grid على الحاوي (Grid container)، وكذلك استخدمنا الخاصيتين grid-template-columns وgrid-template-rows وهما تمثلان المساحة بين الـGrid tracks. بمعنى آخر، فإنّ هاتين القيمتين لا تمثلان مكان تواجد خطوط الـgrid وإنّما تمثلان مقدار المساحة بين الـGrid tracks. ضع في الحسبان أنّ وحدات القياس يمكن أن تكون أي واحدة من التالية: وحدة طول (length).نسبة مئوية معينة من حجم الحاوي (Grid container).مساحة من المحتوى الذي يحتله العمود أو الصف.جزء من المساحة الفارغة في الـgrid.فعلى سبيل المثال، في الخاصية grid-template-column: auto 0 auto 1em 1fr سيكون لدينا التالي: track واحد لتعريف عمودين بعرض auto (مساحة القائمة الرئيسية nav#).gutter واحد بقيمة "صفر" (الـmargin الخاص بالعنصر subnav# موجود في مستوى العنصر، ويمكن أن يكون موجودًا أو لا وبهذه الطريقة نضمن أن لا يكون هناك gutter مزدوج).track واحد لتعريف عمودين بعرض auto (مساحة القائمة الفرعية subnav#).gutter واحد بقيمة 1em.track واحد بقيمة 1fr للعنصر main# (سوف يأخذ المساحة المتبقية).لاحظ أننا استخدمنا القيمة auto في الـtrack، وهذا يسمح لنا بالحصول على أعمدة ديناميكية بحيث يتم تعريف مكان وحجم خطوط الـgrid بناءً على المحتوى الخاص بها. (سوف نحتاج أيضًا إلى تعريف حجم العنصرين nav# وsubnav# وهذا ما سنفعله بعد قليل). وبطريقة مشابهة، سوف تملك الصفوف الخاصية grid-template-row: 5em 1em 1fr 1em 3em مما يجعل العنصرين header# و footer# ثابتين ويؤدي أيضًا إلى أنّ العناصر الموجودة بين هذين العنصرين سوف تستخدم المساحة الفارغة المتبقية في حين تكون قيمة الـgutters بقيمة 1em. لنرى الآن كيف سنقوم بموضعة العناصر داخل الـgrid الذي قمنا بتعريفه: #header { grid-column: 1 / 6; grid-row: 1 / 2; } #footer { grid-column: 1 / 6; grid-row: 5 / 6; } #main { grid-column: 5 / 6; grid-row: 3 / 4; overflow-y: auto; }إنّ تنسيقات CSS الخاصة بالعنصر header# تُخبرنا بأننا نريد أن تكون الترويسة موجودة بين الخطين 1 و6 (أي العرض كامل) بالنسبة للأعمدة وبين الخطين 1 و2 بالنسبة للصفوف. ونفس الشيء بالنسبة للعنصر footer# فنريده أن يكون موجودًا بين الخطين 1 و6 (أي العرض كامل) بالنسبة للأعمدة وبين الخطين 5 و6 بالنسبة للصفوف. أمّا بالنسبة لمنطقة المحتوى فقد تمّ إعطاؤها الخصائص المناسبة حتى تشغل المساحة التي يفترض بها أن تشغلها. لاحظ أنّ الخاصية grid-column هي اختصار (shorthand) للخاصيتين grid-column-start وgrid-column-end و أنّ الخاصية grid-row هي اختصار للخاصيتين grid-row-start وgrid-row-end. لنعد الآن إلى العنصرين nav# وsubnav#. بما أننا قمنا مسبقًا بوضع هذين العنصرين داخل الـtrack بقيم auto فسوف نحتاج إلى تحديد مساحتهما (نفس الشيء سيكون بالنسبة لـ"expanded" فسوف نقوم فقط بتغيير عرضها وسوف يتكفل Grid بالباقي). #nav { width: 5em; grid-column: 1 / 2; grid-row: 3 / 4; &.expanded { width: 10em; } } #subnav { grid-column: 3 / 4; grid-row: 3 / 4; width: 13em; margin-left: 1em; }يمكننا الآن أن نقوم بتغيير وضع القائمة الرئيسية nav# وإخفاء أو إظهار القائمة الفرعية subnav# وكل شيء سيعمل بشكل جيد وملائم. كما أنّ Grid Layout تسمح لنا باستعمال أسماء مستعارة لتسمية الخطوط حتى نستطيع أن نُغير في الـgrid كما نريد دون أن يؤدي ذلك إلى خلل في الأكواد لأنّها ستكون مربوطة باسم معين وليس بأحد خطوط الـgrid. خاتمةحتى باستخدام تقنيات CSS القديمة فإنّ هناك الكثير مما يستطيع مطورو الويب فعله واستغلاله. ومع ذلك فقد يكون ذلك مهمة ليست سهلة وتحتاج إلى الكثير من الأكواد والتي قد تكون مكررة في كثير من الأحيان. ولكن كما شاهدنا فإنّ CSS3 بدأت تقدم طرق وتقنيات أفضل لتخطيط صفحات الويب والتي بدورها تُسهّل العمل على مطوري الويب. لذلك أعتقد أنه يجب على أي مطور ويب أن يتقن ويتعلم هذه التقنيات حتى يُحسّن من تجربة المستخدم وحتى يقوم بكتابة كود أنظف وأفضل. وهذه المقالة قدمت جزءًا صغيرًا فقط مما يمكن فعله باستخدام تقنيات CSS3 وهناك الكثير مما يجب عليك تعلمه. ترجمة -وبتصرّف- للمقال CSS Layout Tutorial: From Classic Approaches to the Latest Techniques لصاحبه Laureano Martin Arcanio.
-
قمنا مؤخرًا بتحديث تصميم صفحة "?Why Should You Attend" التي كانت ماتزال تحتفظ بالتصميم القديم للموقع وقد احتجنا إلى أن نوائمها مع باقي الموقع. وعندما بدأنا العمل عليها قررنا أن نحسّن تصميم هذه الصفحة بأحدث التقنيات المستخدمة في التصميم حاليًا ألا وهي: الأشكال العائمة غير المستطيلة non-rectangular float shapes وميزة الكشف المباشر من قبل المتصفح عن قدرته على تطبيق تعليمات css وهذا مايعرف بـ feature queries. ولكن ليكن واضحًا بأننا لم نقم ببناء هذا المثال المتطور من دون أن يزودنا Mike Pick صاحب Monkey Do بالتصميم حيث أدركنا بأن رؤيته تتوافق بشكل جميل مع ميزات CSS الحديثة وقد كنا سعداء جدًا بالنتائج التي حصلنا عليها من خلال هذه التقنيات الحديثة لذلك أردنا مشاركتها معكم. تصميم الفقاعات styling bubbles هنا يوجد بعض المقتطفات من تصميمنا الأولي (التصميم النهائي لم يتم إنشاؤه كبطاقة صور لذلك لايمكنني عرض الشكل النهائي ولكن هذا الشكل قريب جدًا). مايهمني في هذا المثال هو طريقة استخدام الصور الدائرية، التي كنا نشير إليها باسم "الكُوّة portholes" ولكن بعد التفكير أفضل تسميتها بـ "الفقاعات". عندما بدأت التحضير لتنفيذها من خلال التعليمات البرمجية عدت بالتفكير إلى ما قالته جين سيمون عن الاتجاه الفني الحقيقي في الويب. وبالتحديد كنت أفكر حول الأشكال في CSS وكيف يمكن أن أكون قادرًا على استخدامهم بحيث تكون أسطر الكتابة مرتبة حول محيط الدائرة بشكل انسيابي. تقوم طريقة بناء هذا التنسيق على دمج مجموعة من التقنيات المستخدمة في التعامل مع الأشكال في CSS وهي Ragged Float وفكرتها تقسيم الصورة المنحنية إلى مجموعة من الشرائط مستطيلة الشكل ثم عرضها بالتسلسل لتظهر الشكل النهائي المنحني. و Sliced Sandbags التي تقوم على مبدأ بسيط هو بناء مجموعة من div التي تتوضع فوق الصورة الأساسية وبالتالي هذه الأقسام لاتكون الصورة الحقيقية التي سيتوضع النص حولها وإنما عبارة عن مجموعة من تعليمات php. الآن نمتلك الأشكال العائمة float shapes حيث يمكننا أن نعرّف دائرة أو مضلع ثم نقوم بتوصيف كيفية انسياب النص حول الشكل. أعلم ستقول بأنك لم تسمع أبدًا عن دعم هذه الأشكال في المتصفحات، بالتأكيد هذا صحيح حيث أن المتصفحات التي تدعمها إلى الآن هي WebKit/Blink family—Chrome, Safari, and Opera ولكن ذلك لايشكل عائقًا أمام هذه التقنية لأن المتصفحات التي لاتدعم الأشكال العائمة float shapes ستنفذ الطريقة القديمة boxy float في التعامل مع هذه الأشكال وذلك من خلال عرضها كألبوم صور. من أجل إضافة فقاعة سيكون الشكل الأساسي لتعليمات CSS هو: img.bubble.left { float: left; margin: 0 40px 0 0 ; shape-outside: circle(150px at 130px 130px); } img.bubble.right { float: right; margin: 0 0 0 40px; shape-outside: circle(150px at 170px 130px); } وبالمناسبة هذه الصور الفقاعة هي عبارة عن صور مربعة أبعادها 260px سوف يتم عرضها على سطح المكتب بهذا الحجم ولكن عند تصغير العرض إلى مساحات أصغر سيتم تحجيمها بنسبة 30% لتتناسب مع العرض الجديد. طريقة توضع الشكل لنفهم طريقة إعداد شكل الفقاعة النهائي سنقوم بحساب عدد بكسلات توضع الصورة، أولًا أبعاد الصورة الفقاعة هو 260×260 بكسل ونقوم بإضافة 40 بكسل عند الهامش الأيمن للصورة وبالتالي يتشكل لدينا مربع يحوي الصورة وأبعاده هي 300 بكسل بالعرض و 260 بكسل بالطول وتشغل الصورة الأساسية القسم اليساري من هذا المربع. إذًا وعند القيام بحساب بسيط نجد مركز الدائرة هو عند النقطة 130px 130px ونصف قطر الصورة الدائرية الفقاعة هو 130 بكسل ونمدد المحيط الخارجي للفقاعة 20 بكسل فيصبح نصف قطر الدائرة النهائي هو 150 بكسل. وبنفس الطريقة نبني الفقاعات الموجودة على الجانب الأيمن، حيث تنزاح نقطة المركز إلى 170px 130px لأننا أضفنا 40 بكسل كهامش أيسر للصورة، وستشرح الصورة كيفية توضع مركز كل دائرة من أجل كل صورة سنلاحظ مايلي: الصندوق الأزرق الفاتح يُظهِر العنصر نفسه المعرف بالصف img. المربع البرتقالي الفاتح هو منطقة الهامش الأساسية وعرضها 40 بكسل. الدائرة البنفسجية والتي تمّ تعريفها في تعليمات css بالمعرف shape-outside. بالإمكان ملاحظة كيفية انسياب النص إلى المنطقة البرتقالية حيث يصل إلى أعلى الدائرة البنفسجية وهذا هو تأثير خاصية shape-outside. المناطق خارج هامش الشكل يكون طريقة عرض النص فيها عادي. نلاحظ أن الدائرة البنفسجية تمتد خارج منطقة الهامش وذلك لأنه باستخدام خاصية shape-outside يتم قص الدائرة بحسب الأبعاد المعطاة بغض النظر عن مربع الهامش، لذلك فإنه إذا قمنا بزيادة نصف قطر الدائرة مثلًا 400 بكسل فهذا يعني أن الصورة ستغطي نصف الصفحة مع أن التصميم الأساسي للنص سيبقى حول حواف هامش الصورة العائمة كما لو أنه لايوجد أي شكل على الإطلاق. استجابة الأشكال Being Responsive حتى الآن طريقة التصميم جيدة فالنص ينساب حول الشكل العائم بطريقة سلسلة في متصفحات chrome /safari / opera ويتعامل مع الأشكال كما لو أنها مربع شكل عادي في Firefox /Edge وستبقى هذه طريقة تعامل المتصفحات مع الأشكال جيدة طالما أنه لم يتم تصغيير نافذة المتصفح وتتسبب في التفاف النص بين الفقاعات ولكن بالطبع يمكن حدوث ذلك في هذه الحالة بالنسبة للصور العائمة على اليمين لن يكون الوضع سيئًا على عكس الصور اليسارية التي لن يكون الأمر جميلًا بالنسبة لها. ففي بعض الحالات سيكون الالتفاف مقبولًا كما شاهدنا في الصورة السابقة وذلك في حالة كون النص عبارة عن عدة أسطر، أما في حالة كان النص فقط كلمة أو كلمتين وعند حدوث الالتفاف لهما سيكون شكلهما غير مقبول قليلًا ولذلك من الأفضل تغيير طريقة إعداد الهوامش في النصوص بحيث لايتم الالتفاف حول الفقاعات المرافقة للنص. على سبيل المثال: .complex-content div:nth-child(even):not(:last-child) p { margin-right: 20%; } .complex-content div:nth-child(odd):not(:last-child) p { margin-left: 20%; } أي أنه من كل الكتل div الأبناء زوجية الأرقام (وليست الابن الأخير) نضيف 20% كهامش على المحتوى ونقوم بنفس الأمر من أجل الكتل الأبناء أصحاب الأرقام الفردية. بإضافة هذه التعليمات الجديدة سيظهر شكل النصوص عند تصغيير نافذة المتصفح بشكل جيد في Chrome حيث سيتم التفاف النص على طول الفقاعة وسيتم إدخال النصوص إلى داخل هوامش الصورة بقيم معقولة ولكن في متصفح firefox الذي لايزال يمتلك النظام القديم boxy float في التعامل مع الصور لن يكون هناك التفاف في النص ودفع إلى الداخل وإنما سيتم إظهار شريط التمرير على طول الصفحة ومن جهة أخرى فإن زيادة قيمة الهامش من أجل اصطفاف السطور كما في firefox (الهامش كان بنسبة 33%) لامعنى له في الأشكال العائمة float shape في chrome وذلك لأن النص لن يصل أبداً حتى النصف السفلي من الدوائر. دعم ميزة Querying feature تشغيل ميزة feature query يتم من خلال إضافة سطر supports@ إلى التعليمات حيث نستطيع من خلال هذه الطريقة معرفة المتصفحات التي لاتدعم الأشكال العائمة التي أضفناها فتقوم تعليمة support@ بتعديل الهوامش إلى 33% كما أنها تقلل هذه الهوامش في حال كانت المتصفحات تستطيع التعامل مع هذه الأشكال، ويتم هذا من خلال إضافة تعليمات: .complex-content div:nth-child(even):not(:last-child) p { margin-right: 33%; } .complex-content div:nth-child(odd):not(:last-child) p { margin-left: 33%; } @supports (shape-outside: circle()) { .complex-content div:nth-child(even):not(:last-child) p { margin-right: 20%; } .complex-content div:nth-child(odd):not(:last-child) p { margin-left: 20%; } } وبهذا سيظهر تصميم العناصر بشكل جيد في جميع المتصفحات، بالرغم من وجود بعض الأشياء الصغيرة جدًا التي يمكن إضافتها. ولكن بشكل عام طريقة العرض في جميع الحالات التي تدعم الأشكال العائمة أو لا تبعث على السرور في الفيديو الأول طريقة العرض في متصفح chrome تحميل الفيديو الأول والفيديو الثاني يظهر طريقة العرض في متصفح firefox الذي لايدعم الأشكال العائمة تحميل الفيديو الثاني بالأخير إنها نعمة وجود ميزة مثل feature queries تسمح للمتصفحات مثل firefox و MS Edge الحصول على دعم لإظهار الأشكال العائمة. ومع أنه لايوجد تحسينات قريبة للمتصفحات ولكن يتم العمل بشكل دائم على إدخال التحسينات على CSS نفسها بحيث سيصبح شعارها قريبًا "صمم وانسى"، كما يمكن القول بأن التعديل الأساسي في CSS هو طريقة التعامل مع الأشكال وتحسين عمليه استجابتها من دول وجود الدعم الكافي في المتصفحات لها. ترجمة –وبتصرّف- للمقال A Redesign with CSS Shapes لصاحبه Eric Meyer
-
بناء المواقع الإلكترونية أمر ممتع ومحبط في نفس الوقت، وعادة ما يكون سبب الإحباط هو السعي لتوحيد مظهر وأداء الموقع الإلكتروني في جميع المتصفحات، ولا شكّ أن مصمّمي الواجهات الأمامية قد مرّوا بحالة الإحباط هذه بشكل أو بآخر. ولكن الحقيقة تقول بأنه ما من ضرورة تدعو إلى توحيد مظهر وأداء الموقع الإلكتروني على جميع المتصفحات، فطريقة عمل الموقع في كل متصفّح عائدة إلى المبرمج وإلى طبيعة الموقع الإلكتروني. فإن كان الموقع يستقبل أقلّ من نصف نسبة الزوّار من خلال Internet Explorer 8 فقد يكون من المعقول حينئذٍ صرف النظر عن هذا المتصفح، أما لو كان نصف الزوّار يستخدمون هذا المتصفح وكانت هذه الزيارات تدرّ أموالًا كثيرة، فسيكون دعم هذا المتصفح حينئذٍ أمرًا إلزاميًا. من هنا يجب تحديد ما هو مقبول بالنسبة لموقع إلكتروني معين والعمل بموجب ذلك. يوجد عدد من الممارسات الجيدة التي تتيح للموقع الإلكتروني أن يعمل على نحو جيّد في جميع المتصفحات. ينصح عادة بتوفير الدعم التراجعي Fallback support عند استخدام خصائص CSS 3 وذلك لدعم المتصفحات القديمة، وهناك تقنيات أخرى مثل الـ Shivs و Polyfills وهي عبارة عن ملحقات JavasScript صغيرة تضيف الدعم لعدد من المزايا المطلوبة التي لا تدعمها المتصفحات القديمة مبدئيًّا. HTML Shiv أحد أشهر الملحقات التي تقدّم الدعم التراجعي هو HTML5 Shivs، وقد أنشأ Remy Sharp هذا الملحق لإتاحة استخدام عناصر HTML 5 في Internet Explorer 8 وما قبله، ولا يكتفي هذا الملحق بتوفير الدعم لعناصر HTML5 فقط، بل يتجاوز ذلك إلى إمكانية تنسيقها بواسطة CSS. يجب تنزيل آخر إصدار من هذا الملحق من Google حيث يحتفظ Remy بآخر الإصدارات، ثم ضيافتها على الخادوم الخاص بك. وللحصول على أفضل أداء يفضّل الإشارة إلى ملف JavaScript الخاص بالإضافة في بداية الصفحة ضمن الوسم <head>، مباشرة بعد الإشارة إلى ملفات CSS. كذلك يجب وضع شفرة جلب الإضافة ضمن تعليق مشروط لتضمن تنزيل الملفات في الإصدار الثامن من Internet Explorer وما دونه. <!--[if lt IE 9]> <script src="html5shiv.js"></script> <![endif]--> وبعد إنشاء عناصر HTML5 الجديدة في مستوى Block باستخدام HTML5 Shiv يجب تحديد وتحديث تلك العناصر بواسطة التصريح display:block. article, aside, details, figcaption, figure, footer, header, hgroup, nav, section, summary { display: block; } لا يعرّف الإصداران الثامن والتاسع من Internet Explorer أنماط بعض عناصر HTML5 بطريقة صحيحة في مستوى Inline-block، لذا تجب إضافة التصريح display: inline-block إلى هذه العناصر. بهذا يمكنك استخدام أي عنصر من عناصر HTML5 في جميع إصدارات Internet Explorer. audio, canvas, video { display: inline-block; } ما الفرق بين Shiv و Shim قد تسمع أو تقرأ في بعض المواقع عن HTML5 Shim، وقد تتساءل إن كان هناك فرق بينها وبين HTML5 Shiv. في الواقع لا يوجد أي فارق يذكر بين هذين المصطلحين، وكلاهما يستخدمان للتعبير عن المعنى ذاته. الكشف عن المزايا المتاحة في المتصفح تؤدي HTML5 Shiv عملًا جيّدًا مع التعليقات المشروطة في تعريف المتصفح بخصائص HTML5 وعناصرها الجديدة، ولكن باستخدام هذه الطريقة فإنك تحدّد مسبقًا المتصفح الذي لا يدعم هذه الخصائص. هناك طريقة أخرى لتوفير الدعم لعناصر وخصائص معينة في HTML5 و CSS3 بغض النظر عن المتصفح المستخدم. توفّر مكتبة Modernizr وسيلة للكشف عن ميزات المتصفح من خلال كتابة شفرات CSS و JavaScript مشروطة بالاستناد إلى دعم المتصفح لخاصّية معينة أم لا. فعلى سبيل المثال، إن كان أحد المتصفحات يدعم خاصّية الأركان الدائرية فستقوم Moderinzr بإضافة الصنف borderradius إلى عنصر html. أما إن كان المتصفح لا يدعم هذه الخاصّية، تقوم مكتبة Modernizr بإضافة الصنف no-borderradius إلى عنصر html. تنزيل مكتبة Modernizr لتشغيل مكتبة Modernizr في موقعك توجّه إلى صفحة التنزيل الخاصة بالمكتبة حيث يمكنك اختيار الخصائص التي ترغب في الكشف عنها. بعد تنزيل المكتبة ارفعها إلى الخادوم الخاص بك ثم أشر إلى الملف ضمن الوسم head في صفحة HTML مباشرة بعد آخر إشارة لملفات الأنماط. من الجدير بالذكر أنّه يمكن تخصيص Modernizr لتتضمن HTML5 Shiv، وبهذا لا حاجة للإشارة إليها في بداية Modernizr. <script src="modernizr.js"></script> التطبيق الشرطي لأنماط CSS بمجرد أن تبدأ مكتبة Modernizr بالعمل يصبح بالإمكان تطبيق أنماط CSS بالاعتماد على وجود أو عدم وجود خصائص معينة في المتصفح الذي يعرض الموقع الإلكتروني. تستطيع Modernizr الكشف عن معظم الخصائص والقيم التي تقدّمها CSS3 ويمكنك التعرّف عليها من خلال توثيقات المكتبة على شبكة الإنترنت. يجدر الانتباه إلى أنّه قد يكون من غير الضروري الكشف عن الخصائص المتعلقة ببعض الأنماط، فعلى سبيل المثال عندم استخدام قيمة لون بصيغة RGBa يمكن تقديم دعم تراجعي لهذه القيمة من خلال توفير قيمة اللون بصيغة hexadecimal دون الحاجة إلى اللجوء لتقنية الكشف عن الخصائص. عندما تقرّر استخدام تقنية الكشف عن الخصائص من الضروري أن تحافظ على تنظيم الشفرات وأن تراعي مسألة الأداء. تجنّب قدر الإمكان تكرار الشفرة لأكثر من مرة أو إنشاء طلبات HTTP إضافية. button { border: 0; color: #fff; cursor: pointer; font-size: 14px; font-weight: 600; margin: 0; outline: 0; } /* With CSS Gradient Styles */ .cssgradients button { border: 1px solid #0080c2; background: linear-gradient(#00a2f5, #0087cc); border-radius: 6px; padding: 15px 30px; } .cssgradients button:hover { background: linear-gradient(#1ab1ff, #009beb); } .cssgradients button:active { box-shadow: inset 0 1px 10px rgba(255, 255, 255, .5); } /* Without CSS Gradient Styles */ .no-cssgradients button { background: transparent url("button.png") 0 0 no-repeat; padding: 16px 31px; } .no-cssgradients button:hover { background-position: 0 -49px; } .no-cssgradients button:active { background-position: 0 -98px; } في المثال السابق تمكن ملاحظة أن الزرّ يرث أنماطًا مبدئية، ولكن الأنماط المخصّصة تطبّق بالاستناد إلى دعم المتصفح لخاصية الخلفية المتدرّجة في CSS3، إضافة إلى خاصيتيْ الأركان الدائرية والظلال. إن كان المتصفح يدعم هذه الخصائص، فسيحصل الزرّ على خلفية متدرجة وعلى ظلّ وحواف دائرية، أما في حال عدم دعم المتصفح لهذه الخصائص فيحصل الزرّ على صورة خلفية تتضمن جميع هذه التأثيرات. بهذه الطريقة لا توجد شفرات زائدة ولا يُرسَل طلب HTTP إلا عند الحاجة. عند العمل مع تقنية الكشف عن خصائص CSS3 يكون من الصعب تخمين مظهر عنصر معين في المتصفحات التي لا تدعم الخصائص الجديدة، ولحسن الحظ هناك أداة تدعى deCSS3 تعمل على تعطيل جميع خصائص CSS3 في الصفحة ما يسمح لك بالتعرف على مظهر موقعك الإلكتروني عندما لا تُستخدَم CSS3، إضافة إلى اختبار الأنماط المشروطة المستخدمة في الموقع. لتحصل على فكرة سريعة عن الخصائص والميزات التي يدعمها متصفّح معين،زر الموقع haz.io باستخدام ذلك المتصفح. التنزيل الشرطي للملفات إضافة إلى التنزيل الشرطي للأنماط، تقدّم مكتبة Modernizr وسيلة لاستخدام تقنية الكشف عن الخصائص في JavaScript، حيث يصبح بالإمكان تنزيل ملفات الـ Polyfills وغيرها من الملفات بالاستناد إلى وجود خاصية معينة والاستعانة بمكتبة jQuery وتابع getScript الخاص بهذه المكتبة. يمكن استخدام مكتبة Modernizr في العبارات الشرطية وذلك لتشغيل شفرات متنوعة اعتمادًا على تحقق الشرط أو عدمه. في المثال التالي تتحقّق Modernizr من دعم المتصفح لخاصية التخزين المحلي Local storage. إن كانت هذه الخاصّية متوفرة في المتصفح، يُنزَّل الملف storage.js باستخدام jQuery وتابع getScript، أما إن كانت هذه الخاصّية غير مدعومة في المتصفح فيُستعان بـ jQuery لتنزيل ملف storage-polyfills.js وبواسطة التابع ذاته. $(document).ready(function() { if (Modernizr.localstorage) { // التخزين المحلّي متوفّر jQuery.getScript('storage.js'); } else { // التخزين المحلّي غير متوفّر jQuery.getScript('storage-polyfill.js'); } }); التنزيل الشرطي بالاستناد إلى استعلام الوسيط Media Query استعلامات الوسائط Media queries من الأمور المهمّة التي يمكن لـ Modernizer الكشف عن وجودها ، حيث يمكن تنزيل الملفات فقط في حال تحقق الشروط الخاصة باستعلام الوسائط. تجنّب تنزيل الملفات غير الضرورية من الأمور المفيدة جدًّا في تحسين أداء الصفحة. $(document).ready(function() { if (Modernizr.mq('screen and (min-width: 640px)')) { jQuery.getScript('tabs.js'); } }); تتحقق Modernizer في المثال الموضح أعلاه ممّا إذا كان عرض الشاشة أكبر من 640 بكسلًا، أي شاشات حواسيب سطح المكتب بصورة رئيسية، ثم تُنزِّل ملف tabs.js بالاعتماد على تحقق الشرط. من الضروري الانتباه إلى أن التحقق من هذا الشرط يتم مرة واحدة فقط وذلك عند تنزيل الصفحة، وهذا يعني أنّه لن يُتحقَّق من هذا الشرط عندما يغيّر المستخدم حجم الصفحة، وإن تطلب الأمر إعادة التحقق من جديد، فيجب استخدام شفرة JavaScript إضافية للقيام بذلك. التشغيل الشرطي للشفرات يمكن التحقق من جميع الخصائص التي تقدّمها HTML5 و CSS3 باستخدام Modernizr ومن خلال JavaScript. فعلى سبيل المثال، يستحسن تعطيل عمل التلميحات Tooltips في أجهزة الهاتف المحمول نظرًا لعدم توفّر التحليق Hover في هذه الأجهزة، والاستعاضة عن ذلك بعرض التلميحات على هيئة نصوص صرفة. يمكن تغليف الشفرة المسؤولة عن استدعاء التلميحات بعبارة شرطية تمنع تنزيل الشفرة عند استعراض الموقع في الشاشات الصغيرة. $(document).ready(function() { if (Modernizr.mq('screen and (max-width: 400px)')) { $('.size').text('small'); } }); يوضح المثال السابق على نحو مبسط طريقة تنفيذ شفرة JavaScript بالاستناد إلى شرط وضعته Modernizr. إن كان عرض الشاشة عند تنزيل الصفحة أكبر من 800 بكسل فلن يحدث شيء. ولكن إن كان عرض الشاشة أصغر من هذا الرقم تُبْدَل ‘large’ بكلمة ‘small’. HTML5 و CSS3 Polyfills تتوفّر في الوقت الحاضر polyfills لمختلف مزايا HTML5 وCSS3 تقريبًا، وقد وفّر الفريق المسؤول عن تطوير Modernizr قائمة مفصّلة بالـ polyfills المتوفّرة، والتي يمكن استخدامها حسب الحاجة. كذلك وضع نفس الفريق قائمة بجميع ميزات HTML5 و CSS3 الجديدة إضافة إلى تعليمات استخدام هذه الميزات بصورة صحيحة. يجب الانتباه إلى أنّه لا تحتاج جميع هذه الميزات إلى الـ Polyfills، إذ يمكن الاستفادة من بعضها مباشرة أو من خلال الدعم التراجعي. اختبار الموقع في متصفحات مختلفة ربّما تكون عملية اختبار الموقع الإلكتروني سواء من ناحية التصميم أو التطوير في المتصفحات أمرًا متعبًا للغاية، وبصورة عامة فإنّ المتصفحات الحديثة مثل Chrome، Firefox و Safari تعمل جيّدًا، إلا أن غالبية المشاكل تظهر في متصفح Internet Explorer، إضافة إلى أن اختبار إصدارات مختلفة من هذا المتصفح قد يكون أمرًا صعبًا. هناك العديد من الخدمات التي تساعد على اختبار الموقع الإلكتروني في المتصفحات المختلفة، بعضها تفاعلي وبعضها لا. تساعد القدرة على التفاعل مع المتصفح بدلًا من رؤية لقطة شاشة للموقع كثيرًا على تنقيح الشفرة البرمجية. ومن أفضل الطرق لاستخدام إصدارات مختلفة من متصفح Internet Explorer هي استخدام الآلات الافتراضية Virtual Machines، بحيث تتضمن كل آلة إصدارًا مختلفًا من هذا المتصفح. يظهر في الصورة أعلاه برنامج VirtualBox يعمل على نظام Mac OS X مع المتصفح Internet Explorer من الإصدار السادس إلى التاسع. تقدّم Microsoft مجموعة من الحواسيب الافتراضية Virtual PCs التي يمكن استخدامها في عملية الاختبار، ولكن يمكن لعملية الإعداد أن تكون مرهقة وصعبة. لحسن الحظ قام Greg Thornton ببناء أداة تُؤَتْمِت عملية تنصيب الآلات الافتراضية. تستغرق عملية التنصيب بعض الوقت وذلك لتنزيل جميع الآلات الافتراضية المتوفرة، وستحتاج كذلك إلى مساحة كبيرة على القرص الصلب، ولكن يمكن تثبيت الآلات الافتراضية التي تحتاج إليها فقط، وبالنظر إلى وتيرة استخدامك لهذه الآلات الافتراضية، قد يكون من الأفضل تنصيبها على قرص صلب خارجي. يحتوي الإصدار الثامن من Internet Explorer على أدوات تطوير مضمّنة في المتصفح، ولكن الإصدارات السابقة تفتقر إلى هذه الميزة. ولكن تتوفّر أداة Firebug التي تقدّم أدوات تطوير مفيدة جدًّا داخل المتصفّح. يظهر في الصورة أعلاه الإصدار السابع من Internet Explorer يعمل في آلة افتراضية مع استخدام أداة Firebug Lite لتنقيح الشفرة البرمجية. ترجمة - وبتصرّف - للمقال Feature Support & Polyfills لصاحبه Shay Howe.
-
- css3
- virtualbox
-
(و 3 أكثر)
موسوم في:
-
كانت القدرة على التحكم بتأثيرات الانتقال Transitions والحركة Animations من إحدى الميزات التي أتت بها CSS3، وقد كان مطورو الواجهات الأمامية بحاجة كبيرة إلى مثل هذه الميزة لتصميم هذه التأثيرات باستخدام HTML و CSS فقط دون الحاجة إلى استخدام Javascript أو Flash، وقد تحققت رغبتهم أخيرًا وبعد سنوات عديدة. تتيح تأثيرات الانتقال في CSS3 تغيير مظهر أو سلوك العنصر عندما تتغير حالته، كأن يُمرَّر مؤشر الفأرة فوق العنصر hover، أو عند التركيز focus أو التنشيط active أو استهداف العنصر. أما تأثيرات الحركة في CSS3 فتتيح تغيير هيئة وسلوك العنصر من خلال مفاتيح keyframes متعددة، وهذا يعني أن تأثيرات الانتقال تقدّم تغيّرًا من حالة إلى أخرى، في حين أن تأثيرات الحركة تقدّم نقاطًا متعددة من الانتقالات من خلال مفاتيح مختلفة. تأثيرات الانتقال مثلما ذكرنا سابقًا، فإنّه ولكي يحدث تأثير الانتقال يجب أن يحدث تغير في حالة العنصر، كذلك يجب تعريف أنماط مختلفة لكل حالة من هذه الحالات. وأسهل طريقة لتحديد الأنماط لمختلف الحالات هي استخدام أشباه الأصناف التالية: :hover، :focus، :active ،:target. هناك أربعة خصائص مرتبطة بتأثيرات الانتقال وهي: transition-property، transition-duration، transition-timing-function، و transition-delay. ليست جميع هذه الخصائص مطلوبة لإنتاج تأثيرات الحركة، ولكن الخصائص الثلاثة الأولى هي الأكثر استخدامًا. في المثال التالي سيتغير لون خلفية background الصندوق خلال ثانية واحدة وبطريقة تدريجية خطّية linear. .box { background: #2db34a; transition-property: background; transition-duration: 1s; transition-timing-function: linear; } .box:hover { background: #ff7b29; } سوابق المتصفحات Vendor Prefixes لا تتضمن الشفرة السابقة كما هو الحال مع جميع الشفرات البرمجية في هذا المقال على سوابق المتصفحات، وهذا الأمر مقصود والهدف منه هو الحفاظ على الشفرة بسيطة وصغيرة الحجم وقابلة للفهم. ولتحصل على أفضل دعم في جميع المتصفحات عليك باستخدام سوابق المتصفحات. ولغرض التوضيح فقط، فإن الشفرة السابقة ستكون هكذا: .box { background: #2db34a; -webkit-transition-property: background; -moz-transition-property: background; -o-transition-property: background; transition-property: background; -webkit-transition-duration: 1s; -moz-transition-duration: 1s; -o-transition-duration: 1s; transition-duration: 1s; -webkit-transition-timing-function: linear; -moz-transition-timing-function: linear; -o-transition-timing-function: linear; transition-timing-function: linear; } .box:hover { background: #ff7b29; } خاصية الانتقال تحدّد خاصية transition-property بدقّة الخصائص التي سيتم تغييرها بالتزامن مع الخصائص الانتقالية الأخرى. تتغيّر جميع الخصائص - مبدئيًّا - ضمن الحالات المختلفة للعنصر، ولكن يمكن تحديد الخصائص المراد تغييرها ضمن قيمة transition-property وستتأثّر تلك الخصائص فقط بتأثيرات الانتقال. في المثال السابق قمنا بتعريف الخاصية background قيمةً لـ transition-property، وهذا يعني أنّها ستكون الخاصية الوحيدة التي ستخضع للتغيّر خلال ثانية واحدة وبطريقة تدريجية خطّية linear. بمعنى أنّه في حال وجود عدد من الخصائص لعنصر معيّن عند تغيّر حالته، ولكنّها غير معرّفة كقيمة لـ transition-property فإنّها لن تتلقى تأثيرات الانتقال كتلك المعرّفة في الخصائص transition-duration أو transition-timing-function. إن كنت بحاجة إلى تغيير عدد من الخصائص في الوقت نفسه، فيمكنك أن تفصلها بفواصل، كذلك يمكنك استخدام القيمة all لتطبيق تأثيرات الانتقال على جميع خصائص العنصر. .box { background: #2db34a; border-radius: 6px transition-property: background, border-radius; transition-duration: 1s; transition-timing-function: linear; } .box:hover { background: #ff7b29; border-radius: 50%; } الخصائص التي تسمح بتطبيق تأثيرات الانتقال عليها من الضروري الانتباه إلى أنّه لا تتقبّل جميع الخصائص تطبيق تأثيرات الانتقال عليها، بل فقط تلك العناصر التي تمتلك نقاطًا وسطية قابلة للتعريف. فخصائص مثل الألوان، حجم الخط وما شابهها يمكن تطبيق تأثيرات الانتقال عليها نظرًا لكونها تملك قيمًا معرّفة بين بعضها البعض. في حين أن خاصية display على سبيل المثال لا يمكنها تقبّل تأثيرات الانتقال لأنّها لا تملك أيّة قيم وسطية. القائمة التالية تبيّن مجموعة من الخصائص الشائعة التي يمكن تطبيق تأثيرات الانتقال عليها: background-color background-position border-color border-width border-spacing bottom clip color crop font-size font-weight height left letter-spacing line-height margin max-height max-width min-height min-width opacity outline-color outline-offset outline-width padding right text-indent text-shadow top vertical-align visibility width word-spacing z-index مدة تأثير الانتقال يمكن تعيين المدة التي يستغرقها تأثير الانتقال من خلال خاصية transition-duration، ويمكن استخدام وحدات توقيت عامة وهي الثانية (s) والمللي ثانية (ms)، ويمكن استخدام الأعداد العشرية في تعيين هذه القيمة، فمثلًا يمكن استخدام الصيغة التالية: .2s. عند تطبيق تأثير الانتقال على خصائص متعددة يمكن تعيين مدد متعددة أيضًا لكل خاصية، وكما هو الحال عند تعيين قيمة خاصية transition-property يمكن استخدام الفاصلة لتعيين قيم متعددة لخاصية مدة الانتقال. ولكن من الواجب الانتباه إلى أنّه عند تعيين مدد متعددة يجب مراعاة الترتيب المتّبع في تعيين الخصائص التي ستتلقّى تأثير الانتقال بواسطة خاصية transition-property، بمعنى أنّ القيمة الأولى في هذا الخاصية ستأخذ القيمة الأولى في خاصية transition-duration وهكذا دواليك. وإن طُبِّق تأثير الانتقال على خصائص متعددة مع تعيين قيمة واحدة لمدّة التأثير، فإن تلك القيمة ستطبّق على جميع الخصائص. .box { background: #2db34a; border-radius: 6px; transition-property: background, border-radius; transition-duration: .2s, 1s; transition-timing-function: linear; } .box:hover { background: #ff7b29; border-radius: 50%; } توقيت تأثير الانتقال تُستخدَم خاصّية transition-timing-function لتعيين سرعة تأثير الانتقال، ويمكن لهذا التأثير أن يمتلك سرعات مختلفة ضمن مدة زمنية واحدة وذلك بعد تعيين المدة من خلال خاصية transition-duration. وهناك قيم مفتاحية شائعة تُستخدَم مع هذه الخاصية مثل linear، ease-in، ease-out و ease-in-out. عند استخدام قيمة linear فإن الحركة تكون بسرعة ثابتة من حالة إلى أخرى، أما عند استخدام القيمة ease-in فإن الحركة تبدأ ببطء وتتسارع تدريجيًا مع مرور الوقت، وعند استخدام القيمة ease-out فإن الحركة تبدأ بسرعة وتتباطئ تدريجيًا مع مرور الوقت. أما عند استخدام القيمة ease-in-out فإن الحركة تبدأ بطيئة ثم تتسارع في الوسط لتعود إلى التباطؤ قبل الوصول إلى نهاية المدة المحددة للتأثير. تمتلك كل دالة توقيت منحنى بيزيه مكعبي Cubic-Bezier curve يمكن تعيين قيمه بدقّة بواسطة القيمة cubic-bezier(x1, y1, x2, y2) إضافة إلى قيم أخرى هي step-start و step-stop إلى جانب قيمة فريدة تحدّد من خلال steps(number_of_steps, direction). عند تطبيق تأثر الانتقال على خصائص متعددة، يمكن تعريف دوال توقيت متعددة أيضًا، وكما هو الحال مع قيم خصائص الانتقال الأخرى، يمكنك فصل القيم المتعددة بفواصل. .box { background: #2db34a; border-radius: 6px; transition-property: background, border-radius; transition-duration: .2s, 1s; transition-timing-function: linear, ease-in; } .box:hover { background: #ff7b29; border-radius: 50%; } تأخير تأثير الانتقال إضافة إلى التصريح عن كل من خاصية التأثير والمدة الزمنية ودوال التوقيت، يمكن كذلك تعيين فترة تأخير تأثير الانتقال من خلال خاصّية transition-delay، حيث تُعيَّن قيمة زمنية - بالثانية أو بالمللي ثانية - تحدد الفترة الزمنية التي تسبق انطلاق التأثير. وكما هو الحال مع جميع خصائص تأثيرات الانتقال، يمكن تأخير عدد من التأثيرات من خلال إضافة قيم متعددة مفصولة بفواصل. .box { background: #2db34a; border-radius: 6px transition-property: background, border-radius; transition-duration: .2s, 1s; transition-timing-function: linear, ease-in; transition-delay: 0s, 1s; } .box:hover { background: #ff7b29; border-radius: 50%; } الصيغة المختصرة لتأثيرات الانتقال قد يصبح التصريح عن خصائص الانتقال واحدة تلو الأخرى أمرًا مجهدًا، خصوصًا مع استخدام سوابق المتصفحات، ولحسن الحظّ يمكن اختصار العملية من خلال استخدام الخاصية transition والتي تدعم جميع الخصائص والقيم السابقة. فباستخدام قيمة transition لوحدها، يمكنك تعريف كل خصائص تأثيرات الانتقال وبالترتيب التالي: transition-property, transition-duration, transition-timing-function, وأخيرًا transition-delay. ولا حاجة لاستخدام الفواصل عند تعريف قيم هذه الخصائص إلا إذا كنت تعرّف تأثيرات انتقال متعددة. ولتعريف تأثيرات انتقال متعددة في سطر واحد، يمكنك تعيين قيم كل مجموعة من التأثيرات على حدة وفصل أي مجموعة تأثيرات إضافية باستخدام الفواصل. .box { background: #2db34a; border-radius: 6px; transition: background .2s linear, border-radius 1s ease-in 1s; } .box:hover { color: #ff7b29; border-radius: 50%; } تطبيق تأثيرات الانتقال على أيقونة HTML <button>Awesome Button</button> CSS button { border: 0; background: #0087cc; border-radius: 4px; box-shadow: 0 5px 0 #006599; color: #fff; cursor: pointer; font: inherit; margin: 0; outline: 0; padding: 12px 20px; transition: all .1s linear; } button:active { box-shadow: 0 2px 0 #006599; transform: translateY(3px); } (تجربة حية) بطاقة متقلّبة HTML <div class="card-container"> <div class="card"> <div class="side">...</div> <div class="side back">...</div> </div> </div> CSS .card-container { height: 150px; perspective: 600; position: relative; width: 150px; } .card { height: 100%; position: absolute; transform-style: preserve-3d; transition: all 1s ease-in-out; width: 100%; } .card:hover { transform: rotateY(180deg); } .card .side { backface-visibility: hidden; height: 100%; position: absolute; width: 100%; } .card .back { transform: rotateY(180deg); } (تجربة حية) تأثيرات الحركة تؤدي تأثيرات الانتقال عملًا متميّزًا من خلال إضفاء التأثيرات البصرية عند الانتقال من حالة إلى أخرى، وهي مناسبة جدًّا لمثل هذه الحالات التي يحدث فيها تغيّر الحالة لمرة واحدة فقط. ولكن عندما تكون بحاجة إلى التحكم في الأمور على نحو أدقّ فستضطر إلى إضافة المزيد من الحالات إلى تأثيرات الانتقال، وهنا يأتي دور تأثيرات الحركة. مفاتيح تأثيرات الحركة يمكن استخدام قاعدة @keyframes لتعيين النقاط التي يجب أن يحدث فيها تأثير الانتقال. تتضمن هذه القاعدة اسم تأثير الحركة، والنقاط التي تحدث فيها الحركة، والخصائص التي نرغب في تحريكها. @keyframes slide { 0% { left: 0; top: 0; } 50% { left: 244px; top: 100px; } 100% { left: 488px; top: 0; } } إضافة سوابق المتصفحات إلى قاعدة keyframe تجب إضافة سوابق المتصفحات إلى قاعدة @keyframes كما هو الحال مع خصائص تأثيرات الانتقال والحركة، وكما يلي: @-moz-keyframes @-o-keyframes @-webkit-keyframes يحمل تأثير الحركة في المثال السابق اسم slide، وقد أفصحنا عنه مباشرة بعد قاعدة @keyframes. تُعيَّن نقاط حدوث الحركة باستخدام النسبة المئوية، ابتداءً من 0% وانتهاءً بـ 100% ونقطة وسطية عند 50%. كما يمكن استخدام الكلمات المفتاحية from و to بدلًا من 0% و 100%، كما يمكن تعيين أي عدد من النقاط ضمن هذا المدى. يُصرَّح عن خصائص العنصر التي نرغب في تحريكها داخل كل نقطة، وفي المثال السابق كانت الخصائص المطلوبة هي left و top. من الضروري الانتباه إلى أنّه يمكن تحريك خاصّيّة واحدة فقط كما هو الحال مع تأثيرات الانتقال. فعلى سبيل المثال إن كنت ترغب في تحريك عنصر من الأعلى إلى الأسفل، فإن التحريك من top:0; إلى bottom: 0; لن يجدي نفعًا، لأن الحركة يمكن تطبيقها على خاصية واحدة فقط، وليس من خاصّية إلى أخرى؛ لذا من أجل تحريك العنصر من الأعلى إلى الأسفل يجب التحريك من top: 0; إلى top: 100%;. (تجربة حية). اسم تأثير الحركة بعد تعيين مفاتيح الحركة الخاصّة بتأثير الحركة، يجب إسنادها إلى أحد العناصر في الصفحة. وللقيام بذلك نستخدم خاصّية animation-name مع الاسم الذي عيّناه لقاعدة @keyframes، وتستخدم هذه الخاصّية مع العنصر الذي نرغب في تطبيق تأثيرات الحركة عليه. .stage:hover .ball { animation-name: slide; } لا يكفي استخدام خاصّية animation-name لوحدها، بل يجب تعيين قيمة لخاصية animation-duration ليعرف المتصفح المدة اللازمة لانتهاء التأثير. مدة تأثير الحركة، دالة التوقيت، وتأخير الحركة بعد أن تُعيّن قيمة خاصّية animation-name ستسلك تأثيرات الحركة نفس سلوك تأثيرات الانتقال، إذ يمكن تعيين مدّة التأثير وتعريف دالة التوقيت وتأخير التأثير حسب الرغبة. وليبدأ تأثير الحركة بالعمل فإنه بحاجة إلى تعيين مدّة التأثير من خلال خاصية animation-duration، وكما هو الحال مع تأثيرات الانتقال، يمكن لقيمة هذه الخاصّية أن تكون بالثانية أو بالمللي ثانية. .stage:hover .ball { animation-name: slide; animation-duration: 2s; } يمكن تعريف دالّة التوقيت وتأخير تأثّر الحركة باستخدام الخاصّيتين animation-timing-function و animation-delay على التوالي، ولا يوجد أي فرق في القيم التي تستقبلها هاتان الخاصيتان أو طريقة عملها بين تأثيرات الانتقال وتأثيرات الحركة. .stage:hover .ball { animation-name: slide; animation-duration: 2s; animation-timing-function: ease-in-out; animation-delay: .5s; } في المثال التالي سترتدّ الكرة (العنصر<figure> مع النمط ball) أثناء تحرّكها إلى جهة اليسار، ويمكن مشاهدة الحركة من خلال تمرير مؤشر الفأرة فوق العنصر <div> ذي النمط stage. HTML <div class="stage"> <figure class="ball"></figure> </div> CSS 0% { left: 0; top: 0; } 50% { left: 244px; top: 100px; } 100% { left: 488px; top: 0; } } .stage { height: 150px; position: relative; } .ball { height: 50px; position: absolute; width: 50px; } .stage:hover .ball { animation-name: slide; animation-duration: 2s; animation-timing-function: ease-in-out; animation-delay: .5s; } (تجربة حية) تخصيص تأثيرات الحركة تتيح تأثيرات الحركة المزيد من التخصيص لسلوك العنصر، فيمكن تعيين عدد مرات تكرار الحركة والاتجاه الذي ستنتهي فيه الحركة. تكرار تأثير الحركة لا يتكرر تأثير الحركة بصورة افتراضية بل يتوقف بعد إتمام الدورة الأولى، ولجعل التأثير يتكرّر مرات متعددة يمكن استخدام خاصّية animation-iteration-count، وتتضمن قيم هذه الخاصية إمّا أعداد صحيحة أو كلمة infinite المفتاحية. في الحالة الأولى سيتكرر تأثير الحركة بحسب العدد المحدّد، أما في الحالة الثانية فإن تأثير الحركة سيتكرّر إلى ما لا نهاية. .stage:hover .ball { animation-name: slide; animation-duration: 2s; animation-timing-function: ease-in-out; animation-delay: .5s; animation-iteration-count: infinite; } (تجربة حية) اتجاه تأثير الحركة وإلى جانب القدرة على تعيين عدد مرات تكرار تأثير الحركة، يمكن كذلك تعيين اتجاه انتهاء التأثير باستخدام الخاصية animation-direction، وتأخذ هذه الخاصية القيم: normal، reverse، alternate و alternate-reverse. استخدام القيمة normal يعني أن الحركة ستسير بشكل طبيعي من البداية إلى النهاية، أما القيمة reverse فتعني أن الحركة ستسير بعكس الطريقة المصرّح عنها في قاعدة @keyframes، أي ستبدأ الحركة من 100% وتنتهي بـ 0%. عند استخدام القيمة alternate فإن الحركة ستسير جيئة وذهابًا، أي ستبدأ الحركة من 0% لتتّجه إلى 100% ثم تعود من هذه القيمة إلى 0% مرة أخرى. يمكن تحديد عدد مرّات تكرار الحركة بالاتجاه الأمامي والخلفي وذلك باستخدام الخاصّية animation-iteration-count، حيث يبدأ العدّ من الرقم 1 فتبدأ الحركة من القيمة 0% وصولًا إلا 100% وتكتمل الدورة الأولى، بعد ذلك نعود من القيمة 100% إلى 0% فتضاف دورة أخرى إلى العدّاد، وبهذا نحصل على دورتين بالمجمل. تعمل القيمة alternate كذلك على قلب دوال التوقيت عند بدء الحركة بشكل عكسي، فإن كان تأثير الحركة يستخدم القيمة ease-in عند التحرك من 0% إلى 100% فإنّه سيستخدم القيمة ease-out عند الانتقال من 100% إلى 0%. أخيرًا، تدمج القيمة alternate-reverse القيمتين alternate و reverse، وتكون الحركة بالاتجاه الخلفي ثم بالاتجاه الأمامي، أي تبدأ الحركة من 100% باتجاه 0% لتعود مرّة أخرى إلى 100%. .stage:hover .ball { animation-name: slide; animation-duration: 2s; animation-timing-function: ease-in-out; animation-delay: .5s; animation-iteration-count: infinite; animation-direction: alternate; } (تجربة حية) حالة تأثير الحركة تسمح خاصّية animation-play-state بتشغيل تأثير الحركة أو إيقافه مؤقتًا باستخدام خيارين هما running و paused على التوالي. عند إعادة تشغيل تأثير الحركة المتوقف مؤقتًا فإنّ التأثير يعود إلى الحركة من النقطة التي توقّف عندها وليس من نقطة البداية. في المثال التالي تم تعيين قيمة paused للخاصّية animation-play-state وذلك عند النقر على العنصر ذي النمط stage. لاحظ كيف أن الحركة ستبقى متوقّفة بصورة مؤقتة إلى حين إفلات زر الفأرة. .stage:hover .ball { animation-name: slide; animation-duration: 2s; animation-timing-function: ease-in-out; animation-delay: .5s; animation-iteration-count: infinite; animation-direction: alternate; } .stage:active .ball { animation-play-state: paused; } (تجربة حية) نمط التعبئة الخاصّ بتأثير الحركة تعرّف الخاصّية animation-fill-mode النمط الذي سيطبّق على العنصر قبل أو بعد أو قبل وبعد عمل تأثير الحركة، ولهذه الخاصّية أربع قيم هي: none, forwards, backwards, و both. عند استخدام القيمة none لن يتم تطبيق أي نمط على العنصر قبل أو بعد تطبيق تأثير الحركة. القيمة forwards ستحافظ على الأنماط المعرّفة في المفتاح الحركي الأخير، ولكن يجب الانتباه إلى أن هذه الأنماط قد تتأثّر بقيم الخاصّيتين animation-direction و animation-iteration-count فتتغيّر نقطة انتهاء تأثير الحركة. القيمة backwards ستطبّق الأنماط الموجودة في المفتاح الحركي الأول بمجرد أن يتم تعريفها، وقبل انطلاق تأثير الحركة، وهذا يتضمن تطبيق تلك الأنماط خلال مدة التأخير المحدّدة لتأثير الحركة. إلى جانب ذلك، فإنّ القيمة backwards قد تتأثّر بقيمة الخاصّية animation-direction. وأخيرًا، فإنّ القيمة both تجمع في عملها بين عمل القيمتين السابقتين. .stage:hover .ball { animation-name: slide; animation-duration: 2s; animation-timing-function: ease-in-out; animation-delay: .5s; animation-fill-mode: forwards; } .stage:active .ball { animation-play-state: paused; } (تجربة حية) صيغة مختصرة لتأثيرات الحركة كما هو الحال مع تأثيرات الانتقال، هناك صيغة مختصرة لتعريف تأثيرات الحركة، ويتم ذلك من خلال استخدام الخاصية animation بدلًا من تعريف القيم واحدة تلو الأخرى. وتأخذ القيم التابعة لهذه الخاصية الترتيب التالي: animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode, وأخيرًا animation-play-state. .stage:hover .ball { animation: slide 2s ease-in-out .5s infinite alternate; } .stage:active .ball { animation-play-state: paused; } (تجربة حية) ترجمة - وبتصرّف - للمقال Transitions & Animations لصاحبه Shay Howe.
-
- 1
-
- transition
- animation
-
(و 1 أكثر)
موسوم في:
-
مواقع الويب الحديثة أصبحت أكثر ديناميكية مؤخرا، عبر استخدام Javascript لتزويد المستخدم بتحديثات مباشرة ومتحكمات أكثر سلاسة. أحد أكثر المميزات شيوعا هي إظهار وإخفاء المحتوى، سواءا كان على شكل تبويبات، مخفيا على جانب الصفحة، أو على شكل قائمة متعددة المستويات. عادة، هذه المميزات يتم تطبيقها عبر Javascript فحسب، ولكنك تستطيع القيام بنفس التأثيرات عبر CSS3 بدون اللجوء إلى Javascript. في هذه المقالة سنرى كيف يمكننا تحقيق ذلك، مع تضمين بعض الأمثلة. المحتوى مثال بسيط حل حقيقي الإخفاء والإظهار عبر CSS تحسين القائمة دعم المتصفحات مثال بسيط هذا مثال بسيط يظهر كيف يمكن إخفاء وإظهار المحتوى عبر CSS: See the Pen &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;gt;YXKgRz&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Nadir (&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;gt;@assassinateur&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io' href='http://codepen.io'&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. عندما نضغط على زر إخفاء، سيختفي الزر إلى جانب القائمة في الأسفل، ويظهر زر "إظهار". وإذا شاهدت نسخة الطباعة من الصفحة، فستلاحظ أنّ الأزرار لن تظهر. الآن بعد مشاهدتنا للمثال، لنلقي نظرة على ما استخدمنا والتقنيات الكامنة خلف ذلك، ونبني قائمة بينما نحن نقوم بذلك. حل حقيقي نستطيع استخدام الحل الذي سنطوره في إحدى الحالات التالية: نريد أن تجعل محتوى معين يظهر ويختفي في مكان معين (مثل قوائم المحتوى في ويكيبيديا) لسبب ما، قد لا نريد استعمال جافاسكربت لنبدأ بمشاهدة حل يستخدم جافاسكربت؛ قسم المحتوى في مقالة ما في ويكيبديا See the Pen &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;gt;rVBbMR&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Nadir (&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;gt;@assassinateur&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io' href='http://codepen.io'&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. المثال السابق مأخوذ من صفحة ويكيبيديا (هو مجرد HTML رغم هذا)، يعمل الجدول عبر إخفاء المحتوى، وتغيير الكلمة من "أخفي" إلى "أظهر" ويتم هذا عبر جافاسكربت. يتم إضافة تسجيل مراقب للزر (Event Listener)، عندما يتم الضغط على الزر، يقوم jQuery بإضافة class جديد للصندوق، يتم أيضا إَضافة واحد لحاوي الروابط، كما يتم تغيير محتوى الزر من "أخفي" إلى "أظهر". الإخفاء والإظهار عبر CSS سنحاول إعادة صنع قائمة ويكيبيديا، ولكن عبر CSS فحسب، فسنفقد بعض المميزات، ولكننا سنكسب بعض الأمور في نفس الوقت. يستطيع رابط ما أن يأخذك لأيّ جزء من الصفحة عبر تحديد ID الخاص به كمكان اتجاه للرابط. في المثال سنستخدم شيئا مشابها، ولكن ليس للتصفح، بل لإظهار وإخفاء المحتوى. نستخدم الكود في الأسفل ثم نشرحه. See the Pen &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;gt;oXvOZb&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Nadir (&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;gt;@assassinateur&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io' href='http://codepen.io'&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&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;lt;a data-cke-saved-href='http://codepen.io/assassinateur/pen/pJzBWQ/' href='http://codepen.io/assassinateur/pen/pJzBWQ/'&amp;amp;amp;amp;amp;gt;pJzBWQ&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt; by Nadir (&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;gt;@assassinateur&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;) on &amp;amp;amp;amp;amp;lt;a data-cke-saved-href='http://codepen.io' href='http://codepen.io'&amp;amp;amp;amp;amp;gt;CodePen&amp;amp;amp;amp;amp;lt;/a&amp;amp;amp;amp;amp;gt;. ملاحظة: حالما تضغط على شيء آخر، يعود كل شيء كما كان وهذا هو التصرف الطبيعي لشبه الصنف :focus ولكنه ليس الأمر الذي نريده نحن. هذه المشكلة ليست موجودة في مثال ويكيبيديا بكل تأكيد، كما أن ويكيبيديا تستخدم الـcookies لتتذكر آخر حالة للقائمة حتى بعد تحديث الصفحة، وهو شيء لا نستطيع تحقيقه للأسف. خاتمة استطعنا القيام ببعض التأثيرات البصرية باستخدام CSS لوحدها عبر تعلم كيفية إخفاء وإظهار العناصر، هناك محددات واعدة أكثر ستظهر مستقبلا، وستتيح لنا التحكم أكثر وأكثر في العناصر وتحديدها بسهولة، احدى الخدع التي يمكن استخدامها هي استخدام checkbox بدل الروابط من أجل تغيير حالة الصندوق، ولكن كان هذا ليجعل الأمر أكثر تعقيدا. حقوق الصورة البارزة محفوظة لـ Freepik
-
- css3
- javascript
-
(و 2 أكثر)
موسوم في:
-
رغم أنّ تحويلات CSS3 ثلاثية الأبعاد صار لها فترةً لا بأس بها من الزمن، إلّا أنّني اكتشفت عدم امتلاك الخبرة الكافية للعمل معها بعد. أستخدم Windows 8 منذ فترة من الوقت، ومن أوّل الأمور التي لفتت نظري كانت الانتقالات transitions والتحريكات animations المبنية ضمن لوح البداية Start Dashboard، لذلك خطرت ببالي فكرة رائعة، وهي لماذا لا تكون خبرتي الأولى مع تحويلات CSS3 ثلاثية البعد ببناء تطبيق يماثل في سلوكه تلك التحريكات والتأثيرات في Windows 8؟ وهذا ما حدث في هذا الدرس. سأستخدم خصائص CSS بدون أي بادئة prefix وذلك بغرض الاختصار، لكنك ستجد الخصائص كاملة ضمن النص المصدري للمشروع على Github. ستعمل مقاطع الشيفرة التي ستجدها هنا على متصفحات تدعم خصائص CSS المستخدمة. الرماز The Markupبنية هذا التطبيق بسيطة: يتكون لوح البداية من قائمة من القطع tiles بثلاثة قياسات وهي الصغير، الكبير، والكبير جدًا. لكل قطعة من هذه القطع صفحة page مرتبطة معها. والصفحة عبارة عن تغطية overlay تظهر عند النقر على إحدى القطع في لوح البداية. سنعتبر الصفحة أنّها تُحاكي تطبيق سطح مكتب في Windows 8، فتكون القطعة كما هو واضح اختصارًا له (للصفحة). عند النقر على قطعة ستُفتح الصفحة الموافقة لها. يوجد نوعان من الانتقالات للصفحة بعد فتحها يدعمهما اللوح في Windows 8. يفتح أحدهما الصفحة بتأثير دوران ثلاثي الأبعاد اعتبارًًا من يمين الشاشة، أمّا الآخر فتنزلق فيه الصفحة من وإلى اليسار. سنعرّف صنف CSS لكل نوع من نوعيّ الصفحة، حيث سيكون الصنف s-page للصفحات التي تنزلق من وإلى اليسار، أمّا الصنف r-page فسيكون للصفحات التي تدور من اليمين. ينبغي علينا من أجل كل قطعة تعيين نوع الصفحة التي ستفتحها القطعة (بالاعتماد على التأثير الذي نريده من أجل هذه الصفحة). سنعرّف نوع الصفحة لكلّ قطعة باستخدام سمة attribute مخصّصة سنسميها data-type-page، ستهتم هذه الـسمة بتطبيق أسماء أصناف CSS الصحيحة التي ستفعّل التحريكات المناسبة فيما بعد. يجب أن يكون لكل صفحة اسم. سيختلف اسم الصفحة لتطبيق معيّن عن اسم الصفحة لتطبيق آخر، فمثلًا الـقطعة المسمّاة Skype ستفتح صفحة اسمها skype-app وهكذا دواليك. لقد استخدمت اسميّ صفحة فقط في هذا المثال، وقد كرّرتهما من أجل جميع الـقطع الباقية بغرض التبسيط، كما استخدمت الاسم custom-page لآخر قطعة وذلك على سبيل المثال. ربما تحتاج أن تضيف صفحة مختلفة لكل قطعة، وهذا يعني اسم صفحة مختلف لكلٍّ منها. إليك الرماز الخاص بكامل اللوح (الـقطع والصفحات): <div class="demo-wrapper"> <div class="s-page random-restored-page"> <div class="page-content"> <h2 class="page-title">Some minimized App</h2> <div class="close-button s-close-button">x</div> </div> </div> <div class="s-page custom-page"> <div class="page-content"> <h2 class="page-title">Thank You!</h2> <div class="close-button s-close-button">x</div> </div> </div> <div class="r-page random-r-page"> <div class="page-content"> <h2 class="page-title">App Screen</h2> <p>Chew iPad power cord chew iPad power cord attack feet chase mice leave dead animals as gifts and stick butt in face chew iPad power cord. Chase mice. Run in circles use lap as chair why must they do that. Intrigued by the shower destroy couch leave hair everywhere sleep on keyboard chew iPad power cord. Use lap as chair. Missing until dinner time stand in front of the computer screen, intently sniff hand. Find something else more interesting. Destroy couch play time so inspect anything brought into the house hate dog burrow under covers. Sleep on keyboard destroy couch so hate dog so hide when guests come over. Chase mice destroy couch lick butt throwup on your pillow use lap as chair yet intrigued by the shower but climb leg. Stare at ceiling make muffins or hunt anything that moves claw drapes. Intently sniff hand intrigued by the shower. Why must they do that. Cat snacks leave dead animals as gifts or inspect anything brought into the house sweet beast so stare at ceiling give attitude. Flop over claw drapes but sun bathe lick butt, and chase mice. Rub face on everything lick butt leave hair everywhere lick butt, missing until dinner time for use lap as chair lick butt. Make muffins leave dead animals as gifts play time. Chew foot intrigued by the shower stare at ceiling inspect anything brought into the house yet hopped up on goofballs. Hunt anything that moves intently sniff hand for hunt anything that moves play time. Chew foot climb leg throwup on your pillow so lick butt yet make muffins hate dog. Intrigued by the shower. Intently sniff hand shake treat bag. Cat snacks burrow under covers make muffins but all of a sudden go crazy find something else more interesting. Flop over chase mice. Give attitude. Inspect anything brought into the house. Stick butt in face sun bathe so find something else more interesting and intrigued by the shower. Rub face on everything use lap as chair. Under the bed claw drapes chase mice but leave hair everywhere yet make muffins yet claw drapes. Use lap as chair. Find something else more interesting stretch for under the bed. Nap all day intrigued by the shower, hate dog sweet beast intently sniff hand so hate dog nap all day. Swat at dog hide when guests come over and mark territory chase mice for cat snacks. Use lap as chair. Lick butt throwup on your pillow need to chase tail. Mark territory. Stick butt in face shake treat bag yet hunt anything that moves, yet hopped up on goofballs yet stare at ceiling under the bed. Give attitude chase imaginary bugs stretch so hunt anything that moves so hide when guests come over but intrigued by the shower find something else more interesting. Make muffins behind the couch for chew foot. Sweet beast flop over but throwup on your pillow. Intently sniff hand use lap as chair and missing until dinner time and chase imaginary bugs. </p> </div> <div class="close-button r-close-button">x</div> </div> <div class="dashboard clearfix"> <ul class="tiles"> <div class="col1 clearfix"> <li class="tile tile-big tile-1 slideTextUp" data-page-type="r-page" data-page-name="random-r-page"> <div><p>This tile's content slides up</p></div> <div><p>View all tasks</p></div> </li> <li class="tile tile-small tile tile-2 slideTextRight" data-page-type="s-page" data-page-name ="random-restored-page"> <div><p class="icon-arrow-right"></p></div> <div><p>Tile's content slides right. Page opens from left</p></div> </li> <li class="tile tile-small last tile-3" data-page-type="r-page" data-page-name="random-r-page"> <p class="icon-calendar-alt-fill"></p> </li> <li class="tile tile-big tile-4" data-page-type="r-page" data-page-name="random-r-page"> <figure> <img src="images/blue.jpg" /> <figcaption class="tile-caption caption-left">Slide-out Caption from left</figcaption> </figure> </li> </div> <div class="col2 clearfix"> <li class="tile tile-big tile-5" data-page-type="r-page" data-page-name="random-r-page"> <div><p><span class="icon-cloudy"></span>Weather</p></div> </li> <li class="tile tile-big tile-6 slideTextLeft" data-page-type="r-page" data-page-name="random-r-page"> <div><p><span class="icon-skype"></span>Skype</p></div> <div><p>Make a Call</p></div> </li> <li class="tile tile-small tile-7 rotate3d rotate3dX" data-page-type="r-page" data-page-name="random-r-page"> <div class="faces"> <div class="front"><span class="icon-picassa"></span></div> <div class="back"><p>Launch Picassa</p></div> </div> </li> <li class="tile tile-small last tile-8 rotate3d rotate3dY" data-page-type="r-page" data-page-name="random-r-page"> <div class="faces"> <div class="front"><span class="icon-instagram"></span></div> <div class="back"><p>Launch Instagram</p></div> </div> </li> </div> <div class="col3 clearfix"> <li class="tile tile-2xbig tile-9" data-page-type="custom-page" data-page-name="random-r-page"> <figure> <img src="images/summer.jpg" /> <figcaption class="tile-caption caption-bottom">Fixed Caption: Some Subtitle or Tile Description Goes Here with some kinda link or anything </figure> </li> <li class="tile tile-big tile-10" data-page-type="s-page" data-page-name="custom-page"> <div><p>Windows-8-like Animations with CSS3 & jQuery © Sara Soueidan. Licensed under MIT.</p></div> </li> </div> </ul> </div> </div>حصلت على خط الأيقونة الذي استخدمته من Icomoon. الذي سيحدث الآن: ستحصل JavaScript على اسم ونوع الصفحة المراد فتحها عند نقر القطعة، وبعد ذلك، ووفقًا لنوع الصفحة ستعمل JavaScript على تطبيق أسماء أصناف CSS المناسبة على الصفحة (والتي سنحصل على اسمها أيضًا من السمة data-page-name) لفتحها بنمط تحريك معيّن لكل صنف CSS يتم تطبيقه. تنسيقات CSSأرجو ملاحظة أنّني أستخدم أنماط تنسيق تراعي الأجهزة المحمولة أولًا mobile-first، والتي سنجعلها لاحقًا ذات استجابية responsive عالية ضمن قسم استعلامات الوسائط media queries في CSS. سنتناول في البداية التنسيقات الخاصة بالحاوية (عنصر div) والتي ستحوي كامل المثال التوضيحي. سنعرّف تنسيقات عامّة ونتأكّد من ضبط الخاصية perspective بحيث يؤدي ذلك إلى تفعيل الفضاء ثلاثي البعد 3D، وإلّا سيبدو كامل المثال بشكل منبسط أي ثنائي البعد 2D. .demo-wrapper { padding: 2em .5em; width: 100%; height:100%; perspective: 3300px; position: relative; }لنبدأ الآن بتنسيقات وتحريكات لوح البداية. ستُنفَّذ أوّل تحريكة سنطبّقها على لوح البداية عند تحميل الصفحة ضمن متصفّح الويب. سيكون لوح البداية مخفيًّا في يمين الشاشة بادئ الأمر، ثمّ يظهر تدريجيًّا مع الانتقال إلى موقعه الأساسي عند تحميل الصفحة. .dashboard { margin: 0 auto; width: 100%; padding: 1em; transform: translateX(200px); opacity:0; animation: start 1s ease-out forwards; } @keyframes start{ 0%{ transform: translateX(200px); opacity:0; } 50%{ opacity:1; } 100%{ transform: translateX(0); opacity:1; } }يتضاءل لوح البداية ويختفي عند نقر قطعة منه. حيث ينتقل اللوح على طول محور z، ويتضاءل حجمه، كما تنخفض قيمة الخاصية opacity له تدريجيًا حتى تصبح في النهاية تساوي الصفر مما يعطي شعورًا بأنّ اللوح يختفي بالتدريج. أمّا عندما يُغلق المستخدم الصفحة فإنّ لوح البداية يعود للظهور مرّة أخرى. بالنسبة للأعمدة الثلاثة في لوح البداية فإنّها تظهر تدريجيًّا واحدًا تلو الآخر مع تأخير زمني طفيف بينها. عندما تُغلق الصفحة، سيُضاف اسم صنف CSS لكل عمود (بواسطة JavaScript) وكل من هذه الأصناف ستُفعّل تحريكة بتأخير زمني مُحدّد. فيما يلي أصناف CSS والتحريكات المطبّقة على لوح البداية عند نقر القطع tiles وإغلاق الصفحات. .fadeOutback{ animation: fadeOutBack 0.3s ease-out 1 normal forwards; } .fadeInForward-1, .fadeInForward-2, .fadeInForward-3 { opacity:0; transform: translateZ(-5em) scale(0.75); animation: fadeInForward .5s cubic-bezier(.03,.93,.43,.77) .4s normal forwards; } .fadeInForward-2{ animation-delay: .55s; } .fadeInForward-3{ animation-delay: .7s; } @keyframes fadeOutBack{ 0% {transform: translateX(-2em) scale(1); opacity:1;} 70% {transform: translateZ(-5em) scale(0.6); opacity:0.5;} 95% {transform: translateZ(-5em) scale(0.6); opacity:0.5;} 100% {transform: translateZ(-5em) scale(0); opacity:0;} } @keyframes fadeInForward{ 0% {transform: translateZ(-5em) scale(0); opacity:0;} 100% {transform: translateZ(0) scale(1); opacity:1;} }وبالنسبة لتنسيقات الصفحات: .r-page { width: 100%; height: 100%; text-align: center; font-size: 2em; font-weight: 300; position: absolute; right: 0; top: 0; left:0; bottom:0; opacity: 0; color: white; z-index: 10; padding:10px; transform-origin: 100% 0%; transform: rotateY(-90deg) translateZ(5em) } .s-page { color: white; z-index: 10; text-align: center; font-size: 2em; font-weight: 300; } .page-content{ overflow-y:auto; max-height:100%; font-size:.6em; padding:.6em; text-align:left; } .s-page, .r-page{ background-color: white; color:black; } .page-title { margin: .25em 0; font-weight: 100; font-size: 3em; text-align:center; } .close-button { font-size: 1.5em; width: 1em; height: 1em; position: absolute; top: .75em; right: .75em; cursor: pointer; line-height: .8em; text-align: center }لقد ضبطت الموقع الأصلي لكل صفحة من النوع r-page في الفضاء ثلاثي البعد بتدويرها حول محور التراتيب (محور y) بعد ذلك نقل الصفحة بمقدار 5em إلى يسار الشاشة باستخدام الخاصية translateZ (النقل على محور z). ينبغي ألّا ننسى أنّه عند تحويل (نقل – تدوير) عنصر في الفضاء ثلاثي البعد فمن الضروري تحويل نظام الإحداثيات الخاص به بنفس الصورة. الذي نريده الآن هو نقل الصفحة بمقدار 5em إلى يسار الشاشة، ولكن لاحظ أنّنا بدلًا من استخدام translateX استخدمنا translateZ، ويعود سبب ذلك إلى أنّه بعد التحويل الأوّل (الدوران حول محور y) يدور نظام الإحداثيات أيضًا، وهكذا يُشير محور z في هذه الحالة إلى اليسار وليس إلى الأعلى، أمّا محور الفواصل (محور x) فسيشير باتجاه المستخدم. يكون لجميع الصفحات باستثناء النوع s-page نفس موقع البداية في الفضاء ثلاثي البعد. بالنسبة للصفحات من النوع s-page فإنّها تكون بموقع يبعد بما يُعادل -150% يسار الشاشة (واضح أنّها لن تكون مرئية بهذه الحالة)، بحيث أنّها تنزلق لتعود إلى الشاشة عند تفعيل التحريكة الخاصة بها. عند نقر قطعة مرتبطة بصفحة ما، فسيُضاف صنف CSS الموافق بواسطة JavaScript إلى الصفحة، بالنتيجة ستحصل الصفحة على اسم صنف CSS يُعرّف التأثير ثلاثي البعد الواجب تطبيقه عليها. فيما يلي أسماء أصناف CSS التي تُفعّل عملية فتح وإغلاق الصفحات، بالإضافة إلى التحريكات المعرّفة من أجل كل صنف. .openpage{ animation: rotatePageInFromRight 1s cubic-bezier(.66,.04,.36,1.03) 1 normal forwards; } .slidePageLeft{ transform: rotateY(0) translateZ(0); opacity: 1; animation:slidePageLeft .8s ease-out 1 normal forwards; } .slidePageInFromLeft{ animation: slidePageInFromLeft .8s cubic-bezier(.01,1,.22,.99) 1 0.25s normal forwards; } .slidePageBackLeft{ opacity: 1; left: 0; animation: slidePageBackLeft .8s ease-out 1 normal forwards; }لاحظ أنّني أستخدم الخاصية animation بالشكل المختصر. تعود القيمة الأخيرة forward ضمن الخاصية animation إلى الخاصيّة الفرعية animation-fill-mode، وهذه القيمة ضرورية لها، وإلّا ستعود الصفحة إلى حالتها الابتدائية (المغلقة) فور انتهاء التحريكة التي ستُظهر الصفحة. إذًا لكي نُبقي الصفحة مفتوحة، ولكي نكون قادرين على إنشاء تحريكات متلاحقة، يجب على العنصر أن يبقى مُحتفظًا بحالته النهائية المعرّفة ضمن تحركية ما، ومن هذه "الحالة النهائية" يبدأ عمل التحريكة التالية، وهكذا. فيما يلي التحريكات لأصناف CSS المطبّقة على الصفحات. @keyframes rotatePageInFromRight{ 0% {transform:rotateY(-90deg) translateZ(5em);opacity:0} 30% {opacity:1} 100% {transform: rotateY(0deg) translateZ(0) ; opacity:1} } @keyframes slidePageLeft{ 0% {left:0; transform: rotateY(0deg) translateZ(0) ; opacity:1} 70% {opacity:1;} 100% {opacity:0; left:-150%; transform: rotateY(0deg)} } @keyframes slidePageInFromLeft{ 0% {opacity:0; } 30% {opacity:1} 100% {opacity:1; left:0;} } @keyframes slidePageBackLeft{ 0% {opacity:1; left:0; transform: scale(0.95);} 10% {transform: scale(0.9);} 70% {opacity:1;} 100% {opacity:0; left:-150%;} }أخيرًا وليس آخرًا، سنُنسّق قطع لوح البداية ونُعرّف الانتقالات والتحريكات المطبّقة عليها عند تحريك مؤشّر الفأرة فوقها. لاحظ أنّ التنسيقات العامّة تُعرّف حجم القطع. .tile{ float: left; margin: 0 auto 1%; color: white; font-size: 1.3em; text-align: center; height: 8em; font-weight: 300; overflow: hidden; cursor: pointer; background-color: #fff; color: #333; position:relative; transition: background-color 0.2s ease-out } .tile-2xbig{ height:16.15em; width:100%; } .tile-big { width: 100% } .tile-small { width: 49%; margin-right: 2% } .tile-small.last { margin-right: 0 }سيحتوي زوج من القطع على صورة مع عنوان لها، هاتان القطعتان ستحصلان على الصنف fig-tile وذلك لتمييز نوعهما في شيفرة JavaScript التي سنراها لاحقًا. سنحصل على الألوان المستخدمة من أجل النص والخلفية لصفحة ما من الألوان المستخدمة في العنوان، لذلك لا تنسى أن تُعرّفهم. بالنسبة للعنوان إمّا أن يكون ثابتًا أو أن يُعطي شعورًا بالانزلاق عندما يتحرك فوقه مؤشّر الفأرة: .tile-caption{ position:absolute; z-index:1; background-color: #455962; color:#fff; font-size:1em; padding:1em; text-align: left; } .caption-bottom{ left:0; bottom:0; right:0; height:40%; } .caption-left{ left:-100%; top:0; bottom:0; width:40%; transition: left .3s linear; } .tile:hover .caption-left{ left:0; }بالنسبة للقطع النظامية regular tiles التي لا تملك أي نوع من التحريك، فستغيّر لون خلفيّتها ولون النص عند تحريك الفأرة فوقها. لكي نتأكّد من أنّ النص مُوسّط عموديًا vertically centered في كل قطعة، سنضع في كل قطعة عنصر div يحوي بدوره عنصر فقرة (العنصر <p>) يحوي النص. سنستخدم القيمة table-cell للخاصية display وذلك لتوسيط النص عموديًا ضمن الفقرة: .tile div{ position:absolute; top:0; left:0; right:0; bottom:0; width:100%; height:100%; text-align:center; display:table; padding:0 1em; transition: all .3s ease; } .tile div p{ display:table-cell; vertical-align:middle; }سنترك الحديث عن أنماط التنسيق العامّة للقطع بهدف الاختصار، ولكن ينبغي علينا التأكّد من أنّنا سنعيّن لون النص والخلفية لجميع القطع، حتى تلك التي ستُغطّى بصورة، لأنّ هذه الألوان التي سنحصل عليها باستخدام JavaScript ستُستخدَم لضبط الألوان في الصفحة المرتبطة بها كما أشرنا قبل قليل. دعونا الآن نتحدّث عن التحريكات والانتقالات التي تحدث على قطعة ما. ستحتوي القطع المزوّدة بنص منزلق على عنصري div، سيبدو كل عنصر div كوجه أو كتلة منفصلة داخل القطعة. سيكون تموضعًا عنصريًا div مطلقًا positioned absolutely وسيتحرّكان عند تحرّك الفأرة فوقهما وذلك وفقًا لاتجاه الانزلاق المطلوب. فلكي ينزلق نص القطعة إلى الأعلى عندما يحوم مؤشّر الفأرة فوقه سنطبّق الصنف slideTextUp: .slideTextUp div:nth-child(2){ top:100%; } .slideTextUp:hover div{ transform: translateY(-100%); } .tile-1 p{ font-size:1.3em; }وبشكل مماثل ولكي ينزلق نص القطعة إلى اليسار وإلى اليمين سنطبّق الصنفين slideTextLeft و slideTextRight على الترتيب. .slideTextRight div:first-child{ left:-100%; } .slideTextRight:hover div{ transform: translateX(100%); } .slideTextLeft div:nth-child(2){ left:100%; } .slideTextLeft:hover div{ transform: translateX(-100%); }أمّا بالنسبة لزوج القطع التي ستنقلب، فسيكون لهما تأثير مختلف عندما يحوم مؤشّر الفأرة فوقهما، فهما يدوران ليُظهران الوجه الخلفي. يُعتبر هذا التأثير نوعًا بسيطًا جدًا من تأثير "انقلاب البطاقة" card flip. لن نخوض في تفاصيل هذا التأثير. لإنجاز هذا التأثير، سنطبّق الصنف rotate3d إلى القطعة التي نريد أن تنقلب. بالنسبة للقطعة التي نريد أن تنقلب عموديًّا، سنطبّق الصنف rotate3dy، أمّا بالنسبة للانقلاب الأفقي سنطبّق الصنف rotate3dx (مع الانتباه إلى وجوب وجود الصنف rotate3d في كلتا الحالتين). انظر إلى تنسيقات CSS التالية: .rotate3d{ perspective: 800px; overflow: visible; } .faces{ transform-style: preserve-3d; transition: transform 1s; } .faces div { display: block; position: absolute; top:0; left:0; right:0; bottom:0; width: 100%; height: 100%; backface-visibility: hidden; }لاحظ بأنّه عند تحريك مؤشّر الفأرة فوقهما بالتتالي، فسيظهر وجه أحدهما في حين ستظهر خلفية الآخر بنفس الوقت. .rotate3dY .back{ transform: rotateY( 180deg ); } .rotate3dX .back{ transform: rotateX( 180deg ); }وعندما يحوم مؤشّر الفأرة فوق القطعة فإنّ أي عنصر div يخضع للصنف faces. سيُدوّر ليُظهر وجهه الخلفي: .rotate3dY:hover .faces:hover{ transform: rotateY( 180deg ); } .rotate3dX:hover .faces:hover{ transform: rotateX( 180deg ); } لتنسيق القطع في الدوران ثلاثي البعد، ينبغي الانتباه إلى ضبط لوني الخلفية والنص للوجه الأمامي (ذو الصنف front.) بحيث يمكن الحصول على هذين اللونين واستخدمهما لاحقًا في الصفحة المتربطة بالقطعة عند فتحها. لنعرّف الآن تنسيقات تفاعلية للوح Dashboard. ستكون أعمدة اللوح ذات عرض كامل على الشاشات الصغيرة في البداية (تذكّر أنّنا نراعي متطلبات تصميم الأجهزة المحمولة أولًا mobile-first)، في حين أنّ هذه الأعمدة ستكون بجانب بعضها البعض في الشاشات الكبيرة. .col1, .col2, .col3 { width: 99%; margin: 1em auto } @media screen and (min-width: 43.75em) { .col1, .col2, .col3 { float: left; margin-right: 1%; width: 49% } .page-title{ font-size:2.5em; } .page-content{ font-size:1em; } .close-button{ font-size:2em; } } @media screen and (min-width: 64em) { .col1, .col2, .col3 { float: left; margin-right: .5%; width: 31% } .col3 { margin-right: 0 } .col1 { margin-left: 2em } .page-title{ font-size:3.5em; } } جافا سكريبت JavaScriptستُعالَج جميع أحداث النقر عن طريق JavaScript. سنستخدم مكتبة jQuery لهذه الغاية، وسنضبط معالج حدث event handler النقر لكل قطعة على لوح البداية، فعندما ينقر المستخدم على قطعة ما، يعمل معالج حدث النقر الموافق على الحصول على اسم ونوع الصفحة المرتبطة بهذه القطعة وذلك من السمتين data-page-name و data-page-type على الترتيب، حيث سنستخدم هذه المعلومات لفتح الصفحة المطلوبة. أمّا عند إغلاق الصفحة عند النقر زر الإغلاق لها، فسيعمل معالج حدث النقر لهذا الزر على تطبيق أسماء الأصناف المناسبة لإغلاق الصفحة. بالإضافة لذلك، ولكي نُكسِب كل صفحة لون خلفية ولون نص مماثل لتلك التي للقطعة المرتبطة بها، فإنّنا سنطوف بدايةً على جميع القطع، ونحصل على ألوانها، ثمّ نُطبّق هذه الألوان على الصفحات المرتبطة معها. في حال كان لقطعة ما الصنف rotate3d، فإنّنا سنبحث عن لون الخلفية لوجه face القطعة، ومن ثمّ نطبّق هذا اللون على الصفحة المرتبطة معها. function(){ $('.tile').each(function(){ var $this= $(this), page = $this.data('page-name'), bgcolor = $this.css('background-color'), textColor = $this.css('color'); if($this.hasClass('rotate3d')) { frontface = $this.find('.front'); bgcolor = frontface.css('background-color'); textColor = frontface.css('color'); } if($this.hasClass('fig-tile')) { caption = $this.find('figcaption'); bgcolor = caption.css('background-color'); textColor = caption.css('color'); } $this.on('click',function(){ $('.'+page).css({'background-color': bgcolor, 'color': textColor}) .find('.close-button').css({'background-color': textColor, 'color': bgcolor}); }); }); function showDashBoard(){ for(var i = 1; i <= 3; i++) { $('.col'+i).each(function(){ $(this).addClass('fadeInForward-'+i).removeClass('fadeOutback'); }); } } function fadeDashBoard(){ for(var i = 1; i <= 3; i++) { $('.col'+i).addClass('fadeOutback').removeClass('fadeInForward-'+i); } } $('.tile').each(function(){ var $this= $(this), pageType = $this.data('page-type'), page = $this.data('page-name'); $this.on('click',function(){ if(pageType === "s-page"){ fadeDashBoard(); $('.'+page).addClass('slidePageInFromLeft').removeClass('slidePageBackLeft'); } else{ $('.'+page).addClass('openpage'); fadeDashBoard(); } }); }); $('.r-close-button').click(function(){ $(this).parent().addClass('slidePageLeft') .one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function(e) { $(this).removeClass('slidePageLeft').removeClass('openpage'); }); showDashBoard(); }); $('.s-close-button').click(function(){ $(this).parent().removeClass('slidePageInFromLeft').addClass('slidePageBackLeft'); showDashBoard(); }); })();وبهذا نكون قد وصلنا إلى نهاية الدرس. أرجو أن يكون ممتعًا ومفيدًا. بإمكانك استعراض مثال حيّ لهذا الدّرس من هنا. أما الشيفرة المصدرية فهي مُتوفّرة في هذا المُستودع. ترجمة -وبتصرّف- للمقال How to Create Windows-8-like animations with CSS3 and JQuery لصاحبته Sara Soueidan.
-
عند استخدام التحريكات animations والانتقالات transitions ضمن واجهة المستخدم، فإنّه من الضروري أن يكون لها هدف واضح ومحدّد، ألا وهو تحسين تجربة المستخدم. تؤمّن لنا الانتقالات transitions الوسيلة المناسبة والمثالية لجعل الحركة سلسة وانسيابية أمام المستخدم. بدون تأثيرات الانتقال من الممكن أن يصبح المستخدم في حيرة من أمره حول الذي حدث بالضبط عند تنفيذه لأمر معين. في هذا المقال، سننشئ بعض التحريكات والانتقالات الإبداعية لإضافة وإزالة عناصر من قائمة، لقد أعجبتني الفكرة الواردة في مقال باسكويل دي سيلفيا. أمّا بالنسبة للشيفرة المسؤولة عن الإنتقالات في مقال باسكويل، فقد كتبه كريس كوير. سأعمل على تطوير المثال الوارد في مقال باسكويل، وذلك بإضافة المزيد من تأثيرات الانتقالات والتحريكات، وسأستخدم أيضاً شيفرة صغيرة من مقال كريس لإضافة خطوة إضافية في كل تحريكة، تتمثل بحجز مكان للعناصر المراد إضافتها إلى القائمة قبل إضافتها فعلياً. سأستخدم خصائص CSS بدون أي بادئة prefix وذلك بغرض الاختصار، لكنك ستجد الخصائص كاملة ضمن النص المصدري للمشروع على Github. ستعمل مقاطع الشيفرة التي ستجدها ضمن هذا الدرس على متصفحات تدعم خصائص CSS المستخدمة. لنبدأ العمل! الرماز The Markupلتوضيح فكرة الدرس بشكل جيد، أنشأت تطبيقاً بسيطاً خاصاً بالملاحظات البسيطة. يستخدم هذا التطبيق تقنية التخزين المحلي LocalStorage التي توفرها HTML5 وذلك لحفظ الملاحظات ضمن التخزين المحلي لمتصفح ويب لديك. يسمح لك التطبيق بأخذ ملاحظات وحفظها ضمن المتصفح إن أردت ذلك، في الحقيقة هو السبب الذي من أجله بنيت هذا التطبيق، وذلك من أجل ملاحظاتي الخاصة. لن أخوض في تفاصيل كيفية بناء هذا التطبيق لأنّ ذلك ليس هدف هذا الدرس. الرُماز markup المستخدم في هذا التطبيق هو مجرد نموذج form بسيط يحتوي على حقل نصي text field وزر إرسال submit button، بالإضافة إلى قائمة غير مرتّبة unordered list. ستُضاف الملاحظات إلى هذه القائمة بشكل تلقائي. كما يوجد أيضاً عنصري div لعرض التنبيهات، التي ستظهر عند حفظ أو إزالة أي عنصر، بالإضافة إلى عدّاد وزر لحذف جميع العناصر بنقرة واحدة. فيما يلي جميع رُماز HTML الذي سنحتاجه: <div class="notification undo-button"> Item Deleted. Undo? </div> <div class="notification save-notification"> Item Saved </div> <div class="reminder-container"> <header> <h1>mini reminders list</h1> </header> <form id="input-form"> <input type="text" id="text" placeholder="Remind me to.."/> <input type="submit" value="Add" /> </form> <ul class="reminders"> </ul> <footer> <span class="count"></span> <button class="clear-all"> Delete All </button> </footer> </div>يمكنك إضافة وتحرير وإزالة العناصر (الملاحظات) بالإضافة إلى إمكانية إستعادة العنصر المحذوف. في الواقع، تأتي أغلب التحريكات مرافقة لعملية إزالة وإستعادة العناصر. تُعتبر عملية إضافة العناصر بسيطة ولا تترافق مع الكثير من التحريكات، باستثناء التحريك الخاص بالظهور التدريجي fade in والسقوط إلى أسفل falling down واللذان سنتحدث عنهما عندما نبدأ العمل مع CSS. تنسيقات CSSستحصل العناصر المُضافة توّاً عن طريق JavaScript على الصنف new-item. (صنف CSS). أمّا العناصر المُزالة فستحصل على الصنف removed-item. كما ستحصل العناصر المُستعادة على الصنف restored-item. وكل صنف من الأصناف السابقة سيُفعّل التحريكات الخاصة به. ستبقى أسماء الأصناف السابقة ثابتةً لجميع الأمثلة التوضيحية، في حين ستختلف فيما بينها بالتوجيه المسؤول عن مظهر التحريك keyframes@. لنبدأ الآن بالمثال التوضيحي الأول. المثال الأول المثال الأول: العناصر المُزالة "تسقط إلى أسفل"، والعناصر المُستعادة ستعود بحركة معاكسة. ستسقط العناصر المضافة حديثاً من الأعلى، وهذا تأثير بسيط لكنه جميل. سيبدأ كل عنصر مُضاف حديثاً بالسقوط إلى أسفل وذلك من موقع يعلو 400 بيكسل عن الموقع النهائي الذي سيستقر فيه (أي الموقع النهائي ناقص 400 بيكسل) لا تنس أنّه يجب على الخاصية الفرعية animation-fill-mode أن تحمل القيمة forwards وذلك للتأكّد من أنّ العناصر ستبقى في موقعها النهائي ضمن القائمة، وإلّا فإنّها ستختفي بمجرّد انتهاء عملية التحريك. li.new-item { opacity: 0; animation: new-item-animation .3s linear forwards; } @keyframes new-item-animation { from { opacity: 0; transform: translateY(-400px); } to { opacity: 1; transform : translateY(0); } }ستسقط العناصر المزالة وتتلاشى fade out. بالنسبة لتحريكة السقوط إلى أسفل فهي بسيطة جداً، حيث ينتقل العنصر إلى أسفل وفق محور التراتيب (محور y) ليحاكي تحريكة السقوط، ويدور بينما يسقط ويتلاشى بالتدريج حتى يختفي تماماً (ستتحقّق شيفرة JavaScript من أنّ العنصر قد أُزيل كليّاً من DOM في نهاية هذه التحريكة). li.removed-item { animation: removed-item-animation 1s cubic-bezier(0.55, -0.04, 0.91, 0.94) forwards; transform-origin: 0% 100%; } @keyframes removed-item-animation { 0% { opacity: 1; transform: rotateZ(0); } 100% { opacity: 0; transform: translateY(600px) rotateZ(90deg); } }أمّا عندما نستعيد عنصرًا فستعمل تحريكة الاستعادة على عكس المنطق الموجود في تحريكة إزالة عنصر، لذلك فستكون الأُطر الأساسية keyframes مُعرّفة بشكل معاكس تماماً لما هو عليه في تحريكة إزالة عنصر: li.restored-item { animation: openspace 0.3s ease forwards, restored-item-animation 0.3s 0.3s cubic-bezier(0, 0.8, 0.32, 1.07) forwards; } @keyframes openspace { to { height: auto; } } @keyframes restored-item-animation { 0% { opacity: 0; transform: translateY(600px) rotateZ(90deg); } 10% { opacity: 1; transform: translateY(600px) rotateZ(90deg); } 100% { opacity: 1; transform: rotateZ(0); } }يمكنك أن ترى أننا نستخدم في الشيفرة السابقة مظهر تحريك اسمه openspace استعرته من مقال كريس كوير. يتأكّد مظهر التحريك هذا من أنّ العناصر التي تقع أسفل العنصر المُسترجع (إن وجدت)، ستنزلق إلى الأسفل وتفسح مجالاً للعنصر المُسترجَع ليعود إلى مكانه. إذاً عندما تنزلق العناصر إلى الأسفل لتفسح مجالاً open space للعنصر المُسترجَع، فإنّها فعلياً يجب أن تنتقل إلى الأسفل بشكل سلس، ولكن بما أنّ العناصر في هذا التطبيق لا تملك ارتفاعاً height ثابتاً، لذلك فإنّ إطار التحريك الأساسي to (انظر الشيفرة في الأعلى) سيجعل قيمة الارتفاع height لها لتصبح auto في نهاية عملية التحريك، سيؤدي ذلك لسوء الحظ إلى أنّ العناصر لن تنزلق إلى الأسفل، بل ستبدو كما لو أنّها تقفز إلى الأسفل. على أية حال توجد طريقة تجعل العناصر تغير مواقعها بشكل سلس، وهي تقنية كتب عنها ستيف ساندرسون Steve Sanderson هنا. لكنه يستخدم لهذا الغرض التموضع المطلق absolute positioning، وكمية لا بأس بها من شيفرة JavaScript. يمكنك تفقّد مقالته إذا كنت مهتماً بمعرفة المزيد عن التقنيّة التي يستخدمها، والتي تعطي في الحقيقة نتائج رائعة! المثال الثاني المثال الثاني: العناصر تكبُر وتتلاشى أمام المستخدم، وتُستَعاد بطريقة معكوسة. يعود الفضل في هذه الفكرة إلى تيم بيتروسكي Tim Pietrusky، حيث جاء بها عندما أخبرته أنّ الأفكار قد نفذت منّي بعد أن وضعت خمسة أمثلة توضيحية! في هذه الفكرة، تظهر العناصر المُضافة حديثاً (أي تلك العناصر التي لم تُزال من قبل ثم استُعيدت) بشكل تدريجي fade in ضمن موقعها. li.new-item { opacity: 0; animation: fadeIn .3s linear forwards; } @keyframes fadeIn { to { opacity: 1; } }عندما تُزال العناصر، فإنّها تكبُر وتتلاشى أمام المستخدم، أمّا العناصر المُستعادة فتسلك الأسلوب المعاكس، فعملية التحريك بالنسبة للعناصر المستعادة تماثل تماماً عملية التحريك بالنسبة للعناصر المزالة ولكن بالمقلوب. li.removed-item { animation: removed-item-animation .6s ease-out forwards; transform-origin: 50% 50%; } @keyframes removed-item-animation { 0% { opacity: 1; transform: scale(1); } 100% { opacity: 0; transform: scale(4); } } li.restored-item { animation: openspace .3s ease forwards, restored-item-animation .3s .3s ease-out forwards; } @keyframes openspace { to { height: auto; } } @keyframes restored-item-animation { 0% { opacity: 0; transform: scale(4); } 100% { opacity: 1; transform: scale(1); } }المثال الثالث المثال الثالث: ستنزلق العناصر المستعادة لتدخل من اليمين، أما العناصر المزالة فستنزلق يساراً إلى الخارج. يُعتبر المثال الثالث أبسط من سابقيه من الناحية الشكلية. فالعناصر المُضافة حديثاً سيكون لها نفس تأثير الظهور التدريجي كما في المثالين السابقين، لذلك سنتجاوز عملية التحريك الخاصة بإضافة عنصر جديد. بالنسبة للعناصر المُزالة فإنها ستنزلق يساراً إلى الخارج، مع ملاحظة تأثير جميل يحدث عند بدء عملية الإزالة باستخدام دالة توقيت من النوع Cubic Bezier، انظر إلى المثال التطبيقي لترى كيف تعمل هذه التحريكة. li.removed-item { animation: removed-item-animation .8s cubic-bezier(.65,-0.02,.72,.29); } @keyframes removed-item-animation { 0% { opacity: 1; transform: translateX(0); } 30% { opacity: 1; transform: translateX(50px); } 80% { opacity: 1; transform: translateX(-800px); } 100% { opacity: 0; transform: translateX(-800px); } }أمّا العناصر المستعادة فستنزلق إلى الداخل من اليمين، وذلك باستخدام نفس دالة التوقيت السابقة، ولكنها ليست الحالة المعاكسة تماماً لها (تفقّد المثال التطبيقي لترى النتيجة النهائية). li.restored-item { animation: openspace .3s ease forwards, restored-item-animation .5s .3s cubic-bezier(.14,.25,.52,1.56) forwards; } @keyframes openspace { to { height: auto; } } @keyframes restored-item-animation { 0% { opacity: 0; transform: translateX(300px); } 70% { opacity: 1; transform: translateX(-50px); } 100% { opacity: 1; transform: translateX(0); } } المثال الرابع المثال الرابع: ستكبر العناصر المستعادة والجديدة وتظهر تدريجياً ضمن موقعها، أمّا العناصر المزالة فإنّها ستصغر وتختفي تدريجياً. وهذا المثال بسيط أيضاً. فكل من العناصر الجديدة والمستعادة ستكبر وتظهر تدريجياً في مواقعها، أما العناصر المزالة ستصغر وتختفي تدريجياً. هناك إطارين أساسيين keyframes لهاتين التحريكتين: li.removed-item { animation: removed-item-animation .6s cubic-bezier(.55,-0.04,.91,.94) forwards; } @keyframes removed-item-animation { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0); } } li.restored-item { animation: openspace .3s ease forwards, restored-item-animation .3s .3s cubic-bezier(0,.8,.32,1.07) forwards; } @keyframes openspace { to { height: auto; } } @keyframes restored-item-animation { from { opacity: 0; transform: scale(0); } to { opacity: 1; transform: scale(1); } } المثال الخامس المثال الخامس: تسقط العناصر الجديدة من الأعلى إلى الأسفل. العناصر المزالة تبقى معلّقة قليلاً ثم تسقط إلى الأسفل. أما العناصر المستعادة فتنزلق إلى الداخل من اليمين. في هذا المثال، عندما نُزيل أحد العناصر فإنّه يبقى معلّقاً قليلاً قبل أن يبدأ بالسقوط الفعلي ثم الإختفاء. في الحقيقة هذا هو الجزء الأهم في هذا المثال، لأنّ العناصر الجديدة ستسقط إلى الأسفل كما في المثال الأوّل، والعناصر المستعادة ستنزلق إلى الداخل من اليمين كما في المثال الثالث، ولكن مع فرق طفيف في دالة التوقيت timing function. لذلك فإنّ التحريكة الخاصة بإزالة العناصر هي التأثير الجديد الوحيد في هذا المثال. li.restored-item { transform: translateX(300px); animation: openspace .3s ease forwards, restored-item-animation .3s .3s cubic-bezier(0,.8,.32,1.07) forwards; } @keyframes openspace { to { height: auto; } } @keyframes restored-item-animation { to { opacity: 1; transform: translateX(0); } } li.removed-item { animation: removed-item-animation 2s cubic-bezier(.55,-0.04,.91,.94) forwards; transform-origin: 0% 100%; }يعطي تغيير زاوية الدوران للعنصر ضمن أُطر frames مختلفة (الأطر الرئيسية: 0% و 20% و 40% و 60% و 70% و 90% و 100%) انطباعاً بأنّ العنصر يتأرجح بينما يكون معلّقاً، وبعد ذلك يبدأ بالسقوط إلى الأسفل. @keyframes removed-item-animation { 0% { opacity: 1; transform: rotateZ(0); } 20% { opacity: 1; transform: rotateZ(140deg); } 40% { opacity: 1; transform: rotateZ(60deg); } 60% { opacity: 1; transform: rotateZ(110deg); } 70% { opacity: 1; transform: rotateZ(90deg) translateX(0); } 90% { opacity: 1; transform: rotateZ(90deg) translateX(600px); } 100% { opacity: 0; transform: rotateZ(90deg) translateX(600px); } } المثال السادس المثال السادس: ستختفي العناصر المزالة تدريجياً وتسقط إلى الأسفل باتجاه اليسار، أما العناصر الجديدة والمستعادة فستنزلق إلى الداخل من اليمين. سيكون لكل من العناصر الجديدة والمستعادة نفس السلوك في هذا المثال، حيث ستنزلق هذه العناصر إلى الداخل من اليمين ثم تخرج بشكل طفيف من الجهة اليسرى قبل أن تستقرّ في مكانها. li.restored-item { transform: translateX(300px); animation: openspace .3s ease forwards, restored-item-animation .5s .3s cubic-bezier(.14,.25,.52,1.56) forwards; } @keyframes openspace { to { height: auto; } } @keyframes restored-item-animation { 0% { opacity: 0; transform: translateX(300px); } 70% { opacity: 1; transform: translateX(-50px); } 100% { opacity: 1; transform: translateX(0); } }ستنزلق العناصر المزالة ببطء نحو اليسار، وبعد ذلك ستسقط إلى الأسفل باتجاه اليسار وتتلاشى. من المهم الآن أن نعمل على إعداد تحويل مناسب لموضع نقطة الأصل origin (مبدأ الإحداثيات)، بحيث أنّ التأثير المسؤول عن السقوط إلى أسفل يبدو أكثر واقعية. بغية ذلك، أجريت تحويلاً على نقطة الأصل لكي تنطبق على آخر نقطة تماس بين العنصر والسطر الذي ينتمي إليه، وذلك قبل أن يبدأ بالدوران والسقوط إلى أسفل، يعطي ذلك انطباعاً بأنّ العنصر يسقط بسبب وزنه. li.removed-item { animation: removed-item-animation 1s linear; transform-origin: 390px 100%; } @keyframes removed-item-animation { 0% { opacity: 1; transform: translateX(0) rotateZ(0); } 50% { opacity: 1; transform: translateX(-400px) rotateZ(0); } 75% { opacity: 1; transform: translateX(-420px) rotateZ(-30deg); } 100% { opacity: 0; transform: translateX(-800px) rotateZ(-60deg) translateY(400px); } } خاتمةفي الواقع، الإمكانيات المتاحة لا حدّ لها تقريباً، هناك الكثير من الطرق الأكثر الإبداعية لإضافة وإزالة عناصر قائمة، وأنا على ثقة بأنّك تستطيع ابتكار تأثيرات خاصة بك، وأرجو أن يكون هذا الدرس مثيراً وملهماً. لم أدخل في القسم المتعلّق بـ JavaScript لأنّ ذلك ليس من محور اهتمام الدرس. من الملاحظ وجود خطأ ضمن متصفح Firefox (ربما يُصحّح في النسخ اللاحقة) ,والذي يسبب وميضاً للصفحة كلّما تمّ وضع التركيز على العنصر أو حتى إزالة التركيز عنه (أي عندما تضغط زر edit/save). لا أدري إذا كانت توجد طريقة لتجاوز هذا الأمر، لذلك فمن فضلك أعلمني إذا استطعت تحديد سبب ذلك الوميض وإذا كانت هناك أي طريقة لمنعه. على أية حال جُرّبت الأمثلة السابقة بشكل جيّد على المتصفحات التي تدعم Webkit. شكراً لقراءتك هذا الدرس، وأرجو أن تكون قد استمتعت فيه. بإمكانك الاطّلاع على هذه الأمثلة من هنا، أما الشيفرة المصدرية فهي متُوفّرة على هذا المُستودع. ترجمة -وبتصرّف- للمقال Creative Add/Remove Effects For List Items with CSS3 Animations لصاحبته Sara Soueidan.
-
- 3
-
- transitions
- animations
- (و 9 أكثر)
-
تُعتبر لوحة تسجيل الدخول في ووردبريس من أقل المواضيع التي يتم التحدث فيها أو التلاعب بتصاميمها على عكس التصاميم الخاصة بالقوالب، ولكنه من الجيد لك أن تعرف كيف تُنشئ واحدة حتى يبدو موقعك أو موقع عميلك متميّزًا وله رونقه الخاص. تابع معنا هذا الدرس لتعرف كيفية إنشاء لوحة تسجيل دخول خاصة بدون استعمال الإضافات. لماذا يجب عليك تعلم ذلك؟كل المواقع التي تعمل على منصة ووردبريس تملك نفس تصميم لوحة الدخول وهو التصميم الرئيسي الخاص بالووردبريس، ولكن بعض العملاء يريدون أن يتميزوا بكل صغيرة وكبيرة في موقعهم ومن ضمنها لوحة الدخول. سأريك الآن كيف تقوم بذلك فالأمر سهل وغير معقد ويمكنك أن تكتب أكواد CSS وjQuery خاصة بك ولن تحتاج إلى أي إضافات. لم لا تستخدم إضافة جاهزة وحسب؟هناك إضافة جيدة اسمها "BM Custom Login" ولكن حدثت عليها الكثير من التعديلات والاختلافات منذ إصدارها الأول، وأصبحت أحس أن الإصدار الحالي ليس بتلك الجودة. وشيء آخر، وهو أنه يجب عليك أن تقلل من الإضافات في موقعك على قدر الإمكان إن أردت لموقعك أن يكون سريعًا. على كل حال وكما ذكرنا سابقًا فإننا لن نستخدم أي إضافات في هذا الدرس. هيكلة القالب الجميل في هذه الطريقة هو أنك تستطيع أن تحفظ كل الملفات المهمة داخل القالب نفسه على عكس الإضافات التي تُبقي ملفاتها بداخل مجلد الإضافة نفسه، وبذلك نُبقي كل شيء منظم ومن السهل الرجوع إليه في أي وقت. تحديث/تعديل ملف functions.phpfunction custom_login() { $files = '<link rel="stylesheet" href="'.get_bloginfo('template_directory').'/css/login.css" /> <script src="http://use.typekit.com/pgf3epu.js"></script> <script>try{Typekit.load();}catch(e){}</script> <script src="'.get_bloginfo('template_directory').'/js/jquery.min.js"></script> <script src="'.get_bloginfo('template_directory').'/js/login.js"></script>'; echo $files; } addaction('loginhead', 'custom_login');أول خطوة ستكون كتابة دالة داخل ملف functions.php وتخزين كل الملفات الضرورية داخل مُتغيّر ثمَّ عمل echo له. يمكننا مناداة الملفات الموجودة داخل القالب باستعمال ('get_bloginfo('template_directory وربط الملف مباشرة. لقد قمت أيضًا بإضافة ملف jQuery مُصغّر (minified) وtypekit أيضًا. function customloginurl() { echo bloginfo('url'); } addfilter('loginheaderurl', 'customloginurl'); function customlogintitle() { echo get_option('blogname'); } addfilter('loginheadertitle', 'customlogintitle');قمت أيضًا بإضافة دالّتين؛ واحدة لتغيير رابط الشّعار حتى يظهر الشّعار الخاص بالموقع بدلًا من شعار موقع Wordpress.org، والدالة الثانية استخدمتها لتغيير عنوان لوحة تسجيل الدخول. هذا كان ما يخص أكواد PHP فلن نحتاج إلى أي أكواد PHP إضافية بعد الآن. تغيير تنسيقات CSSهنا يبدأ التحدي. سوف تحتاج الآن إلى الإطلاع على عناصر DOM لمعرفة العناصر التي تستطيع تعديلها وسوف تحتاج أيضًا إلى إزاحة تنسيقات CSS الموجودة في الصفحة واستبدالها بتنسيقات أخرى، وحتى تفعل ذلك سوف تحتاج إلى استخدام Developer Tools كتلك الموجودة في متصفح Google Chrome أو يمكنك استخدام إضافة Firebug المشهورة. ما أحبّ إضافته في بداية الملف هو المحدد العام * لتحديد واستهداف كافة العناصر ومن ثم أضيف لها خاصية transition وخاصية webkit-font-smoothing: antialiasing- حتى نحصل على خط أفضل في متصفحات webkit. ما أفضله أيضًا هو التعديل على محدد الفئة الزائفة (pseudo-class) المسمى focus: للتخلص من الحدود الخارجية (outlines). * { -webkit-transition: all 0.3s ease; -moz-transition: all 0.3s ease; -ms-transition: all 0.3s ease; transition: all 0.3s ease; -webkit-font-smoothing: antialiased; } :focus { outline: 0!important; }يمكننا باستعمال Developer Tools معرفة العناصر الموجودة ومعرفة تنسيقات CSS المستخدمة لنتمكن من تغييرها. فعلى سبيل المثال، يمكننا تغيير الشعار الموجود أعلى لوحة تسجيل الدخول إلى شعار الموقع نفسه: body.login h1 a { background: url('../images/logo.png') center center no-repeat transparent; background-size: 188px 189px; width: 188px; height: 189px; margin: 0 auto 30px; opacity: 0.7; padding: 0; } body.login h1 a:hover {opacity: 1;}كما ترى في الأعلى فقد قمت بتحديد العنصر body.login ثم h1 الموجود بداخله انتهاءً بالوسم a، وقمت بعد ذلك باستخدام الخاصية background لوضع صورة الشعار الموجودة في مجلد images واستعمال بعض تنسيقات CSS بسيطة. لاحظ أيضًا أنني استعملت خاصية background-size كما هو في Wordpress 3.4 وخاصية opacity لتقليل شفافية الشّعار وإعادته إلى شفافيته كاملة عند وضع مؤشر الفأرة فوقه (hover). نريد أيضًا إخفاء عنصر backtoblog# لأننا لن نحتاجه فالشّعار سوف يفي بالغرض ليأخدنا إلى الصفحة الرئيسية للمدونة. يمكنني استعمال الكثير من تنسيقات CSS لتغيير جميع العناصر حتى تتوافق مع التصميم، وإذا أردت استبدال تنسيقات مكان أخرى فسوف أستعمل ids الموجودة في الصفحة وimportant! إن اضطررت لذلك. form#loginform p.forgetmenot label { position: relative; background-image: url('../images/checkbox.png'); background-position: 0 0; background-repeat: no-repeat; padding: 2px 0 0 24px; height: 18px; display: inline-block; -webkit-transition: none; -moz-transition: none; -ms-transition: none; transition: none; } form#loginform p.forgetmenot label input[type="checkbox"] { position: absolute; left: 0; opacity: 0; width: 20px; height: 20px; display: block; cursor: pointer; }سنقوم الآن بتغيير التصميم الخاص بمربع الاختيار (checkbox) وذلك باستعمال background-image على الـتسمية (label) وإضافة بعض padding إلى اليسار وسوف نقوم بإخفاء مربع الاختيار نفسه. ولسوء الحظ، فإنه سيكون من الصعب تغيير الصورة عند النقر عليها وذلك لأن مربع الاختيار موجود داخل وسم <label>، وبالتالي سوف نضطر إلى استعمال jQuery. إضافة أكواد jQueryيمكننا استعمال jQuery لإضافة بعض التنسيقات أو attributes أو حتى تغيير أجزاء بعض العناصر، كما أنني أريد أن أضيف placeholders إلى حقول الإدخال وكذلك جعل مربع الاختيار يعمل مع بعض الصور الخاصة وكل ذلك سوف يتم داخل ملف login.js الموجود في مجلد "js" الخاص بالقالب. $('#loginform input[type="text"]').attr('placeholder', 'Username'); $('#loginform input[type="password"]').attr('placeholder', 'Password'); $('#loginform label[for="user_login"]').contents().filter(function() { return this.nodeType === 3; }).remove(); $('#loginform label[for="user_pass"]').contents().filter(function() { return this.nodeType === 3; }).remove();يمكننا باستعمال jQuery إضافة placeholder إلى حقول الإدخال، ولكن ذلك لن يكون سهلًا بسبب وجود الحقول داخل وسوم <label> مما سيجعل عملية إزالة النص الخاص بالـتسمية أمرًا ليس باليسير. سوف نقوم باستعمال ()contents. و ()filter. لإزالة النصوص الخاصة بالـتسمية ليبقى لدينا placeholders فقط. $('input[type="checkbox"]').click(function() { $(this+':checked').parent('label').css("background-position","0px -20px"); $(this).not(':checked').parent('label').css("background-position","0px 0px"); });وكما قلنا سابقًا، فوجود مربع الاختيار داخل وسم <label> سيجعل عملية تطويع مربع الاختيار ليعمل كما نريد أمرًا صعبًا. فالطريقة التي من المفترض أن يعمل بها هو أنّه عندما يتم الضغط على التسمية (label) فإنّ مربع الاختيار سوف يتم اختياره (يصبح checked) وبالتالي تتغير الصورة التي أضفناها لتدل على أنه تم النقر على المربع، ولذلك قمنا باستعمال jQuery لنتفقد فيما إذا كان مربع الاختيار في حالة checked أو لا، فإذا كان في حالة checked فإن المحدد checked: سوف يعمل على تغيير موضعة الصورة (باستعمال background-position) واذا لم يكن كذلك فسوف يعود كل شيء إلى طبيعته. خاتمة كما رأيت، فقد قمنا بإنشاء لوحة تسجيل دخول بكل سهولة وذلك فقط باستعمال Wordpress functions ،CSS وjQuery ومن دون الحاجة إلى أي إضافات. يمكنك الإطلاع على النتيجة النهائية من هنا. ترجمة -وبتصرف- للمقال: Create a Custom WordPress Login Without Plugins لصاحبه: Iggy.
-
قبل عدة سنوات لم يكن من الممكن إنشاء قائمة منسدلة بدون الاستعانة بالجافاسكربت، أمّا الآن فيمكننا وبمساعدة بعض الخصائص والمُحدّدات (selectors) المتقدمة الخاصة بلغة CSS3 القيام بذلك وبكل سهولة. فإذا أردت إنشاء قائمة منسدلة خاصة بك فعليك بتتبع هذا الدرس. سوف تحتوي القائمة التي سنقوم بإنشائها على قائمتين فرعيتين تظهران عندما يقوم المستخدم بوضع مؤشر الفأرة (hover) فوق الرابط/العنصر الأب (parent link). ألقِ نظرة على ما سنقوم بإنشائه في هذا الدرس. هيكلة ملف HTMLسنقوم في البداية بإنشاء ملف HTML يحتوي على الوسوم (tags) الخاصة بالقائمة. سوف نستعمل وسم <nav> الذي ظهر في HTML5، ثم نضيف روابط القائمة الرئيسية داخل وسم <ul>. <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">Tutorials</a></li> <li><a href="#">Articles</a></li> <li><a href="#">Inspiration</a></li> </ul> </nav>بعد ذلك سوف نضيف القوائم الفرعية (قوائم فرعية درجة أولى) أسفل رابطي "Tutorials" و"Articles"، وكل واحدة من هاتين القائمتين ستكون عبارة عن وسم <ul> موجود داخل وسم <li>. أنظر الشفرة البرمجية في الأعلى. <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">Tutorials</a> <ul> <li><a href="#">Photoshop</a></li> <li><a href="#">Illustrator</a></li> <li><a href="#">Web Design</a></li> </ul> </li> <li><a href="#">Articles</a> <ul> <li><a href="#">Web Design</a></li> <li><a href="#">User Experience</a></li> </ul> </li> <li><a href="#">Inspiration</a></li> </ul> </nav>أمّا روابط القائمة الفرعية الثانية (قائمة فرعية درجة ثانية) فسوف تكون موجودة داخل الخيار "Web Design" من القائمة الفرعية الأولى ذات الدرجة الأولى. أي أنّ هذه الروابط ستكون موجودة داخل وسم <ul> وهذا الوسم سيكون موجودًا داخل الوسم: <li><a href="#">Web Design</a></li> (يمكنك النظر إلى الشفرة البرمجية التالية حتى تتوضح الصورة بشكل أفضل). <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">Tutorials</a> <ul> <li><a href="#">Photoshop</a></li> <li><a href="#">Illustrator</a></li> <li><a href="#">Web Design</a> <ul> <li><a href="#">HTML</a></li> <li><a href="#">CSS</a></li> </ul> </li> </ul> </li> <li><a href="#">Articles</a> <ul> <li><a href="#">Web Design</a></li> <li><a href="#">User Experience</a></li> </ul> </li> <li><a href="#">Inspiration</a></li> </ul> </nav> لقد حصلنا إلى الآن على قائمة منسدلة بقوائم فرعية واضحة المعالم وسنقوم في الخطوة التالية بإضافة تنسيقات CSS. إضافة تنسيقات CSSلنبدأ الآن بإضافة بعض تنسيقات CSS الأساسية لنجعل القائمة المنسدلة تعمل. يمكننا باستخدام بعض المحددات المتقدمة أن نستهدف عناصر موجودة بشكل عميق داخل بنية HTML من دون استعمال أي ids أو classes، ففي البداية سنقوم بإخفاء العناصر الفرعية وذلك عن طريق استخدام الخاصية display:none على عناصر <ul> الموجودة داخل عناصر <ul> أخرى. وحتى نجعل هذه القوائم تظهر مرة أخرى عند وضع مؤشر الفأرة فوقها فإننا سنحتاج إلى إضافة الخاصية display: block. وبالنسبة للمحدد > فسوف نستخدمه حتى نتأكد بأنّ يظهر فقط العنصر الإبن <ul> الموجود داخل <li> الذي وضع فوقه مؤشر الفأرة بدلًا من أن تظهر جميع القوائم الفرعية بنفس اللحظة وهو ما لا نريده بكل تأكيد. nav ul ul { display: none; } nav ul li:hover > ul { display: block; }يمكننا الآن تنسيق القائمة الرئيسية وذلك باستخدام بعض خصائص CSS3 مثل gradients ،box shadows وborder-radius. استخدمنا position:relative حتى نتمكن من موضعة القوائم الفرعية بالنسبة للقائمة الرئيسية (بعبارة أخرى، حتى نستطيع إعطاء الخاصية position: absloute للقوائم الفرعية)، واستخدمنا الخاصية display: inline-table حتى نمنع القائمة من التمدد على كامل الصفحة. أمّا بالنسبة للسطرين الأخيرين في الكود الموجود في الأعلى فهذا ما يسمى Clearfix وهو يستخدم لحل مشكلة الـfloats الشائعة وحتى لا نضطر إلى استعمال overflow: hidden لأن ذلك سيؤدي إلى إخفاء القوائم الفرعية ويمنعها من الظهور. nav ul { background: #efefef; background: linear-gradient(top, #efefef 0%, #bbbbbb 100%); background: -moz-linear-gradient(top, #efefef 0%, #bbbbbb 100%); background: -webkit-linear-gradient(top, #efefef 0%,#bbbbbb 100%); box-shadow: 0px 0px 9px rgba(0,0,0,0.15); padding: 0 20px; border-radius: 10px; list-style: none; position: relative; display: inline-table; } nav ul:after { content: ""; clear: both; display: block; } قمنا بعد ذلك بتنسيق عناصر القائمة <li> وما تحتويه من عناصر <a>. وعندما يقوم المستخدم بوضع مؤشر الفأرة فوق العنصر سيتحول لون الخلفية إلى إحدى تدرجات اللون الأزرق وسوف يتغير لون الخط إلى الأبيض. nav ul li { float: left; } nav ul li:hover { background: #4b545f; background: linear-gradient(top, #4f5964 0%, #5f6975 40%); background: -moz-linear-gradient(top, #4f5964 0%, #5f6975 40%); background: -webkit-linear-gradient(top, #4f5964 0%,#5f6975 40%); } nav ul li:hover a { color: #fff; } nav ul li a { display: block; padding: 25px 40px; color: #757575; text-decoration: none; } أصبحت القائمة الرئيسية جاهزة الآن ولكن القوائم الفرعية تحتاج إلى بعض العمل الإضافي، فبعض التنسيقات في عناصر القوائم الفرعية سوف ترث تنسيقات العنصر الأب، لذلك سوف نحتاج إلى تغيير لون الخلفية (background) وإزالة border-radius وتعديل قيم padding حتى يظهر كل شيء بأفضل شكل. وحتى نضمن أن تظهر هذه القوائم أسفل القائمة الرئيسية فقد استعملنا الخاصيتين position: absolute و top: 100%. إنّ عناصر <li> الموجودة داخل <ul> في القوائم الفرعية لن تحتاج إلى أن تكون بجانب بعضها بشكل أفقي (أي لن نحتاج إلى استعمال خاصية float) وإنما ستكون فوق بعضها البعض بشكل عمودي مع وجود حدود (borders) صغيرة تفصل بينها. وفي الأخير هناك تأثير hover الذي سوف يُغيّر لون الخلفية إلى شيء أدكن. nav ul ul { background: #5f6975; border-radius: 0px; padding: 0; position: absolute; top: 100%; } nav ul ul li { float: none; border-top: 1px solid #6b727c; border-bottom: 1px solid #575f6a; position: relative; } nav ul ul li a { padding: 15px 40px; color: #fff; } nav ul ul li a:hover { background: #4b545f; } نأتي الآن للخطوة الأخيرة وهي موضعة القوائم الفرعية من الدرجة الثانية. سوف ترث هذه القوائم التنسيقات الخاصة بالقائمة الفرعية من الدرجة الأولى وبذلك فكل ما سنحتاجه هو موضعة هذه القوائم باستخدام position: absolute و left: 100% نسبة إلى العنصر الأب <li> الذي يحتوي على الخاصية position: relative. nav ul ul ul { position: absolute; left: 100%; top:0; } وإلى هنا نصل إلى نهاية هذا الدرس ونكون قد حصلنا على قائمة منسدلة جميلة وأنيقة. يمكنك تصفح النتيجة النهائية من هنا. ترجمة -وبتصرف- للمقال How To Create a Pure CSS Dropdown Menu لصاحبه Iggy.
-
- 2
-
- nav
- قائمة منسدلة
- (و 4 أكثر)
-
كنت في الماضي قد قمت بإنشاء العديد من مثل هذا التأثير باستخدام الفوتوشوب، ولكن مع ظهور CSS3 وجلبها للكثير من الخصائص المدهشة فقد قررت أن أقوم بدرس حول كيفية إنشاء ذلك التأثير بمساعدة واستخدام التدرجات (gradients) والمرشحات (filters) الموجودة في CSS3. سوف نستخدم التدرجات (gradients) والمرشحات (filters) الخاصة بلغة CSS لدمج العديد من الألوان المتداخلة لإنشاء التأثير المطلوب. إنّ دعم المتصفحات للمرشحات جيد جدًا فهو مدعوم في جميع المتصفحات الحديثة ما عدا متصفحات Internet Explorer ومتصفح Opera mini (أنقر هنا لمعلومات أكثر عن دعم المتصفحات). كيف تقوم بإنشاء التأثير باستعمال CSS فقط<div class="retro"> <img src="images/retrofy-me.jpg" alt="Retro is cool!" /> </div>حتى نقوم بإنشاء التأثير سنحتاج إلى صورة، لذلك قم بإضافة صورة باستخدام وسم `<img>`. وبما أنّ بعض تأثيرات CSS تعتمد على وجود عنصر حاوي من نوع block فسوف تكون الصورة موجودة داخل وسم `<div>` (يمكنك استخدام `<p>` بدلًا من `<div>` فكلاهما من نوع block ولكني أفضل استخدام div). .retro { -webkit-box-shadow: inset 0px 0px 100px rgba(0,0,20,1); box-shadow: inset 0px 0px 100px rgba(0,0,20,1); background: -webkit-linear-gradient(top, rgba(255,145,0,0.2) 0%,rgba(255,230,48,0.2) 60%), -webkit-linear-gradient(20deg, rgba(255,0,0,0.5) 0%,rgba(255,0,0,0) 35%); background: linear-gradient(top, rgba(255,145,0,0.2) 0%,rgba(255,230,48,0.2) 60%), linear-gradient(20deg, rgba(255,0,0,0.5) 0%,rgba(255,0,0,0) 35%); display: table; } .retro img { -webkit-filter: sepia(20%) brightness(10%) contrast(130%); filter: sepia(20%) brightness(10%) contrast(130%); position: relative; z-index: -1; }يمكنك استعمال تنسيقات CSS الموجودة في الأعلى لإنشاء تأثير retro على أي صورة. كيف يعمل كل شيء نبدأ تنسيقات CSS باستعمال خاصية `box-shadow` واعطائها القيمة (inset 0px 0px 100px rgba(0,0,20,1 مما يخلق توهجًا داخليًا بلون أزرق داكن وذلك لمحاكاة الصورة باهتة الحواف. ولكن هناك مشكلة وهو أن التأثير الذي تصنعه خاصية box-shadow لن يظهر لأنه سيكون موجودًا أسفل الصورة وسوف يتمدد على العرض الكامل للصفحة وهو ما لا نريده، ولحل تلك المشكلة سوف نضيف للصورة الخصائص position: relative و z-index: -1 حتى نجعل التأثير يظهر فوقها، كما أننا سوف نعطي الخاصية display: table للعنصر الأب حتى نمنع تمدده على كامل الصفحة ويكتفي فقط بالتمدد على أبعاد الصورة. لاحظ أننا استعملنا تدرجين؛ الأول (linear-gradient(top, rgba(255,145,0,0.2) 0%, rgba(255,230,48,0.2) 60% وسوف يعطي تدرجًا عموديًا من اللون البرتقالي إلى اللون الأصفر، وتسمح لنا قيم rgba بتقليل شفافية الألوان حتى نسمح للتدرج بالظهور وكأنه عبارة عن غشاء شفاف فوق الصورة. أمّا بالنسبة للتدرج الثاني (linear-gradient(20deg, rgba(255,0,0,0.5) 0%, rgba(255,0,0,0) 35% فقد أضفناه للعنصر الأب (وسم div) ويتدرج من لون أحمر ذو شفافية 50% إلى نفس اللون ولكن بشفافية 0% وبزاوية 20 درجة لمحاكاة تأثير تسرب الضوء الجميل. تعمل التأثيرات حتى الآن بشكل جيد ولكن الصورة تبدو مسطحة كثيرًا، لذلك سوف نستعمل مرشحات CSS كالتالي: (filter: brightness(10%) contrast(130%) sepia(20% للتعديل على الصورة قليلًا حتى تبدو أفضل، فخاصية brightness ستزيد سطوع الصورة بمقدار 10%، وخاصية التباين contrast تقوم بتدكين المناطق الداكنة وتفتيح المناطق الفاتحة، أمّا خاصية sepia فتضيف للصورة درجة من اللون البني المائل للصفار وبقيمة 20% حتى نحافظ على الألوان الأصلية للصورة. خاتمةكما رأيت، فبدمج خاصية gradient مع خاصية filter يمكننا إنشاء تأثيرات جميلة وعصرية وتشبه بدرجة كبيرة تلك التي يمكننا إنشاؤها باستخدام برنامج الفوتوشوب. ترجمة -وبتصرّف- للمقال Create a Trendy Retro Photo Effect Purely with CSS لصاحبه Iggy.
-
إذا كنت تُصمّم قالبًا جديدًا لووردبريس أو تعدّل قالبًا جاهزًا، فإن الخطوط المُخصّصة ستجدّد منظر قالبك. في حين تأتي متصفحات الإنترنت بخطوط جاهزة افتراضية، وهي التي تستدعيها في ملف style.css، استخدام نفس الخطوط التي يستخدمها الآخرين يبدو مملًا بعض الشيء. لحسن الحظ، بإمكانك إضافة الخط الذي تختاره بسهولة عن طريق قاعدة font-face@ في CSS3. كل ما تحتاجه هو رفع الخط إلى خادوم الويب الخاص بك، ثم إضافته إلى قالبك عن طريق بضعة سطور من CSS. العثور على خطهناك أماكن عديدة للعثور على خطوط ويب جيدة مجانًا مثل FontSquirrel أو Adobe Edge Web Fonts. فقط تأكد من اختيارك لخط ذي رخصة تلائم احتياجاتك. حيث أن الخطوط المجانية ليست جميعها متاحة للاستخدام التجاري، ولكن يمكنك شراء خطوط بمقابل مادّي للاستخدام التجاري من أماكن عديدة مثل Typekit. هناك نوعان رئيسيان من الخطوط في اللغة الإنجليزية: serif و sans-serif. تمتلك خطوط serif منحنيات في أطرافها بينما لا تمتلكها خطوط sans-serif. عندما يقع اختيارك على الخط الجديد، ستحتاج لتحميل ملفه. ضع في اعتبارك أن هناك أنواع مختلفة من ملفات الخطوط وليست كلها متوافقة مع أغلب متصفحات الإنترنت. إليك مُلخّصا سريعًا عن الأنواع المختلفة للخطوط وصيغ ملفاتها: (TrueType Font (TTF: متوافق مع إنترنت اكسبلور 9.0 وما يليها، وكروم بداية من الإصدارة 4.0، فيرفكس من الإصدارة 3.5، سافاري من الإصدارة 3.1 وأوبرا من الإصدارة 10.0.(OpenType Font (OTF: له نفس التوافقيات لخط TrueType.(Web Open Font Format (WOFF: يدعمه إنترنت إكسبلورر من الإصدارة 9.0 وما يليها، كروم بداية من الإصدارة 5.0، فيرفكس من الإصدارة 3.6، سافاري من الإصدارة 5.1 وأوبرا من الإصدارة 11.1.(Web Open Font Format 2.0 (WOFF2: مدعوم فقط في كروم من الإصدارة 36.0، فيرفكس من الإصدارة 35.0، وأوبرا من الإصدارة 26.0.(Embedded Open Type Font (EOT: متاح خصيصًا لإنترنت إكسبلورر 6.0 وما يليه.صيغة Web Open Font Format هي الصيغة المفضلة نظرًا لأن الخطوط تٌضغط فيها لتستهلك مساحة أقل من الاتّصال المتاح لك وتحتوي على بيانات وصفية إضافية. ولكن للأسف فإنها ليست دائمًا متاحة للتحميل. فإذا وجدت صعوبة بالعثور على هذه الصيغة، يمكنك استخدام صيغ TrueType وOpenType المتاحة بشكل أكبر للتحميل كما أنها اختيارجيد أيضًا. رفع خطوطك على خادوم الويبحين تجد الخط الذي تريد استخدامه وتتبع إرشادات مصدر الخط لتحميل الملف، فقد حان الوقت إذن لرفعه إلى خادوم الويب الخاص بك. وقبل أن تفعل ذلك، تذكر أن تحتفظ بنسخة احتياطية من موقعك بالكامل قبل إجراء أي تعديلات. من المستحسن إضافة الخط إلى المجلد الذي يحوي قالبك، والذي يمكن أن تجده في المسار: wp-content > themes > your-theme حيث your-theme هو اسم قالبك. يمكنك أيضًا إذا أردت إضافة مجلد Fonts ليحتوي خطوطك حتى تنظم حاجياتك، خاصة إذا كنت تخطط لإضافة أكثر من خط واحد. فك ضغط الملف المضغوط وارفع المحتويات إلى مجلد القالب الخاص بك عن طريق لوحة التحكم. عبر النّقر على زر File Manager تحت Files في الصفحة الرئيسية للوحة التحكم. وغالبًا ستظهر لك نافذة منبثقة، فحينها ستختار مكان موقعك وبعدها تضغط زر الذهاب Go. انتقل إلى مجلد القالب الخاص بك واضغط زر الرفع Upload في أعلى الصفحة. يمكنك ترك صلاحيات الملف 644 ولن تواجه مشاكل غالبا. ولكن إذا واجهتك مشكلة صلاحية، فجرب حذف الملفات ثم إعادة رفعها مجددا بصلاحيات مختلفة. اضغط على زر اختيار الملف Choose file في صفحة رفع الملفات واختر ملفات الخط من حاسوبك. عندما تفتحها، فإن عملية الرفع ستبدأ تلقائيًا دون ضغط زر إضافي على هذه الصفحة. لا يهم المكان الذي تضع فيه ملف الخطوط، بل ستحتاج لتتذكر مساره. وستجده مكتوبًا في صفحة رفع الملفات بالبنط العريض بعد جملة Select files to upload to. إضافة خطوطك إلى القالبلإظهار خطوطك المرفوعة في قالبك، ستحتاج لاستدعائها في ملف style.css الخاص بالقالب، حيث يمكنك العثور عليه في: wp-content > themes > yourtheme في لوحة التحكم، اختر الملف ثم اضغط زر التعديل في أعلى الصفحة. إذا لم تكن قد منعت النوافذ المنبثقة مسبقًا، ستظهر لك نافذة منبثقة، في هذه الحالة اضغط على Go في الأسفل. انسخ النص البرمجي بالأسفل إلى الملف، ويفضل لصقه في الجزء المُخصّص لاستدعاء الخطوط. تأكد أن هناك سطرًا فاصلًا بين كل جزء من أجزاءئ النّص البرمجي في الملف. @font-face { font-family: FontName; src: url(public_html/your-site/wp-content/themes/your-theme/fonts/FontName-Regular.ttf); font-weight: normal; }لا تنس استبدال FontName باسم الخط الذي اخترته، وعدّل في الشيفرة البرمجية لتغيير مسار ملفات الخطوط إلى المسار الصحيح. أضف نفس شيفرة CSS مجددًا لتعريف النمط السميك، المائل، والعناوين الرئيسية للخطوط وما شابه، وتأكد من تغيير اسم الخط ومسار الملف بشكل صحيح. وفي النهاية، حدّد كيفية استخدام خطك ببعض النصوص الإضافية من CSS مثل المثال بالأسفل: p { font-family: FontName; } في هذا المثال، كل نصوص الفقرات (الموسومة بوسم p) ستستخدم الخط الجديد. حين تنتهي من تعديل النص البرمجي إلى اختياراتك الخاصة وتحفظ الملف، سيظهر الخط الجديد على موقعك. خاتمةمع هذه التعليمات، يجب أن تكون قادرًا على إضافة خطوط جديدة إلى القالب الخاص بك دون أي مشاكل. ومع ذلك، هناك العديد من الإضافات التي يمكنها مساعدتك على إضافة خطوط دون الحاجة إلى أي برمجة إذا أردت حلًا أسهل. لمزيد من المعلومات عن استخدام الخطوط في ووردبريس، اقرأ الدليل التالي: اللعب بالخطوط. ترجمة -وبتصرف- للمقال: Adding Custom Fonts to WordPress with @Font-Face and CSS3 لصاحبه: Jenni McKinnon.