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

خفايا CSS المُملّة التي يجب عليك الإلمام بها


نذير صغير

لربما لاحظت مُؤخّرا أنّ CSS في تطور مستمر، وإلى الأفضل بالطبع. فمن جهة لدينا العديد من المُميّزات الجديدة (مثل القواعد الجديدة @rules وأشباه الأصناف المطورة) ونظم بناء الصّفحات وتقسيمها (مثل flexbox و Grid system). ومن جهة أخرى لدينا بعض الأدوات التي تُتيح لنا التّلاعب بالأشكال والصور مباشرة من المتصفح، وأنا أحب هذه الأمور، ومتأكد من أنّك تُحبّها أيضًا، وفي هذه المقالة سنعرض بعضا منها.

سنتحدث عن بعض الأمور التي لا تحظى بالكثير من الشّهرة عادة، هذه الأمور المجهولة ستزيد من إنتاجيتك بشكل مُعتبر، وستجعلك تُفكّر بطرق مُختلفة لحلّ المشاكل اليومية. بعض هذه الأمور هي المُحدّدات Selectors الجديدة الخاصة باللغة، والبعض الآخر عبارة عن دوال، وأشباه أصناف pseudo-classes جديدة.

وحدات القياس النّسبية

بحكم أنّنا في 2015 فلابد وأنّك قد تعاملت من قبل مع الوحدات النّسبية em والنّسب المئوية. ولذا فأنا واثق من أنّك وقعت في المُشكلة الشّائعة والتي تكمن في استخدام هذه الوحدات ضمن الوراثة. سأشرح الأمر بمثال بسيط. من الشّائع مُؤخّرًا أن يتمّ استعمال حجم خط ثابت في الصّفحة، ومن بعدها استعمال وحدات القياس النّسبية لتحديد حجم الخطّ لبقية العناصر في الصفحة.
في CSS سيبدو الأمر كالتالي:

html { font-size: 10px; } 
 p { font-size: 1.4em; }

إلى غاية هذه اللحظة، كل شيء يسير على ما يرام. لكن تظهر المشكلة عندما تريد أن تحدد حجم خط مُختلف لعنصر ما داخل العُنصر السّابق. لنجرب المثال التالي:

The cat sat on the <span>mat</span>.

إذا أردت أن يكون حجم خط span أصغر مثلا، وليكن مثلًا 1.2em، فما الذي ستفعله؟ تحضر الآلة الحاسبة وتحسب نتيجة 1.2/1.4؟ لتحصل على شيء كهذا:

p span { font-size: 0.85714em; }

مشكلة الوراثة ليست محدودة في em فحسب. فإذا كُنت تستخدم النّسب المئوية فالقيمة عادة منسوبة إلى العنصر الحاوي (الأب) وليس إلى حجم الصّفحة. لنضرب مثالًا بسيطًا، ولنقل أنك تملك عنصرًا بارتفاع يُقدّر بـ75% من الصفحة، وهذا العنصر يملك بداخله عنصرًا آخر، ونحن نريد من العنصر الابن أن يكون بارتفاع 40% من الصفحة، في هذه الحالة عليك أن تعطيه قيمة 53.33333%.

الأمر ليس مثالّيًّا إطلاقًا.

القيم المنسوبة إلى أساس ثابت

كالعادة، لكل مشكلة حل. في حالتنا تم تقديم وحدة جديدة تُدعى rem. هذه الوحدة هي وحدة نسبية، ولكنها منسوبة إلى قيمة ثابتة وليس إلى حاويها. هذه القيمة هي حجم الخط في العنصر الأساسي في الصفحة (في حالة HTML فهذا العنصر هو دوما وسم html ). في مثالنا السابق، استعملنا 10px كحجم الخط في الصفحة، سنرى كيف يمكن لـrem أن تساعدنا:

p { font-size: 1.4rem; }
p span { font-size: 1.2rem; }

الآن كلاّ من قيمة التصريحين منسوبة إلى حجم الخط المبدئي، وهذا أفضل من ناحية التّحكم والاستخدام. خُصوصًا إذا كنت تملك حجمًا مبدئيًّا بسيطًا مثل 10px أو 12px. الأمر شبيه باستخدام وحدة البكسل مُجدّدًا، عدى أنها قابلة للتوسع.

هذه الخاصّيّة مدعومة بشكل جيّد من المُتصفّحات. كل المُتصفّحات المُتطوّرة إلى جانب IE9 تقوم بدعمها.
لكن هناك مشاكل بسيطة في الدعم، فمُتصفّح IE لا يدعمها في حال ما إذا استخدمتها داخل الخاصّيّة المُختصرة font ويتم تجاهل التّصريح كاملًا. تستطيع قراءة المشاكل المعروفة هنا في خانة Known Issues في الأسفل Can I use rem.

وحدات القياس المنسوبة إلى النّافذة (Viewport)

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

الوحدات الرّئيسية هي vh (التي ترمز إلى viewport height) و vw (التي ترمز إلى viewport width) وهي منسوبة إلى ارتفاع وعرض النّافذة. الوحدتان منسوبتان إلى أبعاد النّافذة حيث أن قيمة واحدة تقدر بـ 1 بالمئة من أبعاد الشّاشة. أيّ `1vw = 1%’. هذا مثال بسيط لنشرح به الأمر:

div { height: 50vh; }

في هذا المثال، ارتفاع العنصر سيكون بالتّحديد نصف ارتفاع النافذة، حيث أنّه -كما أسلفنا- 1vh = 1% أيّ أن 50vh = 50%من ارتفاع النّافذة.

قيمة الوحدة -كما سبقت الإشارة إليه- منسوبة إلى أبعاد النّافذة، فإذا تغيّر حجم النافذة ستتغير معه قيمة الوحدة. أُنشئت هذه الوحدة لتحل مشكلة النّسب المئوية في الوراثة، حيث أنّ10vw ستبقى دومًا منسوبة إلى حجم النّافذة مهما كان حجم الحاوي.

هناك أيضا وحدة vmin والتي تُساوي أصغر قيمة من أيّ من vh أو vw، إلى جانب وحدة vmax التي تقوم بالعكس أيّ أكبر قيمة من أيّ منهما.

دعم المتصفحات جيد، فكل المتصفحات إلى جانب IE9 تقوم بدعم كل من vh وvw. دعم وحدة vmin جيّد أيضًا، على عكس وحدة vmax فهي غير مدعومة في كل إصدارات IE.
هناك بعض المشاكل في chrome في الإصدارات التي سبقت 34 (عند استعمال الوحدة داخل border وبعض التصريحات الأخرى) Can I use Viewport units.

القيم المحسوبة

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

div {
  margin:  20px;
  width: 33%; 
}

إن كنت تستخدم قيم padding و border فحسب في تقسيم عناصرك في الصّفحة، فتستطيع تخطّي المُشكلة السّابقة عبر استخدام box-sizing: border-box ولكن هذه الخاصّيّة لن تُساعدك في حال كنت تستخدم الحواشي margins. لذا تم توفير دالة تُدعى بـ calc(). هذه الدّالة تسمح لك بالقيام بعمليات حسابية على مختلف الوحدات. شاهد هذا المثال:

div {
  margin:  20px;
  width: calc(33% - 40px);
}

تستطيع استعمال الخاصّيّة في أيّ مكان تريد، ولو داخل نفسها. انظر للمثال في الأسفل:

width: calc(calc(50% - 4em) + 4vmin);

هذه الخاصّيّة مدعومة بشكل جيد، كل الإصدارات الحديثة من المُتصفّحات إلى جانب الإصدار 9 من IE تدعمها (هناك بعض الاستثناءات التي يمكنك قراءتها في خانة known issues على Can I use calc()).

تحميل مجموعة مُعيّنة من الأحرف

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

الخاصية الجديدة تُدعى unicode-range وهي تأخذ مجالًا مُعيّنًا من unicode كقيمة (unicode هو إعطاء كل محرف قيمة له على مجال ما، مثلا الأحرف العربية تقع في المجال 0600—06FF وتقدر بحوالي 255 رمز، وكل ترميز يخصّ محرفًا).

هذه الخاصّيّة تُضاف إلى تصريح @font-face. وعندما يقوم المُتصفّح بجلب الخط، سيقوم بجلب الحُرُوف المُحدّدة فحسب، ويتم التّخلّص من الحروف غير المرغوب فيها. الأمر مُفيدٌ جدًّا في الخطوط الكبيرة جدًّا مثل Helvetica الذي يُقدّر حجمه بـ500kbs ويحتوي أغلب لغات العالم.

في هذا المثال سنقوم بسحب الحروف “عـ ، ـلـ، ـم” (يجب التّنويه إلى أنّ حرف العين المُنفصل ‘ع’ يملك رمزًا مُستقلّا عن حرف العين في أول الكلمة ‘عـ’ والذي يملك رمزًا مُستقلًّا عن نفس الحرف في نهاية الكلمة أو في وسطها، وهذا الأمر ينطبق على كلّ الحروف. تستطيع معرفة ترميز كل حرف من هنا).

@font-face {
  font-family: foo;
  src: url('helvetica.ttf');
  unicode-range: U+FECB,U+FEE0,U+FEE2;
}

في هذا المثال سنقوم بسحب الحروف العربية فقط عبر مجال كامل:

@font-face {
  font-family: foo;
  src: url('helvetica.ttf');
  unicode-range: U+0600-06FF;
}

سيُقلّل هذا من حجم الخط من 500kb إلى حوالي 30kb وهذا تحسن مُمتاز جدًّا.

دعم المُتصفّحات ليس جيّدًا بما فيه الكفاية حاليًّا، الخاصية مدعومة من طرف chrome و من طرف Safari ومتصفح فيَرفُكس سيدعم الخاصية ابتدءًا من الإصدار 36، كما أنّها مدعومة من طرف IE9+ لكن يتم تجاهلها إذا استُخدمت u على شكل صغير (lowercase).

Can I use Font unicode-range subsetting

أشباه الأصناف الجديدة (pseudo-classes)

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

شبه صنف التّجاهل (negation pseudo-class)

شبه صنف التجاهل الجديد not() هو صنع رائع جدا إذا عرفت أين تستخدمه. لتستخدمه عليك أن تُمرّر مُحدّدًا (على شرط أن لا يكون مُركّبًا). سيتم تطبيق كل التأثيرات المُرادة على مجموعة العناصر هذه عدى العُنصر الذي تمّ تمريره للصّنف. فلنلق نظرة على المثال التّالي:

لنقل أن لديك مجموعة من العناصر، وتريد أنّ تغيّر لون كل عنصر ذي مرتبة زوجية ما عدى العنصر الأخير، ستقوم بشيء كهذا:

li { color: white;}
li:nth-child(even) { color: red;}
li:last-child { color: white;}

لكن عبر مُحدّد التّجاهل تستطيع القيام بهذا عبر الشكل التالي

li { color: white;}
li:nth-child(even):not(:last-child) { color: red;}

الخاصّيّة ليست عجيبة، فكما رأيت تستطيع أن تعيش بدونها، ولكنك ستقع في حالات تكون فيها الخاصية مُفيدة جدًّا. الخاصّيّة مدعومة بشكل جيد من طرف المُتصفّحات الحديثة ومن طرف IE9+.

شبه صنف المُطابقة (matches-any pseudo-class)

شبه صنف matches() يقبل مُحدِّدًا (selector)، أو مُحدِّدًا مُركّبًا، أو مجموعة من المُحدّدَات. لكن ما الذي يفعله؟

إنّه مفيد للقيام بتأثير ما على مجموعة من العناصر. كمثال، تخيل أنّه لديك مجموعة من وسوم الفقرات <p> في أماكن مختلفة من الصّفحة، وأنت تريد التّأثير على مجموعة مُعيّنة منها، قد تقوم بالأمر التّالي:

.home header p,
.home footer p,
.home aside p {
  color: #F00;
}

لكن مع matches() تستطيع اختصار الأمر السّابق عبر إيجاد الأمور المشتركة في ما سبق. في مثالنا كل سطر يبدأ بـ .home وينتهي بـ p، لذا نستطيع استخدام matches() لتحديد كل العناصر الموجودة بينهما. لم تفهم كيف سنقوم بذلك؟ لابأس، هذا ما سنفعله:

.home :matches(header,footer,aside) p { color: #F00; }

شبه الصنف هذا هو جزء من CSS4 لذا دعمه ليس قويًّا كالبقية.

حاليًّا تستطيع استخدامه مع chrome و safari بشكل عادي وفي IE9+ تحت الاسم matchesSelector وفي فيَرفُكس أيضًا، من الأفضل أخط الحيطة واستخدامه مع -moz- و -webkit- قبل اسمه.

Can I use matches() DOM method

إذًا، ما رأيك في ما سبق؟

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

الميزات الجديدة الأخرى مثل المُرشِّحات (filters) الخاصّة بالصّور قد تكون أجمل ولكن استخدامها محدُود على عكس الميزات التي استعرضناها.

كل واحدة منها تستطيع جعل حياتك أسهل بشكل أكثر، ولكن لا تتوقّف هنا. هناك الكثير لتتعلمه فلا تتوقف عن البحث.

ترجمة -وبتصرّف- للمقال Learning to Love the Boring Bits of CSS لصاحبه Peter Gasston


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

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



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

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

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

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

  Only 75 emoji are allowed.

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

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

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


×
×
  • أضف...