استثمر فضاءات الألوان الإدراكية، وصياغة الألوان النسبية، والدوال الرياضية المُنمَّطة لبناء أنظمة تصميم يحسبها المتصفح نيابة عنك.
افتح هذا الدرس في Kodokonالعيب البنيوي في hsl(): إضاءتها ليست إدراكية. يبدو hsl(60 100% 50%) (الأصفر) باهرًا بينما يبدو hsl(240 100% 50%) (الأزرق) داكنًا، عند L متطابقة. يصلح oklch ذلك: فمكوّنه L (من 0 إلى 1) يقيس الإضاءة المُدرَكة، وC هو الكروما (التشبّع المطلق، من 0 إلى نحو 0.37) وH زاوية الدرجة اللونية. فتغيير H عند L ثابتة يحافظ على السطوع المُدرَك: تصبح تنويعات لوحتك اللونية أخيرًا قابلة للتنبؤ. وبدمجه مع صياغة الألوان النسبية (from)، يشتق المتصفح تنويعاتك عند التمرير أو المخفوتة أو الداكنة بنفسه.
:root {
--brand: oklch(0.65 0.19 255);
--dark: oklch(from var(--brand) calc(l - 0.15) c h);
--muted: oklch(from var(--brand) l calc(c / 2) h);
--accent: oklch(from var(--brand) l c calc(h + 180));
}يستطيع oklch وصف ألوان خارج نطاق sRGB، بل وحتى خارج Display-P3. ماذا يفعل المتصفح عندما تعجز الشاشة عن عرضها؟ ليس قصًّا فظًّا قناةً بقناة: تفرض المواصفة تعيينًا للنطاق (gamut mapping) يخفض الكروما تدريجيًا مع الحفاظ على الإضاءة والدرجة اللونية، حتى يندرج اللون ضمن النطاق المستهدف. يمكنك استهداف الشاشات ذات النطاق الواسع صراحةً بـ @media (color-gamut: p3). وأداة مزج أخرى: color-mix()، التي تغيّر وسيطتها الأولى - فضاء الاستيفاء - النتيجة فعلًا: مزيج in srgb من الأزرق والأصفر يصير رماديًا، بينما in oklch يعبر درجات لونية زاهية.
.badge {
background: color-mix(in oklch, crimson 70%, white);
border-color: color-mix(
in oklch,
var(--brand),
transparent 60%
);
}إن min() وmax() وclamp() دوال رياضية مُنمَّطة: فهي تقبل خلط وحدات غير متوافقة عند التحليل النحوي (rem + vw) لأن الحسم يحدث عند وقت القيمة المُستخدَمة، حالما تُعرف نافذة العرض. وclamp(MIN, VAL, MAX) مكافئ تمامًا لـ max(MIN, min(VAL, MAX)) - ومن نتائج المواصفة: إن تجاوز MIN قيمة MAX، فاز MIN. وللطباعة السلسة، ضمّن دائمًا مكوّن rem في القيمة الوسطى: فإن font-size: clamp(1rem, 2.5vw, 3rem) بلا rem سيتجاهل تكبير النص لدى المستخدم، وهذه مشكلة حقيقية في إمكانية الوصول.
h1 {
font-size: clamp(1.5rem, 1.1rem + 2vw, 3rem);
}
.sidebar {
width: min(30%, 20rem);
padding-left: max(1rem, env(safe-area-inset-left));
}