{"id":"l-css-3-4","courseId":"css-mastery","lang":"ar","kind":"lesson","summary":"أطلق ثيمًا فاتحًا وداكنًا باستخدام color-scheme وlight-dark()، وأضف تجاوزًا من المستخدم يتغلّب على إعداد النظام، واجعل قسمًا ما داكنًا دائمًا دون تكرار الـ tokens.","html":"<p>بُني الوضع الداكن في Waypoint بالطريقة الكلاسيكية: مجموعة كاملة من tokens الألوان في <code dir=\"ltr\">:root</code>، ومجموعة كاملة ثانية داخل <code dir=\"ltr\">@media (prefers-color-scheme: dark)</code>. ونجح ذلك إلى أن حدثت ثلاثة أشياء. أضاف أحدهم token إلى المجموعة الفاتحة ونسي الداكنة. وطلب المستخدمون مفتاح تبديل، لأن نظام التشغيل لديهم داكن لكنهم يريدون الجدول فاتحًا على جهاز العرض. وأراد فريق التصميم أن يكون الـ hero داكنًا في <em>كلا</em> الوضعين.</p>\n<p>كلٌّ من هذه سطر واحد مع <code dir=\"ltr\">color-scheme</code> و<code dir=\"ltr\">light-dark()</code>.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">color-scheme: أخبر المتصفّح بما تدعمه</h2>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">theme.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\">:root</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  color-scheme</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">light</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> dark</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\">&lt;select&gt;</code> وأشرطة تمرير بيضاء ساطعة، وهذه أشهر علامة تفضح وضعًا داكنًا مصنوعًا يدويًا.</p>\n<p>أضف وسم الـ meta المقابل ليعرف المتصفّح قبل أن تصل الـ CSS، فلا تومض الصفحة بالأبيض عند التحميل:</p>\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\">meta</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> name</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"color-scheme\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> content</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"light dark\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n<h2 id=\"sec-2\" tabindex=\"-1\">light-dark(): token واحد بقيمتين</h2>\n<p>تأخذ <code dir=\"ltr\">light-dark()</code> لونين وتُرجع الأول حين يكون النظام اللوني المستخدم في العنصر فاتحًا، والثاني حين يكون داكنًا:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"2\"><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\">:root</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  color-scheme</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">light</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> dark</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">  --surface</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: light-dark(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#ffffff</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#0f172a</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">  --text</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">:    light-dark(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#1f2937</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#e5e7eb</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">  --card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">:    light-dark(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#f8fafc</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#1e293b</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">  --border</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">:  light-dark(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">oklch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">90</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.01</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 280</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">), </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">oklch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">35</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.02</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 280</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:#116329;--shiki-dark:#7EE787\">body</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\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">--surface</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\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">--text</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 style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</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\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">--card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  border</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> solid</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">--border</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>كل token يُعرَّف الآن مرة واحدة، والقيمتان جنبًا إلى جنب. وإضافة token دون قيمته الداكنة تصبح ناقصة بشكل واضح عند المراجعة. <code dir=\"ltr\">light-dark()</code> للألوان ضمن Baseline 2024 وتعمل في كل المتصفّحات الحالية. أما تمرير صورتين إليها (مثل التدرّجات أو <code dir=\"ltr\">url()</code>) فلم يدخل Baseline إلا في سبتمبر 2026، وهي لا تقبل الأطوال ولا غيرها من القيم أبدًا، لذا أبقِ لهذه الحالات media query <code dir=\"ltr\">prefers-color-scheme</code> في الوقت الحالي.</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>نسيان color-scheme</span></p>\n<p><code dir=\"ltr\">light-dark()</code> لا تقرأ نظام التشغيل مباشرةً. إنها تقرأ <em>النظام اللوني المستخدم</em> في العنصر، الذي يأتي من خاصية <code dir=\"ltr\">color-scheme</code>. وإن لم يضبط شيءٌ <code dir=\"ltr\">color-scheme: light dark</code> (أو <code dir=\"ltr\">dark</code>)، يكون النظام فاتحًا، وتُرجع كل <code dir=\"ltr\">light-dark()</code> وسيطها الأول، حتى على نظام تشغيل داكن.</p>\n</aside>\n<h2 id=\"sec-3\" tabindex=\"-1\">مفتاح تبديل يتغلّب على إعداد النظام</h2>\n<p>لأن كل شيء يقرأ النظام اللوني، لا يحتاج مفتاح التبديل إلا إلى تغيير خاصية واحدة على الجذر:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"3\"><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\">:root</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">[</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">data-theme</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"light\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">] { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color-scheme</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">light</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">:root</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">[</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">data-theme</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"dark\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">]  { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">color-scheme</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">dark</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n<p>دون <code dir=\"ltr\">data-theme</code> يحتفظ الجذر بـ <code dir=\"ltr\">light dark</code> ويتبع نظام التشغيل. ومع <code dir=\"ltr\">data-theme=&quot;dark&quot;</code> يُفرض الداكن، ويتبعه كل token. وكود JavaScript لعنصر تحكّم ثلاثي صغير جدًا:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"js\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">theme-toggle.js</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:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> select</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> document.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">querySelector</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'#theme'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> saved</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> localStorage.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">getItem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'theme'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">if</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (saved) document.documentElement.dataset.theme </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> saved;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">select.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">addEventListener</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'change'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, () </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=></span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  const</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> value</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> =</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> select.value; </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">// 'system' | 'light' | 'dark'</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  if</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (value </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">===</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\"> 'system'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">    delete</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> document.documentElement.dataset.theme;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    localStorage.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">removeItem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'theme'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  } </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">else</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    document.documentElement.dataset.theme </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">=</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> value;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    localStorage.</span><span style=\"color:#8250DF;--shiki-dark:#D2A8FF\">setItem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">'theme'</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, value);</span></span>\n<span class=\"line\"><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>شغّل جزء الاستعادة في script صغير مضمّن داخل <code dir=\"ltr\">&lt;head&gt;</code> ليُطبَّق الثيم المحفوظ قبل الرسم الأول.</p>\n<figure class=\"diagram\"><svg class=\"diagram-svg\" focusable=\"false\" viewBox=\"0 0 680 250\" role=\"img\" aria-labelledby=\"l-css-3-4-t1\"><defs><marker id=\"arrow-l-css-3-4-1\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\" markerWidth=\"7\" markerHeight=\"7\" orient=\"auto-start-reverse\"><path d=\"M0 0 L10 5 L0 10 z\" class=\"d-arrowhead\"/></marker></defs>\n  <title id=\"l-css-3-4-t1\">لعنصر الجذر color-scheme فاتح أو داكن أو الاثنان معًا تبعًا لنظام التشغيل. معظم العناصر ترثه. والـ hero يضبط color-scheme على dark، فيُرجع كل token من نوع light-dark داخله قيمته الداكنة، بينما تُرجع بقية الصفحة القيم الفاتحة.</title>\n  <rect class=\"d-box-primary\" x=\"20\" y=\"20\" width=\"260\" height=\"60\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"36\" y=\"46\">:root color-scheme</text>\n  <text class=\"d-label-muted\" x=\"36\" y=\"68\">النظام / فاتح / داكن</text>\n  <path class=\"d-arrow\" d=\"M150 80 L150 120\" marker-end=\"url(#arrow-l-css-3-4-1)\"/>\n  <rect class=\"d-box\" x=\"20\" y=\"124\" width=\"260\" height=\"56\" rx=\"10\"/>\n  <text class=\"d-label\" x=\"36\" y=\"148\">.schedule ترث</text>\n  <text class=\"d-code\" x=\"36\" y=\"170\">light-dark(A, B) → A</text>\n  <rect class=\"d-box-accent\" x=\"360\" y=\"20\" width=\"300\" height=\"60\" rx=\"10\"/>\n  <text class=\"d-code\" x=\"376\" y=\"46\">.hero</text>\n  <text class=\"d-code\" x=\"376\" y=\"68\">color-scheme: dark</text>\n  <path class=\"d-arrow\" d=\"M510 80 L510 120\" marker-end=\"url(#arrow-l-css-3-4-1)\"/>\n  <rect class=\"d-box\" x=\"360\" y=\"124\" width=\"300\" height=\"56\" rx=\"10\"/>\n  <text class=\"d-label\" x=\"376\" y=\"148\">بطاقة الـ hero ترث الداكن</text>\n  <text class=\"d-code\" x=\"376\" y=\"170\">light-dark(A, B) → B</text>\n  <path class=\"d-line d-dashed\" d=\"M280 50 L360 50\"/>\n  <text class=\"d-label-muted\" x=\"20\" y=\"222\">الـ tokens نفسها في كل مكان؛ وكل عنصر يحسمها بنظامه اللوني.</text>\n</svg><figcaption>يُحسم النظام اللوني لكل عنصر، ثم تختار light-dark() قيمة</figcaption></figure>\n<h2 id=\"sec-4\" tabindex=\"-1\">فرض الداكن على قسم واحد</h2>\n<p><code dir=\"ltr\">color-scheme</code> موروثة، و<code dir=\"ltr\">light-dark()</code> تُحسم بحسب قيمة كل عنصر. لذا لا يحتاج الـ hero الداكن دائمًا إلا إلى تصريح واحد:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"5\"><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\">.hero</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  color-scheme</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">dark</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\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">--surface</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\">var</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">--text</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>داخل الـ hero تُحسم <code dir=\"ltr\">--surface</code> و<code dir=\"ltr\">--text</code> و<code dir=\"ltr\">--card</code> كلها إلى قيمها الداكنة، بما في ذلك بطاقة جلسة الـ keynote المتداخلة فيه، بينما تبقى بقية الصفحة فاتحة. والحيلة نفسها تعمل في الاتجاه المعاكس للوحة «معاينة طباعة» فاتحة داخل تطبيق داكن.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">تصميم لوحة الألوان الداكنة</h2>\n<p>الوضع الداكن ليس الوضع الفاتح مقلوبًا. هذه بضع قواعد تصمد في المشاريع الحقيقية:</p>\n<ul>\n<li><strong>تجنّب الأسود الصافي.</strong> رمادي مزرقّ داكن جدًا مثل <code dir=\"ltr\">#0f172a</code> أريح للعين ويترك مجالًا للارتفاع البصري (elevation).</li>\n<li><strong>أظهر الارتفاع بأسطح أفتح</strong> لا بالظلال: تجلس البطاقة على <code dir=\"ltr\">#1e293b</code>، والنافذة المنبثقة (popover) على درجة أفتح منها. الظلال بالكاد تظهر على الخلفيات الداكنة.</li>\n<li><strong>خفّض تشبّع ألوان التمييز.</strong> ألوان المسارات الحيوية من الدرس السابق تهتزّ على الخلفية الداكنة. و<code dir=\"ltr\">oklch(from var(--track) 72% calc(c * 0.8) h)</code> ترفع الإضاءة وتخفّف التشبّع للأسطح الداكنة.</li>\n<li><strong>أعد فحص التباين في النظامين.</strong> الزوج الذي ينجح في الوضع الفاتح لا يضمن شيئًا في الداكن.</li>\n</ul>\n<p>لا تحتاج إلى تغيير نظام التشغيل لاختبار أيٍّ من هذا. تستطيع DevTools في Chrome محاكاة <code dir=\"ltr\">prefers-color-scheme: dark</code> من لوحة Rendering، ولدى Firefox مفتاح في الـ Inspector. اختبر حالات المفتاح الثلاث والـ hero في كلٍّ منها، وافحص عناصر النماذج: فهي أول مكان يظهر فيه غياب <code dir=\"ltr\">color-scheme</code>.</p>\n<h2 id=\"sec-6\" tabindex=\"-1\">دورك الآن</h2>\n<p>يستخدم التمرين النمط القديم: tokens مع تجاوز بـ <code dir=\"ltr\">prefers-color-scheme</code>، ولا مفتاح تبديل. أعد كتابة الـ tokens بـ <code dir=\"ltr\">light-dark()</code>، واربط <code dir=\"ltr\">data-theme</code> على الجذر، واجعل الـ hero داكنًا في الوضعين. تضبط الفحوصات <code dir=\"ltr\">data-theme</code> وتقرأ الألوان المحسوبة. وبعدها ستتأكّد من أن من يتنقّلون بلوحة المفاتيح يرون أين هم، في الثيمين كليهما.</p>\n","toc":[{"id":"sec-1","text":"color-scheme: أخبر المتصفّح بما تدعمه","level":2},{"id":"sec-2","text":"light-dark(): token واحد بقيمتين","level":2},{"id":"sec-3","text":"مفتاح تبديل يتغلّب على إعداد النظام","level":2},{"id":"sec-4","text":"فرض الداكن على قسم واحد","level":2},{"id":"sec-5","text":"تصميم لوحة الألوان الداكنة","level":2},{"id":"sec-6","text":"دورك الآن","level":2}],"takeaways":["<code dir=\"ltr\">color-scheme: light dark</code> تخبر المتصفّح بأن الصفحة تدعم النظامين اللونيين، فتتبع عناصر النماذج وأشرطة التمرير والألوان الافتراضية إعداد المستخدم.","<code dir=\"ltr\">light-dark(A, B)</code> تُرجع A أو B بحسب النظام اللوني المستخدم في العنصر، فيُعرَّف كل token مرة واحدة بدل مكانين.","مفتاح التبديل الثلاثي (النظام، فاتح، داكن) لا يحتاج إلا إلى ضبط <code dir=\"ltr\">color-scheme</code> على الجذر؛ وكل قيمة <code dir=\"ltr\">light-dark()</code> تتبعه.","لأن <code dir=\"ltr\">light-dark()</code> تُحسم لكل عنصر على حدة، فإن <code dir=\"ltr\">color-scheme: dark</code> على قسم واحد تجعل ذلك القسم داكنًا بينما تبقى بقية الصفحة فاتحة."],"further":[{"title":"light-dark() (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/light-dark"},{"title":"color-scheme (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/color-scheme"},{"title":"Improved dark mode default styling with color-scheme (web.dev)","url":"https://web.dev/articles/color-scheme"}],"quiz":[{"q":"<p>كتبت <code dir=\"ltr\">--surface: light-dark(white, #0f172a)</code> واستخدمتها على <code dir=\"ltr\">body</code>، لكن الصفحة تبقى بيضاء في الوضع الداكن. ما الناقص؟</p>","options":[{"text":"كتلة <code dir=\"ltr\">@media (prefers-color-scheme: dark)</code> حول الـ token.","why":"هذه هي التقنية الأقدم؛ و<code dir=\"ltr\">light-dark()</code> وُجدت كي لا تحتاج إليها. إنها تقرأ النظام اللوني بدلًا من ذلك."},{"text":"<code dir=\"ltr\">color-scheme: light dark</code> على الجذر (أو على العنصر).","why":"صحيح. دونها يكون النظام اللوني المستخدم فاتحًا، فتُرجع <code dir=\"ltr\">light-dark()</code> قيمتها الأولى دائمًا."},{"text":"تسجيل <code dir=\"ltr\">--surface</code> بـ <code dir=\"ltr\">@property</code>.","why":"الـ custom properties غير المسجّلة تعمل جيدًا هنا؛ و<code dir=\"ltr\">light-dark()</code> تُحسم حيث يُستخدم الـ token."},{"text":"الوضع الداكن لا يعمل إلا حين يُكتب اللون بـ oklch().","why":"<code dir=\"ltr\">light-dark()</code> تقبل أيّ صيغة ألوان."}],"answer":1},{"q":"<p>يجب أن تبدو الواجهة الرئيسية (hero) في Waypoint داكنة دائمًا، حتى في الوضع الفاتح. ألوانها تأتي من tokens بـ <code dir=\"ltr\">light-dark()</code>. ما أصغر تغيير ممكن؟</p>","options":[{"text":"كرّر كل token ببادئة <code dir=\"ltr\">--hero-</code> تحمل القيم الداكنة.","why":"ينجح، لكنه يضاعف مجموعة الـ tokens، وتنحرف النسختان لحظة يعدّل أحدهم إحداهما."},{"text":"أضف <code dir=\"ltr\">data-theme=&quot;dark&quot;</code> إلى عنصر الـ hero.","why":"هذه السمة لا تهمّ إلا إن كانت الـ CSS لديك تقرؤها هناك؛ ومفتاح التبديل في هذا الدرس يقرؤها على الجذر."},{"text":"أضف <code dir=\"ltr\">color-scheme: dark</code> إلى <code dir=\"ltr\">.hero</code>.","why":"صحيح. تُحسم <code dir=\"ltr\">light-dark()</code> بحسب النظام اللوني المستخدم في كل عنصر، وهو موروث، فيلتقط الـ hero وكل ما بداخله القيم الداكنة."}],"answer":2},{"q":"<p>ما وظيفة <code dir=\"ltr\">&lt;meta name=&quot;color-scheme&quot; content=&quot;light dark&quot;&gt;</code> في رأس الـ HTML؟</p>","options":[{"text":"تتيح للمتصفّح اختيار النظام الصحيح لخلفية الصفحة قبل تحميل الـ CSS، فتتجنّب الوميض الأبيض في الوضع الداكن.","why":"صحيح. يُقرأ وسم الـ meta لحظة تحليل الـ HTML، فيكون لون الخلفية الأوّلي صحيحًا من أول رسم."},{"text":"إنها شرط لعمل <code dir=\"ltr\">light-dark()</code>.","why":"خاصية <code dir=\"ltr\">color-scheme</code> في CSS تكفي لـ <code dir=\"ltr\">light-dark()</code>؛ ووسم الـ meta يساعد في الرسم الأول."},{"text":"تحلّ محلّ media query <code dir=\"ltr\">prefers-color-scheme</code> في كل ملفات الأنماط.","why":"الـ media queries تظل تعمل؛ ووسم الـ meta يعلن فقط الأنظمة اللونية التي تدعمها الصفحة."}],"answer":0}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<section class=\"hero\">\n  <h1>Waypoint Conf 2026</h1>\n  <article class=\"session-card\" id=\"keynote\">Keynote · The Platform Is the Framework</article>\n</section>\n<main class=\"schedule\">\n  <article class=\"session-card\" id=\"regular\">Shipping View Transitions</article>\n</main>","css":":root {\n  --surface: #ffffff;\n  --text: #1f2937;\n  --card: #f8fafc;\n}\n@media (prefers-color-scheme: dark) {\n  :root {\n    --surface: #0f172a;\n    --text: #e5e7eb;\n    --card: #1e293b;\n  }\n}\n\nbody {\n  background: var(--surface);\n  color: var(--text);\n}\n.hero {\n  padding: 16px;\n  background: var(--surface);\n  color: var(--text);\n}\n.hero h1 { margin: 0 0 12px; font-size: 1.4rem; }\n.session-card {\n  margin-block: 8px;\n  padding: 12px;\n  border-radius: 12px;\n  background: var(--card);\n}\n"},"solution":{"html":"<section class=\"hero\">\n  <h1>Waypoint Conf 2026</h1>\n  <article class=\"session-card\" id=\"keynote\">Keynote · The Platform Is the Framework</article>\n</section>\n<main class=\"schedule\">\n  <article class=\"session-card\" id=\"regular\">Shipping View Transitions</article>\n</main>","css":":root {\n  color-scheme: light dark;\n  --surface: light-dark(#ffffff, #0f172a);\n  --text: light-dark(#1f2937, #e5e7eb);\n  --card: light-dark(#f8fafc, #1e293b);\n}\n:root[data-theme=\"light\"] { color-scheme: light; }\n:root[data-theme=\"dark\"] { color-scheme: dark; }\n\nbody {\n  background: var(--surface);\n  color: var(--text);\n}\n.hero {\n  color-scheme: dark;\n  padding: 16px;\n  background: var(--surface);\n  color: var(--text);\n}\n.hero h1 { margin: 0 0 12px; font-size: 1.4rem; }\n.session-card {\n  margin-block: 8px;\n  padding: 12px;\n  border-radius: 12px;\n  background: var(--card);\n}\n"},"checks":[{"id":"forced-dark","test":"const root = document.documentElement; const set = async (v) => { if (v) root.dataset.theme = v; else delete root.dataset.theme; await tick(16); }; await set(\"dark\"); let ok = false; try { ok = (style('body', 'background-color') === 'rgb(15, 23, 42)' && style('body', 'color') === 'rgb(229, 231, 235)' && style('#regular', 'background-color') === 'rgb(30, 41, 59)'); } finally { await set(null); } return ok;"},{"id":"forced-light","test":"const root = document.documentElement; const set = async (v) => { if (v) root.dataset.theme = v; else delete root.dataset.theme; await tick(16); }; await set(\"light\"); let ok = false; try { ok = (style('body', 'background-color') === 'rgb(255, 255, 255)' && style('body', 'color') === 'rgb(31, 41, 55)' && style('#regular', 'background-color') === 'rgb(248, 250, 252)'); } finally { await set(null); } return ok;"},{"id":"scheme-follows-toggle","test":"const root = document.documentElement; const set = async (v) => { if (v) root.dataset.theme = v; else delete root.dataset.theme; await tick(16); }; await set(\"dark\"); let ok = false; try { ok = (style(root, 'color-scheme') === 'dark'); } finally { await set(null); } return ok;"},{"id":"system-default","test":"const root = document.documentElement; const set = async (v) => { if (v) root.dataset.theme = v; else delete root.dataset.theme; await tick(16); }; await set(null); return style(root, 'color-scheme') === 'light dark';"},{"id":"hero-always-dark","test":"const root = document.documentElement; const set = async (v) => { if (v) root.dataset.theme = v; else delete root.dataset.theme; await tick(16); }; await set(\"light\"); let ok = false; try { ok = (style('.hero', 'color-scheme') === 'dark' && style('.hero', 'background-color') === 'rgb(15, 23, 42)' && style('#keynote', 'background-color') === 'rgb(30, 41, 59)' && style('#regular', 'background-color') === 'rgb(248, 250, 252)'); } finally { await set(null); } return ok;"}],"title":"مجموعة tokens واحدة وثلاثة ثيمات","prompt":"<p>أعد كتابة الثيم بحيث:</p>\n<ol>\n<li>يعلن الجذر دعمه للنظامين اللونيين <strong>كليهما</strong>، وتُعرَّف كلٌّ من <code dir=\"ltr\">--surface</code> و<code dir=\"ltr\">--text</code> و<code dir=\"ltr\">--card</code> <strong>مرة واحدة</strong> بـ <code dir=\"ltr\">light-dark()</code> (القيم الفاتحة: <code dir=\"ltr\">#ffffff</code> و<code dir=\"ltr\">#1f2937</code> و<code dir=\"ltr\">#f8fafc</code>؛ والداكنة: <code dir=\"ltr\">#0f172a</code> و<code dir=\"ltr\">#e5e7eb</code> و<code dir=\"ltr\">#1e293b</code>). احذف الـ media query.</li>\n<li><code dir=\"ltr\">data-theme=&quot;light&quot;</code> أو <code dir=\"ltr\">data-theme=&quot;dark&quot;</code> على <code dir=\"ltr\">&lt;html&gt;</code> تفرض ذلك النظام؛ ودون السمة تتبع الصفحة إعداد النظام.</li>\n<li>يكون <code dir=\"ltr\">.hero</code> داكنًا في كل الأوضاع، باستخدام الـ tokens نفسها (بلا ألوان خاصة بالـ hero).</li>\n</ol>\n<p>تضبط الفحوصات <code dir=\"ltr\">data-theme</code> على <code dir=\"ltr\">&lt;html&gt;</code> وتقرأ الألوان المحسوبة.</p>\n","hints":["<code dir=\"ltr\">light-dark()</code> لا تعمل إلا حين تسمح <code dir=\"ltr\">color-scheme</code> بالداكن. ابدأ بـ <code dir=\"ltr\">color-scheme: light dark</code> على <code dir=\"ltr\">:root</code>.","قواعد مفتاح التبديل لا تغيّر إلا <code dir=\"ltr\">color-scheme</code>: <code dir=\"ltr\">:root[data-theme=&quot;dark&quot;] { color-scheme: dark; }</code>، والأمر نفسه للفاتح.","للـ hero أضف <code dir=\"ltr\">color-scheme: dark;</code> إلى <code dir=\"ltr\">.hero</code>. عندها تُحسم <code dir=\"ltr\">var(--surface)</code> فيه و<code dir=\"ltr\">var(--card)</code> في البطاقة المتداخلة إلى القيم الداكنة."],"explanation":"<p>تختار <code dir=\"ltr\">light-dark()</code> قيمة بحسب النظام اللوني المستخدم في العنصر الذي يُستخدم فيه الـ token، و<code dir=\"ltr\">color-scheme</code> هي التي تضبط ذلك النظام. <code dir=\"ltr\">color-scheme: light dark</code> على الجذر تتبع نظام التشغيل؛ وقواعد <code dir=\"ltr\">data-theme</code> تتجاوزها بخاصية واحدة، فيتبعها كل token دون مجموعة tokens ثانية. ولأن <code dir=\"ltr\">light-dark()</code> تُحسم لكل عنصر و<code dir=\"ltr\">color-scheme</code> موروثة، فإن <code dir=\"ltr\">color-scheme: dark</code> على <code dir=\"ltr\">.hero</code> تجعل الـ hero وبطاقة الـ keynote داخله داكنين بينما تبقى البطاقة العادية فاتحة.</p>\n","checkLabels":{"forced-dark":"data-theme=“dark” تجعل الصفحة داكنة","forced-light":"data-theme=“light” تجعل الصفحة فاتحة","scheme-follows-toggle":"قيمة color-scheme على الجذر تتبع مفتاح التبديل","system-default":"دون data-theme يدعم الجذر النظامين كليهما","hero-always-dark":"الـ hero وبطاقته يبقيان داكنين في الوضع الفاتح"}},"words":618,"readMinutes":4}