أساسيات CSS للمختبِرين

أوراق الأنماط المتتالية (CSS – Cascading Style Sheets) هي اللغة التي تحدد شكل عناصر HTML وموضعها: الألوان والخطوط والأحجام والمسافات والتخطيط، وما يتغيّر عند مرور المؤشر، أو عند وصول تركيز لوحة المفاتيح إلى العنصر، أو على شاشة ضيقة. فشيفرة HTML تقول إن في صفحة الدفع زراً «ادفع الآن»، وCSS تجعله أزرق، وبعرض الشاشة كاملاً على الهاتف، وتحيطه بإطار حين يكون التركيز عليه.

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

لماذا يهم

العيوب المرئية أول ما يلاحظه المستخدم. فالسعر الذي ينزل تحت زره، أو الحقل المختبئ خلف ترويسة ثابتة، يجعل المنتج يبدو معطوباً حتى لو عملت كل وظائفه. وبعضها إخفاق في إمكانية الوصول أيضاً: فإزالة إطار التركيز دون بديل إخفاق في معيار النجاح 2.4.7 Focus Visible من WCAG 2.2.

ومعرفة CSS تحوّل عبارة «التخطيط معطوب على الجوال» إلى تقرير يستطيع المطور العمل به: العنصر، وعرض منفذ العرض (Viewport)، والأحجام المحسوبة، والقاعدة المعنية. وتخبرك أيضاً بما يجب إعادة اختباره، لأن قاعدة واحدة قد تنسّق كل صفحة تستخدم الصنف نفسه.

القواعد والمحددات والتتالي

ورقة الأنماط قائمة من القواعد. لكل قاعدة محدِّد (Selector) يختار العناصر، وكتلة تصريحات (Declaration block) بين قوسين معقوفين تضم أزواج property: value. ففي #checkout .btn:hover { background-color: #0a58ca; } يختار المحدِّد العناصر ذات الصنف btn الموجودة داخل العنصر ذي المعرّف checkout، ما دام المؤشر فوقها. وتصل CSS إلى الصفحة من أوراق أنماط مرتبطة، ومن عناصر <style>، ومن السمة style، فوق الأنماط الافتراضية للمتصفح نفسه.

وعندما تضبط عدة قواعد الخاصية نفسها على عنصر واحد، يختار التتالي (Cascade) إحداها. وبتبسيط: يفوز !important؛ ثم تتغلب السمة style على قواعد أوراق الأنماط؛ ثم يفوز المحدِّد الأعلى خصوصية (Specificity)؛ وعند تساوي الخصوصية تفوز القاعدة اللاحقة. وتَعُدّ الخصوصية المعرّفات أولاً، ثم الأصناف والسمات والأصناف الزائفة، ثم أنواع العناصر والعناصر الزائفة، فخصوصية #checkout .btn هي 1,1,0، والمعرّف الواحد يرجح على أي عدد من الأصناف. وبعض الخصائص، مثل color وfont-family، يرثها العنصر الابن من أبيه أيضاً.

  • button محدِّد نوع (Type) يختار كل عنصر <button>، و.btn-primary محدِّد صنف (Class) يختار كل عنصر تضم سمته class الصنفَ btn-primary بين أصنافها، و#email محدِّد معرّف (ID) يختار العنصر الوحيد الذي يحمل id="email".
  • [type="email"] و[data-testid="pay-now"] محددا سمة (Attribute)؛ و[href^="https"] يطابق القيم التي تبدأ بـ https.
  • المُركِّبات (Combinators) تربط المحددات بعضها ببعض: المسافة تعني «في أي مكان داخل» (form .error)، و> تعني «ابن مباشر لـ» (ul > li).
  • :hover و:focus-visible و:disabled و:checked و:invalid أصناف زائفة (Pseudo-classes) للحالات؛ ولكل حالة أنماطها، فتحتاج كل حالة إلى فحص خاص بها.
  • ::before و::placeholder عناصر زائفة (Pseudo-elements): تنسّق أجزاءً ليست عناصر في HTML.
/* Three rules set one property on the same button */
.btn           { background-color: #0b5ed7; }  /* 0,1,0                      */
#checkout .btn { background-color: #6c757d; }  /* 1,1,0: wins, it has an id  */
.btn           { background-color: #198754; }  /* 0,1,0: later, still loses  */

جرّبها: منسّق CSS جرّبها: محوّل الألوان

نموذج الصندوق

يرسم المتصفح كل عنصر صندوقاً من أربع طبقات، من الداخل إلى الخارج: المحتوى (Content)؛ ثم الحشوة (Padding) التي تُظهر الخلفية وتُحسب من العنصر عند النقر عليها؛ ثم الحدّ (Border)؛ ثم الهامش (Margin)، وهو مسافة شفافة تُبعد العناصر المجاورة. وتُعرف هذه الطبقات معاً بنموذج الصندوق (Box Model).

نموذج الصندوق من الخارج إلى الداخل: الهامش فالحدّ فالحشوة فالمحتوى. ومع content-box الافتراضي يضبط width: 300px المحتوى وحده، فتجعل حشوةُ 16px وحدٌّ بعرض 2px على كل جانب عرضَ الصندوق 336px.
  1. 1الهامش (Margin)خارج الصندوقمسافة شفافة تُبعد العناصر المجاورة

    لا يدخل في width أبداً

    1. 2الحدّ (Border)2pxالخط المرسوم حول الحشوة

      يضيف 2 × 2 = 4px مع content-box

      1. 3الحشوة (Padding)16pxتُظهر الخلفية وتُحسب من العنصر عند النقر عليها

        تضيف 2 × 16 = 32px مع content-box

        1. 4المحتوى (Content)300pxما يضبطه width مع content-box الافتراضي

          ومع border-box يبقى الصندوق 300px ويتقلص المحتوى إلى 264px

القيم مأخوذة من مثال هذا القسم: width: 300px وpadding: 16px وحدّ بعرض 2px.

وتحدد الخاصية box-sizing ما يقيسه width. فمع القيمة الافتراضية content-box يضبط المحتوى وحده، فتُضاف الحشوة والحدّ فوقه: width: 300px مع padding: 16px وحدّ 2px تعطي صندوقاً عرضه ⁦336⁩ بكسل. ومع border-box يبقى الصندوق ⁦300⁩ بكسل ويتقلص المحتوى إلى ⁦264⁩. ولا يدخل الهامش في width أبداً. وكثير من المواقع تضبط border-box على كل العناصر، والمكوّن الذي يفوته ذلك ينتج صناديق أعرض قليلاً من اللازم.

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

  • display: none يزيل العنصر: لا مساحة، ولا نقرات، ومخفي عن قارئات الشاشة.
  • visibility: hidden يُبقي مساحته لكنه يخفيه عن العين والنقرات وقارئات الشاشة.
  • opacity: 0 يجعله شفافاً فقط: ما زال يستقبل النقرات وتعلنه قارئات الشاشة، فقد تحجب طبقة غير مرئية فوق زرٍّ ذلك الزر.

التخطيط واستعلامات الوسائط والعيوب التي تسببها

تتراص العناصر الكتلية مثل <div> عمودياً، وتنساب العناصر السطرية مثل <a> على امتداد السطر. ويرتب Flexbox عبر display: flex العناصر الأبناء في صف واحد أو عمود واحد، ويتحكم في تمددها وانكماشها والتفافها ومحاذاتها؛ أما Grid عبر display: grid فيضعها في صفوف وأعمدة معاً، فالتصريح grid-template-columns: repeat(3, 1fr) ينشئ ثلاثة أعمدة متساوية. وكلاهما يتبع اتجاه الكتابة، فيبدأ صف Flexbox من اليمين في الصفحة العربية. وتُخرج position: absolute وfixed العناصر من التدفق، ويُبقي sticky العنصر ظاهراً أثناء تمرير الصفحة، ويحدد z-index أي العناصر المتداخلة يظهر في الأعلى.

ويطبّق استعلام الوسائط (Media query) القواعد فقط عندما يتحقق شرط: @media (max-width: 600px) { … } يُطبَّق حين يكون عرض منفذ العرض ⁦600⁩ بكسل CSS أو أقل، فيحصل العرض ⁦600⁩ على تخطيط الهاتف ولا يحصل عليه ⁦601⁩. وبكسلات CSS ليست بكسلات الجهاز؛ فالهاتف عالي الكثافة يستخدم عدة بكسلات جهاز لكل بكسل CSS. ولا يعمل ذلك على الهواتف إلا إذا احتوت الصفحة على عنصر <meta> الخاص بمنفذ العرض، الذي رأيته في هيكل الصفحة في درس HTML؛ فبدونه يرسم الهاتف الصفحة كأنها على شاشة عريضة ثم يصغّرها. وكل نقطة توقف (Breakpoint) حدٌّ يُختبر من جانبيه. وتستجيب الاستعلامات أيضاً لـ prefers-color-scheme: dark وprefers-reduced-motion وللطباعة.

ويعود معظم العيوب المرئية إلى هذه الخصائص أو إلى نموذج الصندوق:

  • نص مقصوص أو فائض: height أو width ثابت، أو overflow: hidden، أو white-space: nowrap؛ وتكشفه الأسماء الطويلة والترجمات والنص المكبَّر.
  • التداخل: تموضع مطلق أو ثابت، أو هوامش سالبة، أو z-index خاطئ. والترويسة الثابتة التي تحجب الحقل الذي عليه التركيز حجباً كاملاً إخفاق أيضاً في المعيار 2.4.11 Focus Not Obscured (Minimum) من WCAG 2.2.
  • تمرير أفقي على الهواتف: عروض ثابتة، أو صور بلا max-width: 100%، أو صفوف Flexbox لا تلتف أبداً (القيمة الافتراضية لـ flex-wrap هي nowrap)، أو حساب box-sizing.
  • عدم المحاذاة: عناصر متشابهة بهوامش أو حشوات أو إعدادات محاذاة مختلفة.
  • نص غير مقروء: لون قريب جداً من الخلفية، وكثيراً ما يظهر في الوضع الداكن أو عند مرور المؤشر فقط.
  • تركيز غير مرئي: outline: none دون نمط بديل.
  • عيوب العكس في الصفحات من اليمين إلى اليسار: الخصائص الفيزيائية مثل margin-left لا تنعكس، بينما تنعكس Flexbox وGrid والخصائص المنطقية مثل margin-inline-start.

مثال تطبيقي: بطاقة تتمرر أفقياً

يبلّغ زميل أن صفحة الدفع تتمرر أفقياً على الهاتف. تفتح أدوات المطوّر (DevTools) في المتصفح بالمفتاح F12، وتشغّل وضع الأجهزة (Ctrl+Shift+M في Chrome وEdge وFirefox) الذي يتيح ضبط منفذ العرض على أي عرض. عند ⁦360⁩ بكسل تبرز بطاقة العرض الترويجي خارج حافة الشاشة؛ أما على عروض سطح المكتب فتبدو سليمة. شيفرة CSS أدناه، والعنصر الأب للبطاقة بعرض منفذ العرض نفسه.

انقر البطاقة بزر الفأرة الأيمن واختر Inspect. تسرد لوحة الأنماط (Styles) القواعد التي تنطبق عليها، مع شطب التصريحات التي غُلبت: استعلام الوسائط فعّال، فتنطبق width: 100%. ويُظهر مخطط نموذج الصندوق في لوحة القيم المحسوبة (Computed) حشوة ⁦16⁩ بكسل وحدّاً بعرض ⁦2⁩ بكسل على كل جانب. ومع content-box الافتراضي: ⁦360 + 2 × 16 + 2 × 2 = 396⁩ بكسل، أي أعرض من الشاشة بـ ⁦36⁩ بكسل. والزيادة نفسها، ⁦36⁩ بكسل، تُضاف عند كل عرض حتى ⁦480⁩؛ ومن ⁦481⁩ يصبح عرض البطاقة ⁦320 + 36 = 356⁩ بكسل فتبقى داخل الشاشة.

ويذكر تقرير الخطأ حقائق: الصفحة، والعنصر (.promo-card)، والمتصفح، ومنفذ العرض (كل عرض حتى ⁦480⁩ بكسل؛ والعرض ⁦481⁩ سليم)، والنتيجة المتوقعة (البطاقة تبقى داخل عرض الشاشة) والنتيجة الفعلية (صندوق بعرض ⁦396⁩ بكسل وشريط تمرير أفقي عند ⁦360⁩)، مع لقطة شاشة والقيم المحسوبة. اذكر box-sizing سبباً مرجّحاً، والمطور هو من يختار الإصلاح. ثم أعد الاختبار عند ⁦480⁩ و⁦481⁩ بكسل، بالإنجليزية والعربية، وفي الصفحات الأخرى التي تستخدم .promo-card.

.promo-card {
  width: 320px;
  padding: 16px;
  border: 2px solid #d0d7de;
}

@media (max-width: 480px) {
  .promo-card { width: 100%; }
}

/* Viewport 360px, box-sizing: content-box (the default):
   360 + 2 × 16 + 2 × 2 = 396px wide, 36px wider than the screen */

جرّبها: مولّد Lorem Ipsum جرّبها: مولّد بيانات اختبار متعددة اللغات

محددات CSS لتحديد العناصر في الاختبارات: لمحة أولى

يجب أن يعثر الاختبار الآلي على العنصر قبل أن ينقره أو يتحقق منه، ومحدِّد CSS إحدى طرق وصفه: فـ By.cssSelector في Selenium وcy.get في Cypress وpage.locator في Playwright تقبله جميعاً. وفي تبويب وحدة التحكم (Console) في أدوات المطوّر يعدّ document.querySelectorAll('[data-testid="pay-now"]').length العناصر المطابقة؛ ويجب أن يطابق محدِّد العنصر (Locator) عنصراً واحداً بالضبط.

ليس كل محدِّد جيد للتنسيق محدِّداً جيداً للاختبار. فأصناف التنسيق تتغير مع إعادة التصميم، والمسارات الطويلة تنكسر عند إضافة عنصر مغلِّف، والأسماء المولَّدة مثل css-1q2w3e تتغير بين عمليات البناء. فضّل المحددات القصيرة المبنية على سمات وُضعت للتعريف: id مستقر، أو name الحقل، أو سمة اختبار مثل data-testid. ويوصي توثيق Playwright بالمحددات التي تعكس ما يراه المستخدم (الدور والتسمية والنص) وبمعرّفات الاختبار، ولا يوصي بمحددات CSS وXPath لأنها تنكسر عندما تتغير بنية الصفحة. أما في Selenium وCypress فيُعثر على معرّف الاختبار نفسه عادةً بمحدِّد سمة من CSS.

  • هشّ: div.col-md-6 > div:nth-child(3) > button.btn-primary.
  • أفضل: [data-testid="pay-now"] أو #email أو input[name="email"].

جرّبها: منسّق HTML

أخطاء شائعة

  • الإبلاغ بأن «التخطيط معطوب» دون ذكر العنصر وعرض منفذ العرض والمتصفح واللغة والوضع الفاتح أو الداكن؛ فكثير من العيوب المرئية لا يظهر إلا في واحد منها.
  • الاختبار على عرض واحد لسطح المكتب وآخر للهاتف، وعدم الاختبار أبداً على جانبي نقطة التوقف.
  • فحص الحالة الافتراضية فقط: لحالات المرور والتركيز والتعطيل والخطأ والتحديد أنماط CSS خاصة بها وعيوب خاصة بها.
  • افتراض أن العنصر غير المرئي غير موجود: opacity: 0 لا يخفي شيئاً عن النقرات أو قارئات الشاشة.
  • لصق المحدِّد الطويل الذي ينتجه خيار «Copy selector» في المتصفح داخل اختبار؛ فهو يرمّز بنية الصفحة وينكسر مع أول تغيير في التخطيط.

من منظور ضمان الجودة

في جلسات التنقيح (Refinement) ومراجعات التصميم، اسأل عما يحدث عند كل نقطة توقف، ومع النصوص الطويلة أو المترجمة، وفي التخطيط من اليمين إلى اليسار، وفي الوضع الداكن، وهل صُمّمت حالات المرور والتركيز والخطأ. وأثناء الاختبار احتفظ بقائمة فحص مرئية قصيرة لكل شاشة، واقرأ القيم المحسوبة في أدوات المطوّر بدلاً من الحكم بالعين؛ وتظهر الألوان هناك بصيغة rgb() مثل rgb(11, 94, 215)، بينما يعطي التصميم عادةً قيماً بصيغة HEX مثل #0b5ed7، وهو اللون الأزرق نفسه، فحوّل إحدى الصيغتين إلى الأخرى قبل المقارنة.

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

تمرين عملي

اقرأ ورقة أنماط كما يقرؤها المختبِر

المطلوب

الأنماط والشيفرة أدناه من صفحة دفع. على الهاتف يبلغ عرض منفذ العرض وعرض main ⁦360⁩ بكسل لكل منهما. أجب عن الخطوات الأربع دون تشغيل الصفحة، واذكر سبب كل إجابة.

المادة
<style>
  .card { width: 100%; padding: 12px; border: 1px solid #d0d7de; }
  .btn { padding: 10px 16px; background-color: #0b5ed7; color: #ffffff; }
  #checkout .btn { background-color: #6c757d; }
  .btn:focus { outline: none; }
  @media (max-width: 480px) {
    .card { padding: 24px; }
  }
</style>
<main id="checkout">
  <div class="card">
    <button class="btn" data-testid="pay-now">Pay now</button>
  </div>
</main>
الخطوات
  1. ما لون خلفية الزر، ولماذا؟
  2. ما عرض صندوق البطاقة على الهاتف، وهل يبقى داخل الشاشة؟
  3. أي تصريح يزيل شيئاً يحتاجه المستخدمون، وأي اختبار يكشفه؟
  4. أي محدِّد CSS تستخدم لتحديد الزر في اختبار آلي؟
إظهار الإجابة النموذجية
الإجابة النموذجية

رمادي، #6c757d: خصوصية #checkout .btn هي 1,1,0، وهي أعلى من خصوصية .btn البالغة 0,1,0، والترتيب لا يحسم إلا بين خصوصيتين متساويتين. وإذا كان التصميم يطلب الأزرق فأبلغ عن ذلك مع لقطة من عرض الأنماط، حيث يظهر التصريح الخاسر مشطوباً.

استعلام الوسائط ينطبق لأن ⁦360⁩ لا يتجاوز ⁦480⁩، فتصبح الحشوة ⁦24⁩ بكسل: ⁦360 + 2 × 24 + 2 × 1 = 410⁩ بكسل، أي أكثر من main بـ ⁦50⁩ بكسل، فتتمرر الصفحة أفقياً. اختبر العرضين ⁦480⁩ و⁦481⁩ بكسل حيث تتغير الحشوة؛ وفي العروض الأكبر تبقى البطاقة أعرض من main بـ ⁦26⁩ بكسل.

.btn:focus { outline: none; }. اضغط Tab حتى يصل التركيز إلى الزر: إذا لم تستطع رؤية موضع التركيز فهذا إخفاق في معيار النجاح 2.4.7 Focus Visible من WCAG 2.2.

[data-testid="pay-now"]: وُضع للاختبارات، ويطابق عنصراً واحداً، ويصمد أمام إعادة التصميم. أما .btn فيطابق كل زر بالتنسيق نفسه، وmain > div > button ينكسر عندما تتغير البنية.

أسئلة شائعة

هل يحتاج المختبِر إلى كتابة CSS؟

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

ما الفرق بين محدِّد CSS وتعبير XPath؟

كلاهما يعثر على العناصر. محددات CSS أقصر للمعرّفات والأصناف والسمات، وهي ما تستخدمه أوراق الأنماط. أما XPath فيستطيع أيضاً المطابقة بالنص والانتقال من الابن إلى الأب؛ ولا تستطيع CSS المطابقة بالنص، ولا يغطي صنفها الزائف :has() إلا بعض حالات الأب. ويقبل Selenium وPlaywright الاثنين، أما cy.get في Cypress فيقبل محددات CSS.

هل العيب المرئي منخفض الخطورة دائماً؟

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

المراجع

  • CSS: Cascading Style Sheets — MDNMDN Web Docs (Mozilla)مرجع MDN وأدلته في CSS: المحدِّدات والتتالي والخصائص وأنظمة التخطيط التي تحدد شكل الصفحة وطريقة تكيّفها.
  • Responsive web design — MDNMDN Web Docs (Mozilla)التصميم المتجاوب عملياً: تخطيطات مرنة باستخدام flexbox وgrid، واستعلامات الوسائط، ووسم viewport، لتعمل الصفحة نفسها على مختلف أحجام الشاشات.
  • Web Content Accessibility Guidelines (WCAG) 2.2W3C · 2024توصية W3C التي تحدد معايير النجاح القابلة للاختبار لإتاحة محتوى الويب، مرتّبةً تحت أربعة مبادئ وثلاثة مستويات مطابقة (A وAA وAAA).
  • Locators — PlaywrightMicrosoft (Playwright)كيف يعثر Playwright على العناصر، ولماذا تُعاد تحديد المحدِّدات وتنتظر تلقائياً، ولماذا يُوصى بالمحدِّدات المبنية على الدور أولاً.

تدرّب بأدوات متقن

تجميل CSS بتصريح واحد في كل سطر، مع خيارات المسافة البادئة وترتيب الناتج.

التنسيق

تحويل الألوان بين HEX وRGB(A) وHSL(A) وHSB/HSV وCMYK وألوان CSS المسمّاة مع معاينة مباشرة.

أدوات مساعدة

تجميل HTML بمسافات بادئة صحيحة للعناصر المتداخلة، مع الحفاظ على كتل pre وscript وstyle.

التنسيق

ولّد نصاً بديلاً (placeholder) على شكل فقرات أو جمل أو كلمات — باللاتينية أو العربية أو الهندية.

أدوات مساعدة

للتعمّق أكثر

تقدّمك في هذا الموضوع

جزء من مسار تعلم ضمان الجودة