أساسيات 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 */نموذج الصندوق
يرسم المتصفح كل عنصر صندوقاً من أربع طبقات، من الداخل إلى الخارج: المحتوى (Content)؛ ثم الحشوة (Padding) التي تُظهر الخلفية وتُحسب من العنصر عند النقر عليها؛ ثم الحدّ (Border)؛ ثم الهامش (Margin)، وهو مسافة شفافة تُبعد العناصر المجاورة. وتُعرف هذه الطبقات معاً بنموذج الصندوق (Box Model).
width: 300px المحتوى وحده، فتجعل حشوةُ 16px وحدٌّ بعرض 2px على كل جانب عرضَ الصندوق 336px.- 1الهامش (Margin)مسافة شفافة تُبعد العناصر المجاورة
لا يدخل في
widthأبداً- 2الحدّ (Border)الخط المرسوم حول الحشوة
يضيف
2 × 2 = 4pxمعcontent-box- 3الحشوة (Padding)تُظهر الخلفية وتُحسب من العنصر عند النقر عليها
تضيف
2 × 16 = 32pxمعcontent-box- 4المحتوى (Content)ما يضبطه
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"].
أخطاء شائعة
- الإبلاغ بأن «التخطيط معطوب» دون ذكر العنصر وعرض منفذ العرض والمتصفح واللغة والوضع الفاتح أو الداكن؛ فكثير من العيوب المرئية لا يظهر إلا في واحد منها.
- الاختبار على عرض واحد لسطح المكتب وآخر للهاتف، وعدم الاختبار أبداً على جانبي نقطة التوقف.
- فحص الحالة الافتراضية فقط: لحالات المرور والتركيز والتعطيل والخطأ والتحديد أنماط 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>- ما لون خلفية الزر، ولماذا؟
- ما عرض صندوق البطاقة على الهاتف، وهل يبقى داخل الشاشة؟
- أي تصريح يزيل شيئاً يحتاجه المستخدمون، وأي اختبار يكشفه؟
- أي محدِّد 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 — MDNمرجع MDN وأدلته في CSS: المحدِّدات والتتالي والخصائص وأنظمة التخطيط التي تحدد شكل الصفحة وطريقة تكيّفها.
- Responsive web design — MDNالتصميم المتجاوب عملياً: تخطيطات مرنة باستخدام flexbox وgrid، واستعلامات الوسائط، ووسم viewport، لتعمل الصفحة نفسها على مختلف أحجام الشاشات.
- Web Content Accessibility Guidelines (WCAG) 2.2توصية W3C التي تحدد معايير النجاح القابلة للاختبار لإتاحة محتوى الويب، مرتّبةً تحت أربعة مبادئ وثلاثة مستويات مطابقة (A وAA وAAA).
- Locators — Playwrightكيف يعثر Playwright على العناصر، ولماذا تُعاد تحديد المحدِّدات وتنتظر تلقائياً، ولماذا يُوصى بالمحدِّدات المبنية على الدور أولاً.
تدرّب بأدوات متقن
تجميل CSS بتصريح واحد في كل سطر، مع خيارات المسافة البادئة وترتيب الناتج.
تحويل الألوان بين HEX وRGB(A) وHSL(A) وHSB/HSV وCMYK وألوان CSS المسمّاة مع معاينة مباشرة.
تجميل HTML بمسافات بادئة صحيحة للعناصر المتداخلة، مع الحفاظ على كتل pre وscript وstyle.
ولّد نصاً بديلاً (placeholder) على شكل فقرات أو جمل أو كلمات — باللاتينية أو العربية أو الهندية.
ولّد السجلات نفسها بلغات متعددة (الإنجليزية والعربية والهندية وغيرها) لاختبار التدويل (i18n) واختلاط RTL/LTR.
للتعمّق أكثر
تقدّمك في هذا الموضوع
سجّل الدخول لتتابع تقدّمك
علّم الموضوعات مكتملة، وتابع من حيث توقفت، وافتح امتحانات التخصص.