{"id":"l-css-1-2","courseId":"css-mastery","lang":"ar","kind":"lesson","summary":"احسب الـ specificity لأيّ selector، واستخدم :is() لتجميع الـ selectors و:where() لكتابة أنماط أساسية تستطيع الـ components تجاوزها بلا عراك.","html":"<p>بدأت صفحة جدول Waypoint حياتها نموذجًا أوليًا سريعًا، وملف أنماطها يشهد على ذلك. في مكان ما قرب أعلاه تقبع القاعدة <code dir=\"ltr\">#schedule article a { color: #1d4ed8; }</code>، وفي كل مرة يضيف فريق التصميم رابطًا على هيئة زر داخل بطاقة جلسة، يتحوّل نص الزر إلى الأزرق. «أصلحه» أحدهم الشهر الماضي بـ <code dir=\"ltr\">!important</code>، والآن لا أحد يستطيع تغيير ثيم الزر.</p>\n<p>هذه مشكلة specificity، وحلّها ليس مطرقة أكبر، بل أن تختار الوزن الذي يجب أن يحمله كل selector.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">الـ specificity ثلاثة أعداد لا عدد واحد</h2>\n<p>يعطي المتصفّح كل selector درجة على شكل ثلاثية، تُكتب غالبًا (A, B, C):</p>\n<div class=\"table-wrap\" role=\"region\" aria-label=\"جدول قابل للتمرير\" tabindex=\"0\"><table><thead>\n<tr>\n<th>العمود</th>\n<th>ما يُحسب فيه</th>\n<th>أمثلة</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>A</td>\n<td>selectors الـ ID</td>\n<td><code dir=\"ltr\">#schedule</code></td>\n</tr>\n<tr>\n<td>B</td>\n<td>الـ classes والسمات (attributes) والـ pseudo-classes</td>\n<td><code dir=\"ltr\">.session</code>، <code dir=\"ltr\">[type=&quot;checkbox&quot;]</code>، <code dir=\"ltr\">:hover</code></td>\n</tr>\n<tr>\n<td>C</td>\n<td>selectors الأنواع والـ pseudo-elements</td>\n<td><code dir=\"ltr\">article</code>، <code dir=\"ltr\">a</code>، <code dir=\"ltr\">::before</code></td>\n</tr>\n</tbody>\n</table></div><p>الـ selector الشامل <code dir=\"ltr\">*</code> والروابط بين الـ selectors (combinators: المسافة و<code dir=\"ltr\">&gt;</code> و<code dir=\"ltr\">+</code> و<code dir=\"ltr\">~</code>) لا تضيف شيئًا. لتقارن selectorين، قارن العمود A؛ فإن تعادلا فقارن B؛ فإن تعادلا فقارن C. لا يوجد «حَمْل» من عمود إلى آخر: أحد عشر class <code dir=\"ltr\">(0,11,0)</code> تخسر رغم ذلك أمام ID واحد <code dir=\"ltr\">(1,0,0)</code>. النصيحة القديمة «اجمع النقاط» (100 لكل ID و10 لكل class) تنهار هنا تحديدًا، فانسَها.</p>\n<p>احسب درجات تعارض Waypoint:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#schedule</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> article</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#1d4ed8</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* (1, 0, 2) */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.btn</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#fff</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }                     </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* (0, 1, 0) */</span></span></code></pre></div>\n<p>الـ ID في الـ selector الأول يفوز في العمود A، فيصبح نص الزر أزرق. ونقل <code dir=\"ltr\">.btn</code> إلى أسفل الملف لا يغيّر شيئًا.</p>\n<aside class=\"callout callout-why\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><circle cx=\"12\" cy=\"12\" r=\"6\"/><circle cx=\"12\" cy=\"12\" r=\"2\"/></svg><span><span class=\"callout-kind\">لماذا يهمّ هذا</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>لماذا تؤذي الـ IDs ملفات الأنماط</span></p>\n<p>selector الـ ID يتفوّق على كل selector مبني على الـ classes ستكتبه يومًا. ID واحد في قاعدة أساسية يجبر كل component يلمس الخاصية نفسها على أن يتضمّن ID هو الآخر، أو أن يلجأ إلى <code dir=\"ltr\">!important</code>. احتفظ بالـ IDs للروابط الداخلية (anchors) ولنقاط ربط JavaScript، ونسّق بالـ classes.</p>\n</aside>\n<h2 id=\"sec-2\" tabindex=\"-1\"><code dir=\"ltr\">:is()</code>: تجميع مع شرط خفيّ</h2>\n<p>تأخذ <code dir=\"ltr\">:is()</code> قائمة selectors وتطابق إن طابق أيٌّ منها، فتوفّر عليك تكرار الـ selectors الطويلة:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* Before */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> h2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> h3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> h4</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">text-wrap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">balance</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* After */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> :is</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#116329;--shiki-dark:#7EE787\">h2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#116329;--shiki-dark:#7EE787\">h3</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#116329;--shiki-dark:#7EE787\">h4</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">text-wrap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">balance</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n<p>الشرط الخفيّ هو قاعدة الـ specificity: تأخذ <code dir=\"ltr\">:is()</code> الـ specificity الخاصة بـ <strong>أدقّ وسيط فيها</strong>، أيًّا كان الوسيط الذي طابق فعلًا. فالقاعدة <code dir=\"ltr\">:is(#featured, .session) h2</code> درجتها (1,0,1) على كل <code dir=\"ltr\">.session h2</code>، حتى تلك التي لا يوجد قربها أيّ ID. و<code dir=\"ltr\">:not()</code> و<code dir=\"ltr\">:has()</code> تتبعان القاعدة نفسها.</p>\n<p>وتستخدم <code dir=\"ltr\">:is()</code> أيضًا <strong>قائمة selectors متسامحة</strong>. في القائمة العادية مثل <code dir=\"ltr\">.a, .b:unknown</code>، يكفي selector واحد غير معروف لإبطال القاعدة كلها. أما داخل <code dir=\"ltr\">:is()</code> فيُسقط المتصفّح الوسيط السيئ وحده ويحتفظ بالباقي.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\"><code dir=\"ltr\">:where()</code>: الغلاف عديم الوزن</h2>\n<p>تطابق <code dir=\"ltr\">:where()</code> تمامًا كما تطابق <code dir=\"ltr\">:is()</code>، مع فرق واحد: الـ specificity فيها <strong>صفر</strong> دائمًا، أيًّا كان ما بداخلها. وهذا يجعلها الأداة المناسبة لأيّ نمط يُقصد به أن يكون افتراضيًا:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">base.css</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* Base link style: (0,0,1) because only the trailing `a` counts */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">:where</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#schedule</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> article</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#116329;--shiki-dark:#7EE787\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#1d4ed8</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  text-decoration</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">underline</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* Component: (0,1,0) beats (0,0,1) */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.btn</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#fff</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  background</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#6d28d9</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  text-decoration</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">none</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>ما زالت القاعدة الأساسية تنطبق فقط داخل مقالات <code dir=\"ltr\">#schedule</code>، أي أن <em>نطاقها</em> لم يتغيّر. الذي انخفض هو <em>وزنها</em> فقط. والآن يفوز أيّ component مبني على class بلا حيل.</p>\n<p>وهذا افتراض مفيد لقاعدة كود كاملة: غلّف أنماط إعادة الضبط وافتراضيات العناصر بـ <code dir=\"ltr\">:where()</code>، واكتب الـ components بـ class واحد، واجعل selectors الحالات (<code dir=\"ltr\">.btn:hover</code> و<code dir=\"ltr\">.btn[aria-pressed=&quot;true&quot;]</code>) أثقل من الـ component بدرجة واحدة.</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>تغليف الـ selector كله بينما المطلوب تخفيف جزء منه</span></p>\n<p>درجة <code dir=\"ltr\">:where(.session .title)</code> صفر، لذا حتى قاعدة شاردة مثل <code dir=\"ltr\">h2 { color: … }</code> في ملف آخر تتغلّب عليها. غلّف فقط السياق الذي تريده بلا وزن، واترك الجزء الذي يحدّد العنصر خارجه: <code dir=\"ltr\">:where(.session) .title</code> يحتفظ بـ (0,1,0).</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">أربع طرق لكسب معركة specificity</h2>\n<p>حين تخسر قاعدة ما، أمامك أربعة خيارات. هذه هي بالترتيب الذي ألجأ إليه:</p>\n<ol>\n<li><strong>خفّف الطرف الخاسر.</strong> إن كانت القاعدة الفائزة نمطًا أساسيًا لا ينبغي أن يكون ثقيلًا، فغلّف سياقها بـ <code dir=\"ltr\">:where()</code>. هذا يعالج السبب، ويستفيد منه كل component في المستقبل.</li>\n<li><strong>افصل المجموعات كاملة بالـ layers.</strong> حين يكون التعارض بين أنواع من CSS (إعادة الضبط مقابل الـ components مقابل أدوات الـ utilities)، تحسمه طبقات الـ cascade نهائيًا. وهذا موضوع الدرس التالي.</li>\n<li><strong>ارفع الطرف الفائز.</strong> تكرار الـ class كما في <code dir=\"ltr\">.btn.btn</code> يضيف (0,1,0) دون أن يغيّر ما يطابقه. إنها حيلة مشروعة ومحلية، لكن كل تكرار دَين سيدفعه التجاوز التالي.</li>\n<li><strong><code dir=\"ltr\">!important</code>.</strong> احتفظ بها للـ utilities التي يجب أن تفوز دائمًا ولتجاوزات إمكانية الوصول. أما استخدامها لترقيع تعارض واحد فيبدأ سباق تسلّح، لأن الطريقة الوحيدة لهزيمتها هي <code dir=\"ltr\">!important</code> أخرى.</li>\n</ol>\n<h2 id=\"sec-5\" tabindex=\"-1\">قراءة الـ specificity في DevTools</h2>\n<p>لن تضطر إلى العدّ يدويًا إلى الأبد. مرّر المؤشّر فوق أيّ selector في لوحة Styles في Chrome أو Firefox، وسيُظهر لك التلميح ثلاثية الـ specificity الخاصة به. استخدمه أسبوعًا لتتحقّق من حساباتك الذهنية، وبعدها نادرًا ما ستحتاج إليه.</p>\n<h2 id=\"sec-6\" tabindex=\"-1\">دورك الآن</h2>\n<p>يعطيك التمرين بطاقة جلسة Waypoint مع قاعدة الروابط من النموذج الأولي. خفّف وزن القاعدة الأساسية ليعود الزر زرًّا، بينما تحتفظ الروابط العادية بلونها الأزرق وخطّها السفلي. وستعالج هذا على نطاق أوسع في الدرس التالي، حيث تتيح لك طبقات الـ cascade أن تقرّر أيّ <em>مجموعات</em> الأنماط تفوز، قبل أن تُستشار الـ specificity أصلًا.</p>\n","toc":[{"id":"sec-1","text":"الـ specificity ثلاثة أعداد لا عدد واحد","level":2},{"id":"sec-2","text":":is(): تجميع مع شرط خفيّ","level":2},{"id":"sec-3","text":":where(): الغلاف عديم الوزن","level":2},{"id":"sec-4","text":"أربع طرق لكسب معركة specificity","level":2},{"id":"sec-5","text":"قراءة الـ specificity في DevTools","level":2},{"id":"sec-6","text":"دورك الآن","level":2}],"takeaways":["الـ specificity ثلاثة أعداد منفصلة (الـ IDs، ثم الـ classes والسمات والـ pseudo-classes، ثم الأنواع والـ pseudo-elements) تُقارَن عمودًا بعمود، ولا تُجمع أبدًا في رقم واحد.","<code dir=\"ltr\">:is()</code> و<code dir=\"ltr\">:not()</code> و<code dir=\"ltr\">:has()</code> تأخذ specificity أدقّ وسيط فيها، حتى لو كان الوسيط الأقل دقّة هو الذي طابق العنصر.","الـ specificity في <code dir=\"ltr\">:where()</code> صفر دائمًا، ما يجعلها الغلاف المناسب لأنماط إعادة الضبط (resets) والأنماط الأساسية التي يجب أن تخسر أمام أيّ component.","<code dir=\"ltr\">:is()</code> و<code dir=\"ltr\">:where()</code> تستخدمان قوائم selectors متسامحة: selector واحد غير صالح بداخلهما لا يُسقط القاعدة كلها."],"further":[{"title":"Specificity (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Cascade/Specificity"},{"title":":where() (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:where"},{"title":":is() (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:is"}],"quiz":[{"q":"<p>ما الـ specificity الخاصة بـ <code dir=\"ltr\">nav#main a.active:hover</code>؟</p>","options":[{"text":"(1, 2, 2)","why":"صحيح. ID واحد (<code dir=\"ltr\">#main</code>)؛ وclass واحد مع pseudo-class واحد (<code dir=\"ltr\">.active</code> و<code dir=\"ltr\">:hover</code>)؛ ونوعان (<code dir=\"ltr\">nav</code> و<code dir=\"ltr\">a</code>)."},{"text":"(1, 1, 2)","why":"الـ pseudo-classes مثل <code dir=\"ltr\">:hover</code> تُحسب في العمود الأوسط مع الـ classes، فيكون فيه اثنان لا واحد."},{"text":"(1, 2, 1)","why":"كلٌّ من <code dir=\"ltr\">nav</code> و<code dir=\"ltr\">a</code> selector نوع، لذا فالعمود الأخير قيمته 2."},{"text":"(0, 3, 2)","why":"<code dir=\"ltr\">#main</code> selector من نوع ID، ومكانه العمود الأول لا مع الـ classes."}],"answer":0},{"q":"<p>ما اللون الذي يأخذه الرابط؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">:is</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#sidebar</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#116329;--shiki-dark:#7EE787\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">red</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.card</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .card-link</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">blue</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"html\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">HTML</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">div</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> class</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"card\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">a</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> class</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"card-link\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> href</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"#\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Read&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">div</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n","options":[{"text":"blue، لأن العنصر طابق عبر <code dir=\"ltr\">.card</code> لا عبر <code dir=\"ltr\">#sidebar</code>.","why":"<code dir=\"ltr\">:is()</code> لا تهتم بالوسيط الذي طابق. إنها تأخذ دائمًا specificity أدقّ وسيط فيها، وهو هنا ID."},{"text":"red، لأن <code dir=\"ltr\">:is()</code> تأخذ specificity الـ <code dir=\"ltr\">#sidebar</code>.","why":"صحيح. القاعدة الأولى درجتها (1,0,1) فتتغلّب على (0,2,0)، مع أن العنصر لا يحمل أيّ ID أصلًا."},{"text":"blue، لأنها تأتي لاحقًا في ملف الأنماط.","why":"الترتيب لا يهم إلا عند تعادل الـ specificity، و(1,0,1) تتغلّب على (0,2,0) مباشرةً."}],"answer":1},{"q":"<p>في ملف إعادة الضبط لديك <code dir=\"ltr\">ul[class] { list-style: none; margin: 0; }</code>، والقاعدة <code dir=\"ltr\">.tags { margin-block: 1rem; }</code> في أحد الـ components تخسر أمامها. ما أنظف إصلاح؟</p>","options":[{"text":"أضف <code dir=\"ltr\">!important</code> إلى margin الـ component.","why":"هذا يكسب هذه المعركة لكنه يبدأ تصعيدًا؛ فالتجاوز التالي سيحتاج إلى <code dir=\"ltr\">!important</code> أيضًا، وتفقد القدرة على بناء الثيمات."},{"text":"ارفع selector الـ component إلى <code dir=\"ltr\">ul.tags.tags</code>.","why":"ينجح، لكن كل component سيضطر الآن إلى التفوّق على ملف إعادة الضبط، وهذا هو سباق التسلّح الذي تريد إنهاءه."},{"text":"أعد كتابة إعادة الضبط على شكل <code dir=\"ltr\">:where(ul[class]) { … }</code>.","why":"صحيح. تنخفض specificity إعادة الضبط إلى صفر، فيتجاوزها أيّ selector بـ class في أيّ component."}],"answer":2},{"q":"<p>كُتبت قاعدة بالشكل <code dir=\"ltr\">:is(.card, :future-state) h3 { … }</code> والمتصفّح لا يتعرّف على <code dir=\"ltr\">:future-state</code>. ماذا يحدث؟</p>","options":[{"text":"تُسقَط القاعدة كلها، كما يحدث مع أيّ قائمة selectors غير صالحة.","why":"هذا سلوك القائمة العادية المفصولة بفواصل، لكن <code dir=\"ltr\">:is()</code> و<code dir=\"ltr\">:where()</code> تستخدمان قوائم selectors متسامحة."},{"text":"تظل القاعدة تنطبق على <code dir=\"ltr\">.card h3</code>؛ ويُتجاهل الـ selector المجهول وحده.","why":"صحيح. التحليل المتسامح يتخلّص من الوسيط غير الصالح ويحتفظ بالباقي."},{"text":"يُظهر Chrome خطأً في الـ console ويتوقّف عن تحليل ملف الأنماط.","why":"لا تتوقّف CSS أبدًا عن التحليل بسبب الأخطاء؛ إنها تتجاهل ما لا تفهمه وتكمل."}],"answer":1}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<main id=\"schedule\">\n  <article class=\"session\">\n    <h2>Keynote: The Platform Is the Framework</h2>\n    <p>Read the <a class=\"abstract-link\" href=\"#abstract\">full abstract</a>.</p>\n    <a class=\"btn\" href=\"#save\">Save to my schedule</a>\n  </article>\n</main>","css":"/* Base link style from the prototype */\n#schedule article a {\n  color: #1d4ed8;\n  text-decoration: underline;\n}\n\n/* Button component: leave this rule as it is */\n.btn {\n  display: inline-block;\n  padding: 0.4em 0.9em;\n  border-radius: 999px;\n  color: #ffffff;\n  background: #6d28d9;\n  text-decoration: none;\n}\n"},"solution":{"html":"<main id=\"schedule\">\n  <article class=\"session\">\n    <h2>Keynote: The Platform Is the Framework</h2>\n    <p>Read the <a class=\"abstract-link\" href=\"#abstract\">full abstract</a>.</p>\n    <a class=\"btn\" href=\"#save\">Save to my schedule</a>\n  </article>\n</main>","css":"/* Base link style: same reach, zero-weight context */\n:where(#schedule article) a {\n  color: #1d4ed8;\n  text-decoration: underline;\n}\n\n/* Button component: leave this rule as it is */\n.btn {\n  display: inline-block;\n  padding: 0.4em 0.9em;\n  border-radius: 999px;\n  color: #ffffff;\n  background: #6d28d9;\n  text-decoration: none;\n}\n"},"checks":[{"id":"btn-white","test":"return style('.btn', 'color') === 'rgb(255, 255, 255)';"},{"id":"btn-no-underline","test":"return style('.btn', 'text-decoration-line') === 'none';"},{"id":"link-still-blue","test":"return style('.abstract-link', 'color') === 'rgb(29, 78, 216)' && style('.abstract-link', 'text-decoration-line') === 'underline';"},{"id":"no-important","test":"return ![...document.querySelectorAll('style')].some((s) => s.textContent.includes('!important'));"},{"id":"markup-intact","test":"return exists('#schedule article .btn') && exists('#schedule article .abstract-link');"}],"title":"أنقذ الزر من selector الـ ID","prompt":"<p>قاعدة النموذج الأولي <code dir=\"ltr\">#schedule article a</code> تجعل زر <strong>Save to my schedule</strong> أزرق وتحته خط. عدّل <strong>قاعدة الروابط الأساسية وحدها</strong> بحيث يستعيد <code dir=\"ltr\">.btn</code> نمطه الأبيض بلا خط سفلي، بينما يبقى الرابط العادي <code dir=\"ltr\">.abstract-link</code> أزرق (<code dir=\"ltr\">#1d4ed8</code>) وتحته خط. لا تعدّل قاعدة <code dir=\"ltr\">.btn</code>، ولا تلمس الـ HTML، ولا تستخدم <code dir=\"ltr\">!important</code>.</p>\n","hints":["احسب درجة الـ selectorين: <code dir=\"ltr\">#schedule article a</code> درجته (1,0,2) و<code dir=\"ltr\">.btn</code> درجته (0,1,0). أيّ عمود يحسم المقارنة؟","تريد أن تبقى القاعدة الأساسية منطبقة داخل مقالات <code dir=\"ltr\">#schedule</code> فقط، لكن بوزن أقل.","غلّف السياق بـ <code dir=\"ltr\">:where()</code>: درجة <code dir=\"ltr\">:where(#schedule article) a { … }</code> هي (0,0,1)."],"explanation":"<p>تحتفظ <code dir=\"ltr\">:where()</code> بنطاق الـ selector لكنها لا تضيف أيّ specificity، لذا تصبح درجة <code dir=\"ltr\">:where(#schedule article) a</code> هي (0,0,1). درجة قاعدة <code dir=\"ltr\">.btn</code> هي (0,1,0)، فتفوز الآن في اللون وزخرفة النص، بينما تظل الروابط العادية داخل المقال مطابقة للقاعدة الأساسية. إزالة الـ ID كليًا (مثل <code dir=\"ltr\">article a</code>) ستنجح أيضًا، لكن <code dir=\"ltr\">:where()</code> تتيح لك الإبقاء على النطاق الذي قصده النموذج الأولي.</p>\n","checkLabels":{"btn-white":"نص الزر أبيض","btn-no-underline":"الزر بلا خط سفلي","link-still-blue":"رابط الملخّص ما زال أزرق وتحته خط","no-important":"لا توجد !important في أيّ مكان من الـ CSS","markup-intact":"الـ HTML لم يتغيّر"}},"words":732,"readMinutes":4}