المحتوى عن 'عناصر'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

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

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML5
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • مقالات تصميم عامة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات DevOps عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عمل حر عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 6 نتائج

  1. تُقدّم أشباه العناصر (pseudo-elements) عناصر DOM إضافيّة وبدون عناء يُذكر، فهي تَسمح للمُطوّر في إضافة مُحتوى إضافي إلى الصفحات وبدون إضافة أيًا من عناصر HTML على الصفحة، كما يُمكن لها أنّ تتحرّك (animated). ستتناول هذه المقالة استخدام شبه عنصر (pseudo-element) لإضافة تأثير بصري على زر. Shiny effect شبه العناصر Pseudo-elements يُمكن باستخدام CSS تحديد شبه عنصر باستخدام ::before أو ::after ليتم بعد ذلك إدراج شبه العنصر ضمن العنصر، أو بين العنصر و محتوى ما، وباعتبار أنّ شبه العنصر يعمل عمل أي عنصر، فمن المُمكن أنّ يتمّ تنسيقه، أو توضيعه، وستكون صياغة الشيفرة الخاصّة به على الشكل التّالي: .pebble::before { ... } .pebble::after { ... } يُمكن القول هنا، أنّ العنصر pebble. يملك عنصرين وهميين مُرتبطين به، ويُمكن تنسيقهما أيضًا. ملاحظة حول الفرق بين استخدام "::" و ":" يُقبَل عامًّا استخدام تضعيف النقطتان، وذلك للدلالة على استخدام شبه العناصر، وذلك على عكس شبه الأصناف (pseudo-classes) مثل :hover أو :first-child، ولكن يجب استخدام ( في حال الرغبة في دعم IE8، مع العلم أنّ جميع المُتصفّحات الأخرى وبإصداراتها الأخيرة تدعم النقطتان المُضاعفتان (::). استخدام خاصية content يجب عند استخدام شبه العناصر، ضبط الخاصّيّة content لكي يُصبح شبه العناصر مرئيًا على الصّفحة، ومن المُمكن الاحتيال عليه للظهور عبر استخدام مُحتوى فارغ كما في التّالي: .pebble::before { content: "" ... more styling goes here... } .shiny{-webkit-perspective:500px;perspective:500px;-webkit-transform-style:preserve-3d;transform-style:preserve-3d;display:inline-block}.shiny button{background:#d1703c;color:#fff;font-size:14px;border:none;border-radius:0.5em;height:3em;padding:0 1em;position:relative;overflow:hidden;line-height:2em;-webkit-transition:all 0.5s cubic-bezier(.67,-0.51,.42,1.43);transition:all 0.5s cubic-bezier(.67,-0.51,.42,1.43)}.shiny button:hover,.shiny button:focus{border-color:#d1703c;color:#fff;font-size:24px}.shiny button:hover::after,.shiny button:focus::after,.shiny .demo-container.active button::after{-webkit-animation:sheen 1s 0.5s forwards;animation:sheen 1s 0.5s forwards}.shiny button::after{content:'';position:absolute;top:-50%;right:-50%;bottom:-50%;left:-50%;background:-webkit-linear-gradient(top,rgba(209,112,60,0),rgba(255,255,255,0.5) 50%,rgba(209,112,60,0));background:linear-gradient(to bottom,rgba(209,112,60,0),rgba(255,255,255,0.5) 50%,rgba(209,112,60,0));-webkit-transform:rotateZ(60deg) translate(-5em,7.5em);transform:rotateZ(60deg) translate(-5em,7.5em)}.shiny button.visible{overflow:visible}.shiny button:hover{cursor:pointer}@-webkit-keyframes sheen{100%{-webkit-transform:rotateZ(60deg) translate(1em,-14em);transform:rotateZ(60deg) translate(1em,-14em)}}@keyframes sheen{100%{-webkit-transform:rotateZ(60deg) translate(1em,-14em);transform:rotateZ(60deg) translate(1em,-14em)}} يجب أنّ تجعل الشيفرة السابقة من العنصر مرئيًا على الصّفحة. الزر البراق (Shiny button) سيتمّ استخدام شبه العنصر لإتمام هذا المثال، وذلك عبر إنشاء تأثير اللّمعان عند المرور فوق الزر، كما في المثال. Shiny effect البداية مع شيفرة HTML <button>Oooh SHINY</button> لا يوجد حاجة إلى كتابة المزيد من سطور HTML للمُتابعة، على اعتبار أنّه سيتمّ استخدام شبه العنصر لإضافة بقيّة المُحتوى، ولكن لا بأس من إضافة صنف (class) إلى الوسم <button> لتنسيقه عند وجود أكثر من نوع على الصّفحة، ولكن للمثال الحالي سيتمّ استخدام عنصر الزر على حاله للتبسيط. إضافة التأثير إن التأثير المُراد إضافته ما هو إلا تدرّج خطي (linear gradient) يمر عبر الزر، ولإنشاء هذا التدرّج سيتمّ استخدام شبه العنصر after، وتوضيعه في خارج الزر وفي بدايته. button::after { content: ''; position: absolute; top: -50%; right: -50%; bottom: -50%; left: -50%; background: linear-gradient(to bottom, rgba(229, 172, 142, 0), rgba(255,255,255,0.5) 50%, rgba(229, 172, 142, 0)); transform: rotateZ(60deg) translate(-5em, 7.5em); } يُصنع تأثير اللّمعان من تدرّج اللون الخارجي للزر إلى الأبيض ومن ثُمّ إلى العودة إلى اللون الأصلي. يجب إخفاء طبقة اللّمعان لتظهر فقط عند حركة المرور (hover)، ولعمل ذلك سيتمّ ضبط خاصّيّة overflow إلى hidden للزر، وباعتبار أنّ شبه العنصر هو ضمن الزر، فهذا يعني أنّ تموضعه خارج الزر لن يكون مرئيًّا. button { background: #e5ac8e; color: #fff; font-size: 14px; border-radius: 0.5em; padding: 0 1em; position: relative; overflow: hidden; line-height: 32px; } تمّ إضافة بعض التنسيق إلى الزر لكي يظهر بارزًا وذو منظرٍ خاصٍّ به، تجدر الإشارة هنا إلى استخدام position: relative، وذلك لكي يكون شبه العنصر المتموضع بشكل مُطلق (absolutely) مُتواجدًا داخل الزر، فبدون ضبط هذه الخاصّيّة، سيتموضع العنصر ذو التَمَوْضُع المُطلق ضمن العنصر الأب. إضافة التحريك (Adding the animation) يجب لاستكمال هذا المثال باستخدام التحريك: أوّلًا: إخبار المُتصفّح ليستخدم التحريك عند حركة المرور (hover). ثانيًا: تحديد بالضَّبط ما هو التحريك المطلوب وذلك باستخدام keyframes. يتمّ إضافة حالة المرور عبر إلحاق after إلى hover كما في التّالي: button:hover::after, button:focus::after { animation: sheen 1s forwards; } تمّ في الشيفرة السابقة إخبار المُتصفّح، أنّه عند حركة المرور (hover)، يجب على شبه العنصر after أنّ يُطبّق التحريك animation، ذو الاسم “sheen”، ولمدّة ثانية واحدة، ويتوقف عند النهاية بدون تكرار. يجب الأخذ بعني الاعتبار الترتيب، فاستخدام ::after:hover لن يعمل، حيثُ عندها سيتمّ إخبار المُتصفّح ليتفاعل مع حالة المرور (hover) لشبه العنصر نفسه. تتوفّر الشيفرة السابقة أيضًا على حالة التمركز (focus)، والّتي تعني أنّ المُستخدم الّذي يضغط على زر لوحة المفاتيح tab ضمن الصّفحة سيرى التأثير "sheen" أيضًا عند الوصول إليه، وبدون الحاجة لحركة المرور. سيتمّ في الخطوة التّالية تعيين وضبط keyframes لهذا التحريك: @keyframes sheen { 100% { transform: rotateZ(60deg) translate(1em, -9em); } } تمّ في الشيفرة السابقة كتابة keyframe واحد فقط، وذلك باعتبار أنّ بداية التَمَوْضُع (0%) هي مُضمّنة من قبل تَمَوْضُع بداية شبه العنصر، فكل ما يجب فعله هو ضبط نهاية التَمَوْضُع، والتي ستكون أعلى يمين الزر، ليُحاكي المُتصفح هذا التأثير Shiny effect دعم المتصفحات للتحريك أصبحت الخاصّيّة animation، و شبه العناصر مدعومة بشكل جيّد مع آخر إصدارات المُتصفّحات، ولكن يُستحسن دائمًا إلحاق السوابق webkit و moz من أجل الخاصّيّة keyframes. ترجمة وبتصرف للمقال Animating pseudo-elements.
  2. يُعتبر التصميم الجرافيكي مجالًا واسعًا جدًّا، ومهمّة الحصول على وظيفة مصمّم جرافيك ليست بالسّهلة. فعملية الحصول على وظيفة على شبكة الإنترنت تتطلب، بالإضافة إلى المهارات التي يجب أن تكتسبها، سِمات شخصية كمقاومة الإجهاد، الإبداع، والحافز الذاتي. لكنّ الجزء العملي يُعتبر، وبشكل واضح، هو الجزء الأهمّ، وهو الذي يتمّ الحكم من خلالهِ حتّى قبل تقييم مهاراتك الشخصيّة. لذلك سنبدأ اليوم بسلسلة من المقالات التي تدور حول أساسيات التصميم الجرافيكي، وسنستعرض في هذا الجزء العناصر الأكثر شيوعًا في هذا المجال. إنّ وظيفة مصمّم الجرافيك الرئيسية هي تصميم عناصر مرئية يمكن استخدامها في شبكة الإنترنت أو لغرض الطباعة. كمثال على ذلك؛ مخططات المواقع (التي يتم تحويلها في أغلب الأحيان إلى مواقع حقيقية من قِبل مصممي المواقع)، الملصقات، الكُتيّبات، النشرات، أو الحملات الإعلانية (في كِلا من شبكة الإنترنت والواقع). توجد في المجموع ستّة عناصر خاصّة بالتصميم يجب أن تكون مُلمًّا بها: الخط، الشكل، اللون، الخامة، القيمة والمساحة. 1. الخطيتواجد الخط عادةً في كلّ تصميم، حتّى لو كان إطارًا مُصمَتًا بعرض 1 بكسل أو خطًّا منقّطًا بعرض 5 بكسل. تحتوي جميع مواقع الإنترنت على خطوط، لكن مع أسلوب التبسيط للحدّ الأدنى (يُعرف أيضًا بالتبسيطية أو التقليليةMinimalism ) الذي أصبح شائعًا في السنوات الأخيرة هنالك محاولة لمسح الخطوط من مخططات الصفحات، أو على الأقل تقليل استخدمها. يمكن أن تكون الخطوط طويلة، حمراء، مستقيمة، رفيعة، زرقاء، متقطّعة، قصيرة، سوداء، أو منحنية، لكن تندرج جميعها تحت نفس الفئة. تستخدم الخطوط في أغلب الأحيان لرسم الحدود بين أقسام التصميم، أو لتوجيه نظر المشاهد نحو وجهة معيّنة. تعمل الخطوط على خلق تأثيرات ووقوع بصريّة مختلفة. تجذب الخطوط السميكة، العريضة الانتباه بسبب قوّتها البصرّية، بينما يكون للخطوط الرفيعة تأثيرًا مختلفًا معاكسًا لذلك. كما إن الألوان لها وقعٌ أيضًا، فالألوان الداكنة تكون سهلة الرؤية وجذب الانتباه أكثر من الألوان الفاتحة أو الباهتة. وهذا ليس كلّ ما في الأمر. فنمط الخط يمكن أن يؤثّر أيضًا في طريقة رؤية المستخدم له. هذا النمط يمكن تحديده بسهولة خلال CSS، ويمكن أن يكون، من بين الأنماط الأخرى، مصمتًا، منقّطًا، ومتقطّعًا. الخطوط المصمتة لها تأثير مختلف عن تأثير الخطوط المنقّطة، لأنّ الأولى تكون بارزة بشكل أكبر. في أسلوب التبسيط للحد الأدنى الذي تحدّثنا عنه سابقًا يتمّ إما استخدام الخطوط المصمتة بشكل أقلّ أو استخدم الخطوط المنحنية بشكل أكبر لأنها تعطي مظهرًا حركيًّا وانسيابيًّا للتصميم، والذي يعتبر أيضًا هدف من أهداف هذا الأسلوب. وهذه الخطوط توحي بالطاقة، تُبقي المستخدم مهتمًّا، وإذا ما تمّ دمجها مع الرسوم الإيضاحية سيصبح لها قوة فعّالة أمام عين الإنسان. كانت للخطوط المصمتة شعبية كبيرة قبل سنوات عديدة لأنها تحدد أسلوب التصميم؛ متين، متماسك، ومنظّم. لكنّ مواقع الإنترنت تغيّرت في السنوات الماضية ولم يعُد هذا النمط ذو شعبية بعد الآن، خاصّةً في معارض الأعمال Portfolio التابعة للمصمّمين والصفحات الأخرى ذات الحاجة الكبيرة إلى اللمسة الشخصية. فصلت الخطوط بين العمودين، وهي ليست بالعريضة جدًّا. استُخدمت الخطوط المصمتة للفصل بين أجزاء مختلفة من الموقع. 2. الشكلالشكل، أو الهيئة، هو العنصر الثاني الأكثر استخدامًا في تصميم المواقع. وهو في الواقع عبارة عن خطوط مجموعة جنبًا إلى جنب بأشكال مختلفة. ما زالت الأشكال تحظى بشعبيّة، وسبب هذا يعود إلى الحاجة إلى إبراز شيء ما، والأشكال هي إحدى الطرق للقيام بذلك. قد تكون الأشكال دوائر، مربّعات، مستطيلات، مثلّثات، أو غيرها من الأشكال التجريدية، ومعظم التصاميم تحتوي على الأقل على واحد من هؤلاء. يتمّ استخدام العديد من هذه الأشكال في تصاميم التبسيط للحد الأدنى، لأنها في الغالب تقوم على أساس الرسوم الإيضاحية والمخطّطات. كما إنّ النمط القديم لتصميم المواقع تضمّن الأشكال أيضًا، لذلك بقيت ذات شعبيّة طوال الوقت، وعلى الأرجح ستستمرّ على هذا المنوال. الأشكال، حالها كحال الخطوط، مرتبطة بذهن الإنسان بطرق مختلفة. على سبيل المثال؛ الدوائر مرتبطة بالحركة والطبيعة، بينما يتم النظر إلى المربّعات على أنها تصاميم أساسية هيكلية. وكما هو الحال في الخطوط فإن لون، نمط، خلفية أو خامة الشكل يمكن أن تغيّر كلّيًّا الإدراك الحسّي للمُشاهد. في معرض الأعمال الخاصّ بفريد مايا أعلاه، تمّ استخدام الأشكال لإبراز الشعار والأعمال السابقة. 3. الخامات Texturesلم تكن الخامات ذات شعبيّة منذ بضع سنواتِ مضت، لكنّها تميل إلى أن تصبح أكثر وأكثر استخدامًا. وقد حلّت محل (أو نافست، إذا استطعنا تسميتها منافسة) الخلفيات ذات اللون المفرد. قد تبدو الخامات شبيهة بالخلفيات ذات الألوان المصمتة، لكن عند معاينتها عن قرب، يمكن ملاحظة اختلافات صغيرة ولكنّها فعّالة. تتضمّن أنماط الخامات الورق، الحصى، الخرسانة، الطوب، الألياف، والعناصر الطبيعية، وما بين الألوان الباهتة أو الناعمة. ويمكن للخامات أيضًا أن تكون دقيقة أو بارزة، وأن تستخدم باعتدال أو بإسباغ؛ يمكنها أن تعمل مع أي شيء تقريبًا. من شأن الخامات أن تغيّر شكل الموقع كليّا حتّى وإن بدت غير مهمّة، فهي توفّر وقعًا بصَريًّا مختلفًا تمامًا. في معرض الأعمال الخاص بجيسون جوليان أعلاه، تم استخدام خامة ذات النمط البالي grunge. في هذه الصفحة تمّ استخدام خامة مختلفة عن الخامة في المثال الأول، تبدو هذه كدفتر رياضيات. 4. اللونقد يكون اللون هو العنصر الأكثر أهميّةً في التصميم لأنه يعطي التأثير البصري الأقوى في لمحة واحدة. اللون واضح ولا يحتاج إلى مهارات رسم أساسية لملاحظتها. فبينما تعني الخطوط والأشكال الشيء نفسه كما في الواقع، عدا المستويات الأكثر عمقًا، تعني الألوان الشيء نفسه بالضبط كما في الطبيعة. الألوان تخلق الأحاسيس؛ الأحمر هو العاطفة، الأزرق هو الهدوء، والأخضر هو الطبيعة. للألوان تأثيرٌ واضحٌ على عقولنا حتّى وإن لم نُدرك ذلك. تم إجراء الدّراسات حول هذا الموضوع، ووجِد أن الشخص الذي يعيش في بيئة حمراء يمتلك ضربات قلب ونبضًا أعلى من الشخص الذي يعيش في بيئة زرقاء. الدماغ البشري يرى ذلك ويؤثّر على بقية الجسد تِبَعًا لما يراه. لذلك من المهم معرفة نظرية الألوان، حيث لا يمكن للعديد من المصممين أن يدعوا أنفسهم بالخبراء في هذا المجال. أن تكون خبيرًا في الألوان هو الذي يصنع الفرق بين التصميم الجيّد والتصميم المذهل. لا نقول إنه يجب أن تعرف كل شيء، لكن معرفة كيفية عمل خصائص اللون معًا كالصبغة Hue، الإشباع Saturation، الظل Shade، المشيج Tint، الدرجة Tone، أو الصفاء Chroma لهو أمرٌ جوهريّ بالنسبة لمصمم الجرافيك. في موقع Feed Fever تم استخدام ألوان مختلفة للنصوص في محاولة لإبراز أهمية كل خط باختلاف دقيق. 5. القيمةلم نتحدّث عن القيمة Value في النقطة السابقة على الرغم من أنها مرتبطة بشكل وثيق بعنصر اللون، لأن القيمة هي أكثر عمومية وهي التي تحدّد كون التصميم داكِنًا أو فاتِحًا. كما أن القيمة لها تأثير على المزاج أيضًا، ولكن فقط في مستويات أعمق. إنّ فهمك لخصائص الألوان يأخذك إلى مستويات قريبة من الإتقان، ولكن معرفة عمل وتأثير القيمة يأخذك إلى مستويات أبعد من ذلك. التصاميم الفاتحة تعطي انطباعًا وشعورًا مختلفًا عن التصاميم الداكِنة، ولذلك تحتاج إلى عينيّ خبير لملاحظة الفرق واختيار الأفضل تبعًا لذلك. 6. المساحةللمساحات وطريقة استخدامها تأثيرٌ مهمٌّ جدًّا في التصميم. أصبحت "المساحات البيضاء" (تسمّى أيضًا المساحات السلبية) تستخدم بشكل واسع في الآونة الأخيرة، لأنها تسمح للعين بالقراءة بشكل أسهل. ولمن لا يعرف مصطلح "المساحة البيضاء"؛ لا نقصد هنا أنها مملوءة باللون الأبيض على وجه التحديد، ولكن كل مساحة ضمن التصميم مملوءة فقط بلون الخلفية. يمكنك رؤية العديد من الأمثلة أدناه لفهم أفضل لهذا المفهوم. إذا كان تصميم الصفحة يحتوي على العديد من المساحات السلبيّة فإن هذا يضفي إضاءةً وشعورًا منفتحًا. وبخلاف ذلك يصبح التصميم مبعثرًا وقديم الطراز. وبذلك يكون للمساحات تأثيرٌ مهمّ في الطريقة التي يُنظر بها إلى التصميم من قِبل العين البشريّة. المساحات في مقدمة عناصر التصميم المهمّة، حتّى وإن قلنا إن اللون قد يكون العنصر الأهم، لأن المساحات من السهل ملاحظتها من قِبل العين المبتدئة. كما يمكنها أن تحوّل التصميم لصالحك والحصول على أفضل النتائج لمخطط صفحتك. صفحة جوجل هي أبسط مثال على استخدام المساحات السلبيّة بكثرة. في موقع Site Inspire تمّ استخدام المساحات السلبيّة على الجوانب وجُمع بينها وبين فنون الطباعة المناسبة. الخلاصة كانت هذه هي العناصر الأساسية التي يجب على كل مصمّم جرافيك مبتدئ أن يعرفها. وبالاطلاع على هذه العناصر يمكنك أن تفكّر أكثر من وجهة نظر المستخدم وبالتالي تستطيع التصميم بأسلوب أفضل. لكن هذا ليس كلّ شيء، هنالك المزيد عن مبادئ التصميم سنتحدث عنها في مقالات قادمة -إن شاء الله-. ترجمة -وبتصرّف- للمقال: Graphic Design Basics Part 1: Elements لصاحبه: James Richman. حقوق الصورة البارزة: Designed by Freepik.
  3. css 101

    في هذا الدرس من سلسلة تعلّم CSS، سنشرح كيف يمكن استخدام CSS لتحديد مظهر القوائم؛ وسنتدرّب على ذلك بإنشاء مستند جديد يحوي قوائم، ونُرفقه بورقة أنماط جديدة تُنسّق القوائم الّتي أنشأناها. فهرس السلسلة: مدخل إلى أوراق الأنماط المتتالية (CSS). آلية عمل تعليمات CSS داخل المتصفحات. المحددات (Selectors) في CSS. كيفية كتابة تعليمات CSS يسهل قراءتها. تنسيق نصوص صفحات الويب باستخدام CSS. التعامل مع الألوان في CSS. إضافة محتوى إلى صفحة ويب باستخدام CSS. تنسيق القوائم (Lists) في CSS. (هذا الدرس) تعرف على الصناديق (Boxes) في CSS. رصف العناصر (Layout) في CSS. الجداول (Tables) في CSS. التعامل مع أجهزة العرض المختلفة والمطبوعات في CSS. القوائم إن كنت قد أتممت التّمرين في الدرس السابق "إضافة محتوى إلى صفحة ويب باستخدام CSS" فلعلّك لاحظت كيف يمكن إضافة محتوىً قبل أي عنصر بحيث يظهر وكأنّه عنصرٌ في قائمة. تقدّم CSS بعض الخواصّ المُصمّمة خصّوصًا للقوائم، ومن الأفضل استخدام هذه الخواصّ في معظم الحالات. لتعيين نمط القائمة، استخدام الخاصّة list-style لتحديد نوع العلامة الّتي تظهر قبل كلّ عنصر في القائمة. يمكن استهداف القائمة ذاتها (<ul> مثلًا) بحيث ترث العناصر منها، أو يمكن استهداف العناصر ضمن القائمة (<li> مثلًا). القوائم غير المرتبة في القوائم غير المرتّبة، تكون لكلّ العناصر العلامة ذاتها. تتضمّن CSS ثلاثة أنواع للعلامات: disc (قرص) circle (دائرة) square (مربّع) يمكن أيضًا تحديد رابط صورة لاستخدامها كعلامة للعناصر كخيار بديلٍ. مثال القاعدتان التاليتان تُحدّدان علامات مختلفة لأصناف مختلفة من عناصر القائمة: li.open {list-style: circle;} li.closed {list-style: disc;} نستخدم الأصناف للتمييز بين العناصر المفتوحة والمغلقة (مثلًا: في قائمة مهامّ): <ul> <li class="open">Lorem ipsum</li> <li class="closed">Dolor sit</li> <li class="closed">Amet consectetuer</li> <li class="open">Magna aliquam</li> <li class="closed">Autem veleum</li> </ul> قد تبدو النّتيجة هكذا: القوائم المرتبة في القوائم المُرتّبة، يكون لكل عنصر علامة مختلفة تُميّز موضعه في السلسلة. لتعيين نمط القائمة، استخدام الخاصّة list-style لتحديد نوع العلامة الّتي تظهر قبل كلّ عنصر في القائمة: decimal (أرقام بنظام العدّ العشريّ) lower-roman upper-roman lower-latin upper-latin مثال القاعدة التّالية تجعل العناصر في القائمة المرتّبة <ol> من الصّنف info مرتّبة بحروف لاتينيّة كبيرة: <ol class="info"> <li>Lorem ipsum</li> <li>Dolor sit</li> <li>Amet consectetuer</li> <li>Magna aliquam</li> <li>Autem veleum</li> </ol> ol.info {list-style: upper-latin;} ترث العناصر <li> هذا التنسيق عن القائمة: تفاصيل أكثر الخاصّة list-style هي خاصّة مختصرة، وقد ترغب في التنسيقات المعقّدة باستخدام الخصائص المنفردة لتعيين قيم مستقلّة. للاطّلاع على الخصائص المنفردة، وعلى تفاصيل أكثر عن قوائم CSS، راجع صفحة list-style. إن كنت تستخدم لغة رماز مثل HTML توفّر وسومًا مختلفة للقوائم المرتّبة (<li>) وتلك غير المرتّبة (<ol>)، فيفضّل استخدام هذه القوائم بحسب دلالتها، على أنّه يمكن عرض القوائم المرتّبة لتبدو وكأنها غير مرتّبة من خلال CSS والعكس بالعكس. قد تختلف المتصفّحات في طرق عرضها لتنسيق القوائم، لا تتوقّع الحصول على نتائج متطابقة تمامًا في كلّ المتصفّحات. العدادات ملاحظة هامّة: بعض المتصفحات لا تدعم العدّادات، تقدّم الصّفحة CSS contents and browser compatibility على موقع َQuirks Mode مخطّطًا تفصيليًّا لتوافق المتصفحات مع هذه الميزة وميزات أخرى، كما توفّر الصّفحات الفرديّة في مرجع CSS معلومات عن دعم المتصفّحات. يمكن استخدام العدّادات لعدّ أيّة عناصر، وليس فقط عناصر القوائم، فمثلًا يمكن عدّ العناوين والفقرات في المستند. لمتابعة العدّ، تحتاج إلى إنشاء عدّاد (counter) ذي اسم خاصّ تحدّده بنفسك. يمكن تصفير العدّاد ضمن عنصر ما قبل البدء بالعدّ باستخدام الخاصّة counter-reset مع اسم العدّاد الذي اخترته. الأب المشترك للعناصر الّتي ترغب بعدّها مكانٌ مناسب لتصفير العدّاد، ولكن يمكن استخدام أي عنصر يرد قبل العناصر المطلوب عدّها. في كلّ عنصر ترغب بعدّه، استخدم الخاصّة counter-increment مع اسم العدّاد الّذي اخترته. لعرض العدّاد، استخدام ‎::before‎ أو ‎::after‎ مع المُحدّد واستخدم الخاصّة content (كما شاهدنا في الدّرس السابق عن إضافة المحتوى). استخدم ‎counter()‎ مع اسم العدّاد كقيمة للخاصّة content، ويمكن كذلك استخدام نوع للعلامة (غير إلزاميّ). الأنواع المُتاحة هي ذاتها الّتي عرضناها في فقرة القوائم المرتّبة. يزيد العنصر الّذي يعرض العدّاد قيمته عادةً. مثال هذه القاعدة تُنشئ عدّادًا لكلّ عنصر <h3> من الصّنف numbered: h3.numbered {counter-reset: mynum;} هذه القاعدة تعرض وتزيد العدّاد لكلّ عنصر <p> من الصّنف numbered: <p class="numbered">Lorem ipsum</p> <p class="numbered">Dolor sit</p> <p class="numbered">Amet consectetuer</p> <p class="numbered">Magna aliquam</p> <p class="numbered">Autem veleum</p> body { counter-reset: mynum; } p.numbered:before { content: counter(mynum) ": "; counter-increment: mynum; font-weight: bold; } هكذا تبدو النّتيجة: تفاصيل أكثر لا يمكنك استخدام العدّادات إلّا إن كنت متأكّدًا من أن كلّ جمهورك يستخدم مُتصفّحًا يوفّر العدّادات. إحدى مزايا العدّادات أنّها تُوفّر إمكانيّة تنسيق العدد بصورة مستقلّة عن عنصر القائمة المرافق لها، لاحظ كيف جعلنا العدد ذا خطّ عريض دون عناصر القائمة في المثال السّابق. يمكن أيضًا استخدام العدّادات بطرق أكثر تعقيدًا؛ مثلًا: لعدّ الفقرات والعناوين والعناوين الفرعيّة والفقرات في المستندات الرّسميّة. تمرين: قوائم منسقة أنشئ مستند HTML جديد في ملف doc2.html، انسخ والصق المحتوى التالي: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Sample document 2</title> <link rel="stylesheet" href="style2.css"> </head> <body> <h3 id="oceans">The oceans</h3> <ul> <li>Arctic</li> <li>Atlantic</li> <li>Pacific</li> <li>Indian</li> <li>Southern</li> </ul> <h3 class="numbered">Numbered paragraphs</h3> <p class="numbered">Lorem ipsum</p> <p class="numbered">Dolor sit</p> <p class="numbered">Amet consectetuer</p> <p class="numbered">Magna aliquam</p> <p class="numbered">Autem veleum</p> </body> </html> أنشئ ورقة أنماط جديدة style2.css وضع فيها المحتوى التّالي: /* numbered paragraphs */ h3.numbered {counter-reset: mynum;} p.numbered:before { content: counter(mynum) ": "; counter-increment: mynum; font-weight: bold; } غيّر أسلوب تنسيق الشّيفرة والتعليقات كما تحبّ إن لم يُعجباك. افتح المستند في المتصفّح، إن كان متصفّحك يدعم العدّادات، سترى ما يشبه الصّورة أدناه، وإلّا فلن ترى الأرقام (ولا النّقطتين (:) حتّى في بعض المتصفّحات): تمرين أضف قاعدة إلى ورقة الأنماط السّابقة بحيث تعدّ الأرقام باستخدام الحروف الرّومانيّة من i إلى v: وعدّل ورقة الأنماط بحيث تستخدم العناوين حروفًا لاتينيّة كبيرة: شاهد الحل الحروف الرّومانيّة الصّغيرة عرّف قاعدة لعناصر القائمة لتستخدم lower-roman كقيمة للخاصّة list-style: li { list-style: lower-roman; } الحروف اللاتينيّة الكبيرة أضف قاعدة لمتن المستند (كونه أب العناوين) لتصفير عدّاد جديد، ثمّ زد قيمته عند كلّ عنوان: /* numbered headings */ body {counter-reset: headnum;} h3:before { content: "(" counter(headnum, upper-latin) ") "; counter-increment: headnum; } ما التّالي؟ عندما يعرض المتصفّح مستندك، فإنّه يُنشئ مساحات حول العناصر عندما يضعها في مواضعها في الصّفحة، سنشرح في الدّرس القادم كيف يمكن استخدام CSS للتّعامل مع الأشكال الضّمنيّة للعناصر (المستطيلات) من خلال استخدام الصناديق Boxes في CSS. ترجمة -وبتصرف- للمقال Lists من سلسلة Getting started with CSS على شبكة مطوّري Mozilla.
  4. Object Linking and Embedding (وتكتب اختصارا OLE) هي تقنية استحدثتها شركة مايكروسوفت تتيح مشاركة المعلومات بين البرامج. يُقصد بالربط Linking (في PowerPoint) إنشاء ارتباط بين الملف الأصلي ونسخته داخل العرض التقديمي، وبذلك سيتم تحديث النسخة كلما جرى تغيير على الملف الأصلي. أما التضمين Embedding فيقصد به إنشاء ارتباط بين الكائن/العنصر داخل العرض التقديمي وبرنامج المصدر مما يتيح إمكانية تعديل الكائن/العنصر من داخل باوربوينت نفسه مهما كان امتداده. سنتعلّم في هذا الدرس كيفية ربط الملفات وتضمينها، وكذلك كيفية فصل الارتباط. تضمين العناصر يمكننا تضمين الملفات بطريقتين. الطريقة الأولى هي بتحديد الشريحة التي نرغب في تضمين الملف فيها ثم الذهاب إلى تبويب: إدراج Insert > كائن Object من مربع الحوار "إدراج كائن" لدينا خياران لتضمين الملفات. أما إنشاء ملف جديد من العرض التقديمي نفسه بتحديد الخيار Create New. هذا الخيار أشبه بإنشاء برنامج داخل برنامج. فلو اخترنا إنشاء ورقة اكسل، سيُفتح برنامج اكسل داخل برنامج بوربوينت، ويمكننا العمل على الورقة بهذه الطريقة: أو تضمين ملف موجود مسبقا بتحديد الخيار Create from file: ننقر Browse لاختيار الملف من مجلد الحفظ، ثم موافق OK: سيتم إدراج الملف كأي عنصر آخر داخل العرض التقديمي، وسيكون بإمكاننا تحجيمه باستخدام المقابض أو تحريكه من مكان إلى آخر ضمن الشريحة. الطريقة الأخرى هي نسخ الملف (Ctrl+C) من المجلد المصدر، ثم لصقه في الشريحة (Ctrl+V). وبهذه الطريقة، كسابقتها، يمكن تحجيم الملف الذي تحول إلى عنصر داخل الشريحة أو نقله من مكان إلى آخر. ونلاحظ أيضا ظهور تبويب تنسيق Format الذي يمكننا من خلاله تطبيق عدة تنسيقات على العنصر، كإضافة لون تعبئة من خيار Shape Fill: أو إضافة حدود من خيار Shape Outline: أو غيرها من الخيارات الفعّالة. من مزايا التضمين هو أنّه بإمكاننا تحرير الملف الذي قمنا بتضمينه من داخل العرض التقديمي. كل ما علينا فعلها هو النقر بشكل مزدوج على العنصر. مثلا عند النقر على الجدول الذي قمنا بإدراجه ستُفتح نافذة اكسل داخل نافذة بوربوينت (كأنّما قمنا بفتح اكسل داخل بوربوينت). وتحتوي هذه النافذة على جميع التبويبات الموجودة في برنامج اكسل: يمكننا إجراء أي تغيير على العنصر من خيارات وأوامر تبويبات اكسل، وعند الانتهاء نغلق النافذة الداخلية ونحفظ التغييرات. بإمكاننا تحرير العناصر بطريقة ثانية. ننقر على العنصر بزر الفأرة الأيمن، نمرر المؤشر فوق Worksheet Object ثم نختار تحرير Edit وستُفتح النافذة نفسها. علما أنّ الخيار Worksheet Object سيختلف باختلاف العنصر المحدد. فإذا كنا نحدد مستند وورد سيكون الخيار Document Object. يجب أن نأخذ في الاعتبار أنّ أي تغيير نجريه على العنصر سيقتصر على العنصر المضمّن فقط، ولا يتم تحديث الملف الأصلي وفقا لهذا التغيير. ربط العناصر إنّ ربط العناصر هو بمثابة جعل الملف الذي قمت بتضمينه داخل بوربوينت متزامنا مع الملف الأصلي، وبذلك سيتم تحديث العنصر المضمن كلما قمت بتعديل الملف الأصلي (أو بالعكس). هناك طريقتان أيضا لربط العناصر. الأولى بتحديد الشريحة التي نريد ربط الملف بها، ثم الذهاب إلى تبويب: إدراج Insert > كائن Object سنحدد الخيار الثاني Create from file كما فعلنا في عملية التضمين، ثم ننقر على Browse لاختيار الملف. لكن هذه المرة سنقوم بتأشير الخيار Link لإنشاء ارتباط: وكما يخبرنا التلميح في أسفل مربع الحوار، أن النتيجة ستكون إدراج الملف كملف مختصر shortcut داخل العرض التقديمي، وأنّ إي تغيير نجريه على الملف الأصلي سينعكس التغيير على النسخة داخل العرض التقديمي أيضا. لتحرير العنصر ننقر بشكل مزدوج عليه، ولكن هذه المرة ستُفتح نافذة جديدة مستقلة عن نافذة بوربوينت. وبما أننا قمنا بربط مستند وورد هذه المرّة، ستُفتح نافذة وورد منفصلة يمكننا من خلالها إجراء التغييرات على العنصر باستخدام أوامر وخيارات وورد: سنقوم مثلا بتغيير لون نص العنوان، "General Introduction"، وكذلك نوع الخط، وسنلاحظ تحديث العنصر تلقائيا داخل الشريحة ليعكس هذا التغيير: الطريقة الأخرى لربط العناصر هي باستخدام النسخ واللصق. سنقوم في هذه المرة بربط جزء من ملف وليس كلّه. مثلا، إذا كنا نريد ربط المخطط أدناه فقط من ضمن عناصر الورقة، نقوم بتحديده ثم الضغط على مفتاحي Ctrl+C: نذهب إلى العرض التقديمي، نحدد الشريحة التي نريد لصق العنصر فيها وإنشاء ارتباط بينه وبين النسخة الأصلية، ننقر على السهم تحت أمر لصق Paste ثم نختار Paste Special: في مربع الحوار الذي سيظهر نحدد الخيار لصق كارتباط Paste Link ثم ننقر على موافق OK: سيتم إدراج العنصر وإنشاء ارتباط بينه وبين الملف الأصلي. يمكننا أيضا تغيير حجمه وموضعه. وكذلك تحريره بالنقر بشكل مزدوج عليه أو بالنقر بزر الفأرة الأيمن، تمرير المؤشر فوق Linked Worksheet Object (وهذا الخيار يختلف باختلاف العنصر المحدد) ثم اختيار Edit: ملاحظة: بالإمكان ربط وتضمين مختلف أنواع الملفات، كملفات وورد، اكسل، ملفات PDF، صور، ملفات صوتية، إلخ. تعطيل الروابط وإصلاح الروابط المعطلة إن لم تعد بحاجة إلى الملف المرتبط بالعرض التقديمي، يمكنك تعطيل الارتباط بسهولة. لتعطيل الرابط نذهب إلى تبويب: ملف File > معلومات Info > تحرير الارتباطات إلى الملفات Edit Links to Files في مربع الحوار "Links" تُعرض الارتباطات التي قمنا بإنشائها، وتكون مرتبة حسب الأسبقية، أي الارتباط الذي قمنا بإنشائه أولا سيكون أول ارتباط في القائمة. نحدد الارتباط الذي نرغب في تعطيله ثم ننقر على أمر قطع الارتباط Break Link: عند قطع الارتباط سيتحول العنصر إلى صورة، ويمكننا معرفة ذلك بظهور تبويب Format السياقي الذي يحتوي على أدوات تنسيق الصور، ولن تُفتح نافذة مستقلة عن النقر عليه بشكل مزدوج لتحريره: هناك طريقة أخرى لقطع الارتباط، وهي نقل الملف الأصلي من مجلده إلى مجلد آخر. إذا احتوى العرض التقديمي على ارتباطات، ستظهر نافذة تنبيه كلما قمنا بفتح الملف. وعندما نقوم بتحديث الارتباطات Update Links سيحاول بوربوينت استرجاع جميع المعلومات من الملف المصدر: لكن عندما نقوم بنقل الملف إلى مجلد آخر سيفشل البرنامج في استرجاع المعلومات وستظهر نافذة تخبرنا بالخطأ الذي حصل: إذا لم نتعمّد نقل الملف إلى مجلد آخر وأردنا إصلاح الارتباط ليعمل التزامن من جديد، يمكننا القيام بذلك بتحديث مصدر الارتباط. في المثال أدناه قمنا بنقل مستند وورد الذي قمنا بإدراجه سابقا إلى مجلد آخر، وبذلك تظهر لنا نافذة تنبيه بهذا الخطأ عندما ننقر بشكل مزدوج عليه لتحريره: سنقوم بإصلاح هذا الخلل بالذهاب إلى تبويب: ملف File > معلومات Info > تحرير الارتباطات إلى الملفات Edit Links to Files نحدد الارتباط الذي نريد تغيير مصدره ثم ننقر Change Source: نذهب إلى المجلد الجديد الذي نقلنا الملف إليه، نحدد الملف، ثم ننقر على فتح Open: نغلق نافذة تحرير الارتباطات، وسيتم إنشاء الارتباط من جديد وبذلك يصبح بإمكاننا تحريره.
  5. عند استخدام التحريكات 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.
  6. رؤوس الجداول الثابتة ليست بالأمر الجديد في مواقع الويب. على عكس الورق، حيث يستطيع القارئ نقل نظره بسرعة إلى أعلى الشاشة ليعرف في أي عمود هو، لكن أبعاد الشاشة تجعل من قراءة الجداول الطويلة أمر صعبا. رؤوس الجداول الثابتة، كما يشير اسمها، تبقى ثابتة في أعلى الجدول حتى وإن نزلنا أكثر في الجدول. يساعد الأمر في إبقاء أسماء الأعمدة دوما في متناول اليد، حتى لا يجبر المستخدم على الرجوع إلى أعلى الجدول كل مرة من أجل النظرة ثم الرجوع مجددا. يوجد العديد من سكربتات وإضافات jQuery التي تعمل بطريقة فعالة وخالية من الأخطاء، فهم ليسوا الحل المثالي لجميع المشاكل الممكنة، ففي بعض الحالات، على الجداول أن تتبع قواعد هيكلة لم تحسب لها الإضافات حساب، كالجداول التي تسمح بإظهار مؤشر التحرك (scroll bar) عندما لا تكفي المساحة لإظاهر الجدول. هذا المقال لن يكون الحل المثالي لجميع المواقف، ولكنه سيكون حلا لأغلب المشاكل الشائعة. حل باستخدام CSS فحسب عبر position: sticky؟تملك CSS حلا مناسبا لهذه المشكلة وهو عبر استخدام postion: sticky. لكن للأسف، الحل غير مدعوم في chrome رغم أنه كان مدعوما سابقا، إلا أنّ فريق التطوير قام بإلغاء الخاصية تماما منه إلى أجل غير معلوم. ولأننا لا نستطيع التضحية بكل مستخدمي متصفح chrome فعلينا إيجاد حل بديل للمشكلة. حل عبر استخدام jQueryحل jQuery هو بسيط جدا، لكن قبل أن نبدأ باستخدام، علينا أن نلقي نظرة على كيف يكون جدول ما صحيحا من حيث الهيكلة: <table> <thead> <tr> <th></th> <!-- more columns are possible --> </tr> </thead> <tbody> <tr> <td></td> <!-- more columns are possible --> </tr> <!-- more rows are possible --> </tbody> <tfoot><!-- هذا الجزء اختياري --> <tr> <td></td> </tr> </tfoot> </table>ما الذي نحاول تحقيقه؟سنحاول جعل السكربت يدعم أغلب المشاكل الشائعة والتي هي: الاستخدام الأساسي: رأس الجدول يكون ثابتا.رؤوس الجداول الأفقية والعمودية.الجداول العريضة:العمود الأفقي: إذا كان هنالك العديد من الأعمدة التي لا يمكن إظهارها في عرض الصفحة، فسنستخدم عمودا جانبيا ثابتا.الصف العمودي: وهو الاستخدام الأساسي، أن يكون الرأس العلوي ثابتا عند النزول بالجدول.كلا العمودين: حيث نثبت كل من العمود والصف.CSS من أجل البدءرغم أننا سنستخدم حلاّ عبر جافاسكربت، فإن CSS ضرورية من أجل تنفيذ الأمر: .sticky-wrap { overflow-x: auto; position: relative; margin-bottom: 1.5em; width: 100%; } .sticky-wrap .sticky-thead, .sticky-wrap .sticky-col, .sticky-wrap .sticky-intersect { opacity: 0; position: absolute; top: 0; left: 0; transition: all .125s ease-in-out; z-index: 50; width: auto; /* Prevent table from stretching to full size */ } .sticky-wrap .sticky-thead { box-shadow: 0 0.25em 0.1em -0.1em rgba(0,0,0,.125); z-index: 100; width: 100%; /* Force stretch */ } .sticky-wrap .sticky-intersect { opacity: 1; z-index: 150; } .sticky-wrap .sticky-intersect th { background-color: #666; color: #eee; } .sticky-wrap td, .sticky-wrap th { box-sizing: border-box; }ملاحظة: من المهم جدا نقل كل CSS الخاصة بوسم <table> إلى sticky-wrap. هذا حتى يتاح لنا التحكم بها مباشرة عبر jQuery. لنقل أنك تملك CSS التالي: table { margin: 0 auto 1.5em; width: 75%; }كل ما عليك فعله ببساطة هو نقلها إلى sticky-wrap. : .sticky-wrap { overflow-x: auto; /* Allows wide tables to overflow its containing parent */ position: relative; margin: 0 auto 1.5em; width: 75%; }استخدام جافاسكربتسوف نقوم بتنفيذ دالتنا على كل جدول موجود في الصفحة، الأهم من هذا سنتفقد إن كان الجدول يملك <thead> وإن كان هذا الأخير يحتوي على الأقل على <th> واحد. إن لم تتحق الشروط، فستتجاهل دالتنا هذا الجدول. $(function () { // هنا نقوم باختيار جميع الجداول في الصفحة // لكنك حر بتحديد الجداول التي تريدها $('table').each(function () { if($(this).find('thead').length > 0 && $(this).find('th').length > 0) { // بقية السكربت تكون هنا } }); });الخطوة 1: نسخ عنصر <thead>// تحديد المتغيرات وبعض الاختصارات var $t = $(this), $w = $(window), $thead = $(this).find('thead').clone(), $col = $(this).find('thead, tbody').clone();الخطوة 2: تغليف الجدول ونسخهمن أجل دعم الحالات التي يكون فيها الجدول أعرض من ماهو مسموح (أي عندما يكون عندما عدد كبير من الأعمدة، أو أعمدة طويلة، فنحوي الجدول في <div> حتى نسمح لك بأن يكون scrollable على المحور الأفقي: // احتواء الجدول $t .addClass('sticky-enabled') .css({ margin: 0, width: '100%'; }) .wrap('<div class="sticky-wrap" />'); // تفقد إن كنا قد حددنا بأن يكون الجدول قابلا للتمرير (scroll) على المحور الأفقي if($t.hasClass('overflow-y')) $t.removeClass('overflow-y').parent().addClass('overflow-y'); // صنع رأس جدول جديد بصنف .stiky-head $t.after('<table class="sticky-head" />') // إذا كان <tbody> يحتوي على <th> فنقوم بصنع عمود جديدة ليكون الخانة أعلى الجدول if($t.find('tbody th').length > 0) { $t.after('<table class="sticky-col" /><table class="sticky-intersect" />'); } // اختصارات var $stickyHead = $(this).siblings('.sticky-thead'), $stickyCol = $(this).siblings('.sticky-col'), $stickyInsct = $(this).siblings('.sticky-intersect'), $stickyWrap = $(this).parent('.sticky-wrap');الخطوة 3: وضع محتوى الجداول المنسوخةما سنقوم به الآن هو أخذ المحتوى المنسوخ من الجدول الأصلي ووضعه في الجداول الجديدة التي ستكون ملتصقة: رأس الجدول الجديد سيستلم كامل المحتوى من عنصر <thead> المنسوخ.الأعمدة الملتصقة ستستلم المحتوى من أول عنصر <th> من <thead> وكل عناصر <th> المتبقية من <tbody>.اندماج العمود مع الصف (أيّ الخانة المشتركة بين العمود والصف) ستأخذ محتوى من خلال أعلى خانة على يمين الجدول (بافتراض أننا نتعامل مع الصفحة على أساس RTL).// StickyHead يحصل على المحتوى من <thead> $stickyHead.append($thead); $stickyCol .append($col) .find('thead th:gt(0)').remove() .end() .find('tbody td').remove(); // StickyIntersect يحصل على المحتوى من <th> في <thead> $stickyInsct.html('<thead><tr><th>'+$t.find('thead th:first-child').html()+'</th></tr></thead>');الخطوة 4: الدوالهنا يأتي أهم جزء من السكربت الخاص بنا، سنحدد أيّ دوال يجب أن تنفذ من أجل أن يعمل السكربت بشكل صحيح: دالة من أجل تحديد عرض عناصر <th> في رأس الجدول المنسوخ، بما أننا نسخنا عنصر <thead> فحسب، فعرض رأس الصفحة المنسوخ الكلي لن يكون عرض رأس الصفحة الفعلي، لأن عرض <tbody> لم يتم إضافته حيث لا نعلم هل سيؤثر على رأس الصفحة أو لا.دالة من أجل تحديد مكان رأس الصفحة الثابت حتى نقوم بتحديث بُعد رأس الصفحة المنسوخ الأفقي، الذي قمنا بتحديد position: absolute عندما نبدأ بتمرير شريط التقدم داخل الجدول.دالة من أجل تحديد مكان العمود الجانبي الثابت ولها نفس حالة تثبيت رأس الصفحة.دالة من أجل حساب المساحة المتبقية وسنقوم بشرح هذه الدالة لاحقا بشكل أعمق. // Function 1: setWidths() // Purpose: To set width of individually cloned element var setWidths = function () { $t .find('thead th').each(function (i) { $stickyHead.find('th').eq(i).width($(this).width()); }) .end() .find('tr').each(function (i) { $stickyCol.find('tr').eq(i).height($(this).height()); }); // Set width of sticky table head $stickyHead.width($t.width()); // Set width of sticky table col $stickyCol.find('th').add($stickyInsct.find('th')).width($t.find('thead th').width()) }, // Function 2: repositionStickyHead() // Purpose: To position the cloned sticky header (always present) appropriately repositionStickyHead = function () { // Return value of calculated allowance var allowance = calcAllowance(); // Check if wrapper parent is overflowing along the y-axis if($t.height() > $stickyWrap.height()) { // If it is overflowing // Position sticky header based on wrapper's scrollTop() if($stickyWrap.scrollTop() > 0) { // When top of wrapping parent is out of view $stickyHead.add($stickyInsct).css({ opacity: 1, top: $stickyWrap.scrollTop() }); } else { // When top of wrapping parent is in view $stickyHead.add($stickyInsct).css({ opacity: 0, top: 0 }); } } else { // If it is not overflowing (basic layout) // Position sticky header based on viewport scrollTop() if($w.scrollTop() > $t.offset().top && $w.scrollTop() < $t.offset().top + $t.outerHeight() - allowance) { // When top of viewport is within the table, and we set an allowance later // Action: Show sticky header and intersect, and set top to the right value $stickyHead.add($sticktInsct).css({ opacity: 1, top: $w.scrollTop() - $t.offset().top }); } else { // When top of viewport is above or below table // Action: Hide sticky header and intersect $sticky.add($stickInsct).css({ opacity: 0, top: 0 }); } } }, // Function 3: repositionStickyCol() // Purpose: To position the cloned sticky column (if present) appropriately repositionStickyCol = function () { if($stickyWrap.scrollLeft() > 0) { // When left of wrapping parent is out of view // Show sticky column and intersect $stickyCol.add($stickyInsct).css({ opacity: 1, left: $stickyWrap.scrollLeft() }); } else { // When left of wrapping parent is in view // Hide sticky column but not the intersect // Reset left position $stickyCol .css({ opacity: 0 }) .add($stickyInsct).css({ left: 0 }); } }, // Function 4: calcAllowance() // Purpose: Return value of calculated allowance calcAllowance = function () { var a = 0; // Get sum of height of last three rows $t.find('tbody tr:lt(3)').each(function () { a += $(this).height(); }); // Set fail safe limit (last three row might be too tall) // Set arbitrary limit at 0.25 of viewport height, or you can use an arbitrary pixel value if(a > $w.height()*0.25) { a = $w.height()*0.25; } // Add height of sticky header itself a += $sticky.height(); return a; }; }والآن سنقوم بشرح ما قمنا به في الدالة الرابعة، نحن لا نريد من رأس الجدول أن يلحقنا إلى أسفل الجدول، فالأمر غير ضروري وقد يغطي لنا آخر سطر من الجدول، لذا من الضروري إبقاء مساحة فارغة في الأسفل. حسب ما جربت، فقد اكتشفت أننا لا نحتاج لرأس الجدول عندما نصل لأخر 3 سطور من الجدول لأن تركيزنا انتقل على المحتوى الآن. $t.find('tbody tr:lt(4)').each(function () { allowance += $(this).height(); });الخطوة 5: ربط كل شيءوالآن قد انتهينا من تعريف كل الدوال اللازمة، كل ما تبقى هو ربط المتفقدات أو (Event handlers) مع عنصر(window)$. عندما يجهز الـDOM نقوم بالحسابات الأولية للعرض.عندما تحمل كامل المعلومات نقوم بحساب الأبعاد مرة أخرى، هذه الخطوة مهمة لأن جدولك قد يحتوي على أشياء تحمل بعد الـ DOM مثل الصور وخطوط الويب.عندما يتم التمرير في الحاوي الرئيسي ولكن هذا سيحدث في حالة كان المحتوى أكبر من عرض الحاوي، حينها نريد إعادة تغيير مكان العمود الرئيسي.عندما يتم تصغير نافذة المتصفح نريد إعادة حساب العرض.عندم يتم النزول في المتصفح نريد أن نغير مكان رأس الجدول.يمكن تلخيص ما قلناه للتو في الكود التالي. يجدر الذكر أن أحداث التصغير والتمرير يتم التحكم بهما باستخدام إضافة throttle+debounce. // #1: DOMعندما يجهز الـ setWidths(); // #2: نراقب الحاوي في حال حدوث تمرير فيه $t.parent('.sticky-wrap').scroll($.throttle(250, function() { repositionStickyHead(); repositionStickyCol(); })); // الآن نربط ما قمنا بعنصر $(window) $w // #3: عندما يتم تحميل كامل المحتويات .load(setWidths) // #4: عندما يتم تصغير النافذة // قمنا باستخدام throttle هنا حتى لا يتم إطلاق الحدث أكثر من مرة (في الوضع الافتراضي يتم إطلاق الحدث من أجل كل جزء يتم تصغيره، هنا ننتظر حتى ينتهي التصغير كاملا ثم نطلق) .resize($.throttle(250, function () { setWidths(); repositionStickyHead(); repositionStickyCol(); }) // #5: عندما يتم النزول في النافذة // استخدمنا throttle حتى لا يتم إطلاق الدالة كثيرا .scroll($.throttle(250, repositionStickyHead);وانتيهنا، كان هذا كل شيء! النقاشنحن نعرف أن لاشيء كامل، لذا سنناقش الطرق الأخرى التي تملك محاسن على هذه الطريقة ومساوئها ولم استخدمنا هذه الطريقة. استخدام position: fixedاستخدام هذه الطريقة قد يبدو مغريا لسبيين: لا يوجد حاجة لحسابات من أجل رأس الجدول، لأن العنصر المثبت (fixed) يقع خارج الصفحة الفعلية وسيبقى ثابتا في مكانه.نتجنب البطء في الحسابات هذا لأن العناصر الثابتة تلاحق الجدول ولا تثبت معه، لأننا نقوم بالحساب في فترات ثابتة (عبر throttle) وبالتالي سيظهر أن العنصر الثابت غير متجاوب وبالتالي غير طبيعي.لكن المشكلة في هذه الطريقة هي أننا نزيل العنصر من رونق الصفحة، ففي حالة تجاوز عرض الجدول العرض المسموح وأصبح من الضروري إضافة scroll فإن رأس لن يلحق المحتوى على المحور الأفقي لأنه ثابت في الصفحة. وهذا سبب كبير لا يسمح لنا باستخدام أغلب إضافات jQuery التي تقدم هذه الخواص. وكتبت هذه الدورة من أجل إصلاح هذا الأمر بالتحديد. استخدام position: stickyالخاصية الجديدة مناسبة للأمر، في الواقع لقد بنيت من أجل هذا الأمر في الحسبان، المشكلة فيها أنها غير مدعومة من متصفح chrome (سبق وكانت مدعومة ولكن أزيل الدعم كليا) وبذلك تفقد كل الزوار من هذا المتصفح. مثال حي:See the Pen avovoo by Hsoub Academy (@HsoubAcademy) on CodePen. ترجمة -وبتصرف- للمقال: Sticky Table Headers & Columns لصاحبه Terry Mun.