{"id":"l-css-3-3","courseId":"css-mastery","lang":"ar","kind":"lesson","summary":"عرّف الألوان بـ oklch() لتكون الإضاءة متوقّعة، واشتقّ الدرجات الفاتحة بـ color-mix()، وابنِ حالات المرور والتعطيل من لون أساسي واحد بصيغة الألوان النسبية.","html":"<p>اختيرت ألوان المسارات الأربعة في Waypoint واحدًا تلو الآخر في أداة تصميم، كأكواد hex. بدا وردي Design صاخبًا، وأخضر Accessibility باهتًا، ونجح النص الأبيض في الشارات في اختبار التباين على مسارين وفشل على الآخرَين. وحين احتاج الفريق إلى درجة فاتحة لخلفية شارة كل مسار، ولّد أحدهم ثمانية أكواد hex أخرى بالعين. ثم جاءت حالات المرور. عشرون لونًا، بلا نظام، ولا أحد يستطيع أن يقول لماذا <code dir=\"ltr\">#0891b2</code> هو اللون الصحيح.</p>\n<p>ألوان CSS الحديثة تتيح لك تعريف لون أساسي واحد لكل مسار، واشتقاق كل ما عداه بقواعد.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">لماذا oklch()</h2>\n<p>hex و<code dir=\"ltr\">rgb()</code> و<code dir=\"ltr\">hsl()</code> كلها تصف الألوان في فضاء sRGB، المنظّم حول طريقة إطلاق الشاشات للضوء، لا طريقة رؤية العين له. و«الإضاءة» في HSL أسوأ المذنبين: <code dir=\"ltr\">hsl(60 100% 50%)</code> (الأصفر) و<code dir=\"ltr\">hsl(240 100% 50%)</code> (الأزرق) يدّعيان الإضاءة نفسها، لكن الأصفر مبهر والأزرق داكن. وأيّ لوحة ألوان تُبنى بتدوير درجة اللون في HSL تنتهي بتباين متفاوت بشدّة.</p>\n<p><code dir=\"ltr\">oklch()</code> مبنية على نموذج OKLab، المصمّم لتتبع الأرقامُ الإدراكَ:</p>\n<ul>\n<li><strong>L</strong>، الإضاءة، من 0 (الأسود) إلى 1 أو 100% (الأبيض)، والـ L المتساوية تبدو بالإضاءة نفسها عبر درجات اللون.</li>\n<li><strong>C</strong>، التشبّع اللوني (chroma)، من 0 (الرمادي) إلى نحو 0.37 لأكثر الألوان حيوية التي تستطيع الشاشات عرضها.</li>\n<li><strong>H</strong>، زاوية درجة اللون بالدرجات: حول 30 أحمر، و140 أخضر، و250 أزرق، و350 وردي.</li>\n</ul>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">tokens.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:#953800;--shiki-dark:#FFA657\">  --track-design</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\">62</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.19</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 350</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">  --track-perf</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\">62</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.19</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 220</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">  --track-a11y</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\">62</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.19</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 150</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">  --track-platform</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\">62</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.19</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></code></pre></div>\n<p>إضاءة واحدة، وتشبّع واحد، وأربع درجات لون. أصبحت المسارات تحمل وزنًا بصريًا متساويًا، وإن نجح النص الأبيض في اختبار التباين على أحدها فسيكون على مسافة قصيرة جدًا من النجاح على الأربعة. ما زلت تتحقّق من التباين (نماذج الإدراك ليست معادلات تباين)، لكنك تبدأ من نقطة قريبة بدل التخمين.</p>\n<aside class=\"callout callout-note\" 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\"/><path d=\"M12 16v-4\"/><path d=\"M12 8h.01\"/></svg><span><span class=\"callout-kind\">ملاحظة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>نطاق لوني واسع مجانًا</span></p>\n<p>تستطيع OKLCH وصف ألوان خارج sRGB، مثل الأخضر الحيوي الذي تستطيع شاشة P3 عرضه. وإن لم تستطع الشاشة عرض لون ما، ينقله المتصفّح إلى أقرب لون تستطيعه. ولهذا قد يبدو تشبّع عالٍ مثل 0.25 مختلفًا قليلًا بين هاتف جديد وشاشة قديمة. و<code dir=\"ltr\">oklch()</code> ضمن Baseline منذ 2023 ومتاحة على نطاق واسع منذ أواخر 2025.</p>\n</aside>\n<h2 id=\"sec-2\" tabindex=\"-1\">الدرجات الفاتحة والداكنة بـ color-mix()</h2>\n<p>تمزج <code dir=\"ltr\">color-mix()</code> لونين في فضاء ألوان تختاره:</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:#0550AE;--shiki-dark:#79C0FF\">.badge</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\">color-mix</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">in</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> oklch</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\">--track</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">15</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">white</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\">color-mix</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">in</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> oklch</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\">--track</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">70</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">black</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.is-cancelled</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\">color-mix</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#953800;--shiki-dark:#FFA657\">in</span><span style=\"color:#953800;--shiki-dark:#FFA657\"> oklch</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\">--track</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">), </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">transparent</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 85</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:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>النسبة المئوية تخصّ اللون الذي تليه؛ واللون الآخر يأخذ الباقي. لذا فإن <code dir=\"ltr\">var(--track) 15%, white</code> أبيض في معظمه مع لمحة من لون المسار: خلفية شارة. والمزج مع <code dir=\"ltr\">transparent</code> يُنتج نسخة شبه شفافة، دون الحاجة إلى token منفصل للشفافية.</p>\n<p>فضاء الألوان يغيّر النتيجة. مزج الأزرق والأصفر <code dir=\"ltr\">in srgb</code> يمرّ برمادي موحل؛ أما <code dir=\"ltr\">in oklch</code> فتنتقل درجة اللون حول العجلة وتبقى حيوية. ولدرجات الواجهة الفاتحة تعطي <code dir=\"ltr\">oklch</code> أو <code dir=\"ltr\">oklab</code> أكثر الخطوات انتظامًا. و<code dir=\"ltr\">color-mix()</code> ضمن Baseline 2023.</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>التعتيم بالمزج مع الأسود لحالات المرور</span></p>\n<p><code dir=\"ltr\">color-mix(in srgb, var(--track), black 20%)</code> تبدو جيدة على الوردي، لكن فضاء sRGB ليس منتظمًا إدراكيًا: النسبة نفسها، 20%، تُغمق بعض درجات اللون أكثر بكثير من غيرها وتُخمد تشبّعها، فلا تعود حالات المرور الأربع متطابقة. حين تريد «اللون نفسه، أغمق قليلًا» بمقدار يمكن توقّعه، غيّر الإضاءة وحدها، وهذا بالضبط ما وُجدت له الألوان النسبية.</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=\"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\">.session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#953800;--shiki-dark:#FFA657\">  --track</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\">--track-design</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  border-inline-start</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">6</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\">--track</span><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\">  &#x26;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">:hover</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">,</span></span>\n<span class=\"line\"><span style=\"color:#116329;--shiki-dark:#7EE787\">  &#x26;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.is-active</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    border-color</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\">(from </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\">--track</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">calc</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(l </span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">-</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.15</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) c h);</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\">  &#x26;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.is-past</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    border-color</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\">(from </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\">--track</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) l </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.03</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> h);   </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* nearly grey, same hue */</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\">  &#x26;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> .badge-soft</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\">oklch</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(from </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\">--track</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) l c h / </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">20</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">%</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">);  </span><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* same color, 20% alpha */</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>بعد <code dir=\"ltr\">from var(--track)</code> تحمل الكلمات المفتاحية <code dir=\"ltr\">l</code> و<code dir=\"ltr\">c</code> و<code dir=\"ltr\">h</code> قنوات اللون الأساسي كأرقام، وتستطيع استخدامها في <code dir=\"ltr\">calc()</code>. لاحظ أن <code dir=\"ltr\">l</code> هنا رقم من 0 إلى 1، لذا فطرح 0.15 يُغمق اللون 15 نقطة. وكل حالة مشتقّة تتبع الآن اللون الأساسي تلقائيًا: أضف مسارًا خامسًا، وستوجد أشكال المرور والماضي والدرجة الناعمة الخاصة به لحظة تعريف لونه الأساسي.</p>\n<p>الألوان النسبية ضمن Baseline 2024، في Chrome وEdge وFirefox وSafari. وإن كان عليك دعم متصفّحات أقدم، فلا تعتمد على تصريح احتياطي ثابت تكتبه قبلها: هذه القيم تحتوي على <code dir=\"ltr\">var()</code>، فيقبلها المتصفّح القديم وقت التحليل، ثم يقع في فخّ «غير صالح في وقت حساب القيمة» الذي رأيته في درس <a href=\"/ar/lesson/css-mastery/l-css-1-4\">الـ Custom Properties و@property</a>، فيضيع البديل أيضًا. بدلًا من ذلك غلّف الحالات المشتقّة بـ <code dir=\"ltr\">@supports (color: oklch(from red l c h)) { … }</code>، فتحتفظ المتصفّحات القديمة بالقاعدة الأساسية.</p>\n<aside class=\"callout callout-tip\" 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=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">نصيحة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>اقرأ الألوان في DevTools وأنت تعمل</span></p>\n<p>يعرض Chrome وFirefox عيّنة لونية بجوار كل لون، والنقر عليها يفتح منتقي ألوان يستطيع عرض OKLCH والتحويل إليها. وحين يبدو لون مشتقّ خاطئًا، تخبرك القيمة المحسوبة بالضبط بما انتهت إليه <code dir=\"ltr\">l</code> و<code dir=\"ltr\">c</code> و<code dir=\"ltr\">h</code>.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">دورك الآن</h2>\n<p>لبطاقة التمرين قيم hex مكتوبة يدويًا لدرجة الشارة الفاتحة وللحدّ في الحالة النشطة. استبدلها بدرجة فاتحة بـ <code dir=\"ltr\">color-mix()</code> وحالة نشطة بلون نسبي، وأضف مسار Performance يطابق مسار Design في الإضاءة والتشبّع. تقرأ الفحوصات قنوات OKLCH المحسوبة. وبعدها ستنقل لوحة الألوان هذه إلى الوضع الداكن باستخدام <code dir=\"ltr\">color-scheme</code> و<code dir=\"ltr\">light-dark()</code>.</p>\n","toc":[{"id":"sec-1","text":"لماذا oklch()","level":2},{"id":"sec-2","text":"الدرجات الفاتحة والداكنة بـ color-mix()","level":2},{"id":"sec-3","text":"الألوان النسبية: عدّل قناة واحدة","level":2},{"id":"sec-4","text":"دورك الآن","level":2}],"takeaways":["<code dir=\"ltr\">oklch(L C H)</code> تفصل الإضاءة المُدرَكة (lightness) عن التشبّع اللوني (chroma) وعن درجة اللون (hue)، فيبدو لونان لهما L نفسها بالإضاءة نفسها، وهذا ما لا تستطيع HSL أن تعد به.","لوحة ألوان بإضاءة وتشبّع ثابتين ودرجات لون متغيّرة تعطي كل فئة الوزن البصري نفسه وتباينًا متقاربًا.","<code dir=\"ltr\">color-mix(in oklch, var(--track) 15%, white)</code> تصنع درجة فاتحة من أيّ لون أساسي، وفضاء الألوان الذي تمزج فيه يغيّر النتيجة.","صيغة الألوان النسبية، مثل <code dir=\"ltr\">oklch(from var(--track) calc(l - 0.15) c h)</code>، تشتقّ لون الحالة بتعديل قناة واحدة من اللون الأساسي."],"further":[{"title":"oklch() (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/oklch"},{"title":"color-mix() (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Values/color_value/color-mix"},{"title":"Using relative colors (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Colors/Using_relative_colors"}],"quiz":[{"q":"<p>للونين <code dir=\"ltr\">hsl(60 100% 50%)</code> و<code dir=\"ltr\">hsl(240 100% 50%)</code> قيمة الإضاءة نفسها. لماذا يُقرأ النص الأبيض جيدًا على أحدهما وسيئًا على الآخر؟</p>","options":[{"text":"لأن إضاءة HSL ليست إدراكية؛ الأصفر الصافي يبدو أفتح بكثير من الأزرق الصافي عند L نفسها.","why":"صحيح. HSL إعادة ترتيب هندسية لـ RGB. أما L في OKLCH فمصمّمة لتطابق الإضاءة المُدرَكة، فتعني L المتساوية تباينًا متقاربًا."},{"text":"لأن المتصفّح يرسم الأصفر بسطوع إضافي على معظم الشاشات.","why":"الشاشات ترسم اللونين كما حُدّدا؛ الفرق في الإدراك البشري، الذي لا تمثّله HSL."},{"text":"لأن إضاءة 50% خارج نطاق sRGB اللوني للأزرق.","why":"ألوان <code dir=\"ltr\">hsl()</code> داخل sRGB دائمًا؛ النطاق اللوني (gamut) ليس المشكلة هنا."}],"answer":0},{"q":"<p>ما الذي تُنتجه <code dir=\"ltr\">color-mix(in oklch, var(--track) 20%, white)</code> حين تكون <code dir=\"ltr\">--track</code> لونًا ورديًا مشبعًا؟</p>","options":[{"text":"ورديًا بشفافية 20% فوق ما يقع خلفه.","why":"المزج مع الأبيض يُنتج لونًا معتمًا. الشفافية تأتي من المزج مع <code dir=\"ltr\">transparent</code>."},{"text":"ورديًا أغمق، لأن 20% كمية قليلة من الأبيض.","why":"الـ 20% تخصّ الوردي؛ والأبيض يأخذ الـ 80% المتبقية، فتكون النتيجة أفتح بكثير."},{"text":"درجة وردية باهتة، 20% وردي و80% أبيض، ممزوجة في OKLCH.","why":"صحيح. النسب المئوية تخصّ اللون الذي تليه، واللون الآخر يأخذ الباقي."},{"text":"خطأ، لأن الـ custom properties لا يمكن استخدامها داخل color-mix().","why":"<code dir=\"ltr\">var()</code> تعمل داخل <code dir=\"ltr\">color-mix()</code> كما تعمل في أيّ مكان آخر؛ وتُستبدل قبل تقييم الدالة."}],"answer":2},{"q":"<p>أيّ تصريح يعطي حالة المرور لونًا أغمق من <code dir=\"ltr\">--track</code> بمقدار 0.1 مع التشبّع ودرجة اللون نفسيهما، أيًّا كانت <code dir=\"ltr\">--track</code>؟</p>","options":[{"text":"<code dir=\"ltr\">filter: brightness(0.9)</code>","why":"<code dir=\"ltr\">filter</code> تُعتّم العنصر كله، بما فيه النصوص والصور، وتعمل في فضاء RGB، فقد تنزاح درجة اللون."},{"text":"<code dir=\"ltr\">background: oklch(from var(--track) calc(l - 0.1) c h)</code>","why":"صحيح. صيغة الألوان النسبية تفكّ اللون الأساسي إلى <code dir=\"ltr\">l</code> و<code dir=\"ltr\">c</code> و<code dir=\"ltr\">h</code>، وتتيح لك تعديل قناة واحدة، ثم تعيد تركيبه."},{"text":"<code dir=\"ltr\">background: oklch(calc(var(--track) - 0.1))</code>","why":"لا يمكنك الطرح من لون كامل؛ ودون <code dir=\"ltr\">from</code> تتوقّع <code dir=\"ltr\">oklch()</code> ثلاث قيم منفصلة للقنوات."}],"answer":1},{"q":"<p>ألوان المسارات لديك مكتوبة بالشكل <code dir=\"ltr\">oklch(62% 0.25 150)</code>، وعلى حاسوب محمول قديم بشاشة sRGB يبدو الأخضر مختلفًا قليلًا عنه على شاشة P3 لدى المصمّم. ماذا حدث؟</p>","options":[{"text":"رفض المتصفّح اللون واستخدم البديل الاحتياطي.","why":"اللون صالح. الألوان خارج النطاق لا تُرفض؛ بل تُنقل إلى ما تستطيع الشاشة عرضه."},{"text":"OKLCH غير مدعومة على ذلك الحاسوب.","why":"الدعم يعتمد على المتصفّح لا على الشاشة، وكل المتصفّحات الحالية تدعم <code dir=\"ltr\">oklch()</code>."},{"text":"شاشة P3 غير معايَرة جيدًا.","why":"الفرق متوقّع: التشبّع أعلى مما تستطيع شاشات sRGB عرضه."},{"text":"اللون خارج نطاق sRGB، فنقله المتصفّح إلى أقرب لون تستطيع الشاشة عرضه.","why":"صحيح. تستطيع <code dir=\"ltr\">oklch()</code> وصف ألوان أكثر حيوية من sRGB. الشاشات واسعة النطاق تعرضها؛ والبقية تحصل على أقرب لون قابل للعرض."}],"answer":3}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<article class=\"session-card track-design is-active\" id=\"design\">\n  <h3>Designing in oklch()</h3>\n  <span class=\"badge\">Design</span>\n</article>\n<article class=\"session-card track-perf\" id=\"perf\">\n  <h3>The Cost of a Frame</h3>\n  <span class=\"badge\">Performance</span>\n</article>","css":".track-design { --track: oklch(62% 0.19 350); }\n\n.session-card {\n  margin-block-end: 12px;\n  padding: 12px 16px;\n  border-radius: 12px;\n  border-inline-start: 6px solid var(--track, #94a3b8);\n}\n.session-card h3 { margin: 0 0 8px; }\n.badge {\n  display: inline-block;\n  padding: 0.1em 0.6em;\n  border-radius: 999px;\n}\n\n/* Hand-picked values: replace them with rules derived from --track */\n.badge { background: #fce7f3; }\n.session-card.is-active { border-inline-start-color: #9d174d; }\n\n/* Add the Performance track here */\n"},"solution":{"html":"<article class=\"session-card track-design is-active\" id=\"design\">\n  <h3>Designing in oklch()</h3>\n  <span class=\"badge\">Design</span>\n</article>\n<article class=\"session-card track-perf\" id=\"perf\">\n  <h3>The Cost of a Frame</h3>\n  <span class=\"badge\">Performance</span>\n</article>","css":".track-design { --track: oklch(62% 0.19 350); }\n\n.session-card {\n  margin-block-end: 12px;\n  padding: 12px 16px;\n  border-radius: 12px;\n  border-inline-start: 6px solid var(--track, #94a3b8);\n}\n.session-card h3 { margin: 0 0 8px; }\n.badge {\n  display: inline-block;\n  padding: 0.1em 0.6em;\n  border-radius: 999px;\n}\n\n.track-perf { --track: oklch(62% 0.19 220); }\n\n.badge { background: color-mix(in oklch, var(--track) 15%, white); }\n.session-card.is-active {\n  border-inline-start-color: oklch(from var(--track) calc(l - 0.15) c h);\n}\n"},"checks":[{"id":"badge-tint","test":"const ok = (s) => { const m = /oklch\\(([\\d.]+) ([\\d.]+) ([\\d.]+)/.exec(s); return m ? m.slice(1).map(Number) : null; }; const near = (a, b, t) => Math.abs(a - b) <= t; const c = ok(style('#design .badge', 'background-color')); return !!c && near(c[0], 0.943, 0.01) && near(c[1], 0.0285, 0.006) && near(c[2], 350, 2);"},{"id":"active-darker","test":"const ok = (s) => { const m = /oklch\\(([\\d.]+) ([\\d.]+) ([\\d.]+)/.exec(s); return m ? m.slice(1).map(Number) : null; }; const near = (a, b, t) => Math.abs(a - b) <= t; const c = ok(style('#design', 'border-left-color')); return !!c && near(c[0], 0.47, 0.01) && near(c[1], 0.19, 0.01) && near(c[2], 350, 1);"},{"id":"perf-track","test":"const ok = (s) => { const m = /oklch\\(([\\d.]+) ([\\d.]+) ([\\d.]+)/.exec(s); return m ? m.slice(1).map(Number) : null; }; const near = (a, b, t) => Math.abs(a - b) <= t; const c = ok(style('#perf', 'border-left-color')); return !!c && near(c[0], 0.62, 0.01) && near(c[1], 0.19, 0.01) && near(c[2], 220, 1);"},{"id":"perf-badge-follows","test":"const ok = (s) => { const m = /oklch\\(([\\d.]+) ([\\d.]+) ([\\d.]+)/.exec(s); return m ? m.slice(1).map(Number) : null; }; const near = (a, b, t) => Math.abs(a - b) <= t; const c = ok(style('#perf .badge', 'background-color')); return !!c && near(c[0], 0.943, 0.01) && near(c[2], 220, 2);"},{"id":"derived-for-new-tracks","test":"const ok = (s) => { const m = /oklch\\(([\\d.]+) ([\\d.]+) ([\\d.]+)/.exec(s); return m ? m.slice(1).map(Number) : null; }; const near = (a, b, t) => Math.abs(a - b) <= t; const card = $('#perf'); card.classList.add('is-active'); await tick(16); const c = ok(style(card, 'border-left-color')); card.classList.remove('is-active'); await tick(16); return !!c && near(c[0], 0.47, 0.01) && near(c[2], 220, 1);"}],"title":"اشتقّ ألوان المسارات","prompt":"<p>اللون الأساسي لمسار Design هو <code dir=\"ltr\">--track: oklch(62% 0.19 350)</code>، لكن درجة شارته الفاتحة وحدّه في الحالة النشطة أكواد hex مختارة يدويًا. استبدلها بقواعد تعمل مع <strong>أيّ</strong> مسار:</p>\n<ol>\n<li>خلفية الشارة: امزج <strong>15%</strong> من <code dir=\"ltr\">--track</code> مع <strong>الأبيض</strong>، في <strong>oklch</strong>.</li>\n<li>حدّ البطاقة النشطة (<code dir=\"ltr\">.is-active</code>): لون المسار بإضاءة <strong>أقل بمقدار 0.15</strong>، مع التشبّع ودرجة اللون نفسيهما، باستخدام صيغة الألوان النسبية.</li>\n<li>أضف class اسمه <code dir=\"ltr\">.track-perf</code> تكون فيه <code dir=\"ltr\">--track</code> بإضاءة Design وتشبّعه نفسيهما، ودرجة لون <strong>220</strong>.</li>\n</ol>\n<p>تقرأ الفحوصات قيم OKLCH المحسوبة، وتُفعّل بطاقة Performance أيضًا لتتأكّد من أن قواعدك ليست خاصة بمسار واحد.</p>\n","hints":["<code dir=\"ltr\">color-mix(in oklch, A 15%, B)</code> تعطي 15% من A و85% من B.","الصيغة النسبية تبدأ بـ <code dir=\"ltr\">from</code>: <code dir=\"ltr\">oklch(from var(--track) … c h)</code>. والقناة <code dir=\"ltr\">l</code> رقم من 0 إلى 1.","<code dir=\"ltr\">.badge { background: color-mix(in oklch, var(--track) 15%, white); }</code> و<code dir=\"ltr\">.is-active { border-inline-start-color: oklch(from var(--track) calc(l - 0.15) c h); }</code> و<code dir=\"ltr\">.track-perf { --track: oklch(62% 0.19 220); }</code>."],"explanation":"<p>لونا الحالتين يقرآن الآن <code dir=\"ltr\">--track</code> عند العنصر الذي يُستخدمان فيه، فيحصل كل مسار على درجته الفاتحة وحدّه النشط من قيمة أساسية واحدة. <code dir=\"ltr\">color-mix(in oklch, var(--track) 15%, white)</code> تنتقل بالإضاءة والتشبّع نحو الأبيض مع الحفاظ على درجة اللون، فتعطي درجة فاتحة باهتة (L ≈ 0.94). والصيغة النسبية تفكّ <code dir=\"ltr\">--track</code> إلى <code dir=\"ltr\">l</code> و<code dir=\"ltr\">c</code> و<code dir=\"ltr\">h</code>، وتطرح 0.15 من الإضاءة وتعيد التركيب، فيكون الحدّ النشط الوردي نفسه، لكن أغمق. ولأن مسار Performance يشارك Design في L وC، تحمل ألوانه الوزن البصري نفسه.</p>\n","checkLabels":{"badge-tint":"شارة Design درجة فاتحة بنسبة 15% من لون المسار","active-darker":"الحدّ النشط أغمق من لون المسار بمقدار 0.15","perf-track":"لمسار Performance قيمتا L وC نفسيهما ودرجة لون 220","perf-badge-follows":"درجة شارة Performance الفاتحة تتبع مسارها هي","derived-for-new-tracks":"بطاقة Performance النشطة تحصل على حدّ أغمق خاص بها"}},"words":709,"readMinutes":4}