Kodokon kodokon.com

สีและฟังก์ชันขั้นสูง: oklch, color-mix, min/max

ใช้ประโยชน์จากพื้นที่สีเชิงการรับรู้ ไวยากรณ์สีแบบสัมพัทธ์ และฟังก์ชันคณิตศาสตร์แบบมีชนิด เพื่อสร้าง design system ที่เบราว์เซอร์คำนวณให้คุณ

10 นาที · 3 คำถาม

เปิดบทเรียนนี้ใน Kodokon

ข้อบกพร่องเชิงโครงสร้างของ hsl(): ค่าความสว่าง (lightness) ของมันไม่ได้เป็นเชิงการรับรู้ hsl(60 100% 50%) (สีเหลือง) ดูจ้าตา ในขณะที่ hsl(240 100% 50%) (สีน้ำเงิน) ดูมืด ทั้งที่มีค่า L เท่ากัน oklch แก้ปัญหานี้ได้: ส่วนประกอบ L ของมัน (0 ถึง 1) วัดความสว่างที่รับรู้ได้จริง C คือ chroma (ความอิ่มตัวสัมบูรณ์ 0 ถึงราว ๆ 0.37) และ H คือมุมของเฉดสี (hue) การเปลี่ยน H ที่ค่า L คงที่จะรักษาความสว่างที่รับรู้ได้เอาไว้: การแปรผันของพาเลตสีของคุณจึงคาดเดาได้ในที่สุด เมื่อผสานกับ ไวยากรณ์สีแบบสัมพัทธ์ (from) เบราว์เซอร์จะคำนวณตัวแปรสีสำหรับ hover, muted หรือ dark ให้เองโดยอัตโนมัติ

CSS
: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));
}
สีต้นทางเพียงสีเดียว ให้อนุพันธ์ที่คำนวณได้สามสี: แชนเนล l, c, h ถูกเปิดเผยออกมาเป็นตัวแปรท้องถิ่น

oklch สามารถอธิบายสีที่อยู่ นอก ขอบเขต (gamut) ของ sRGB หรือแม้แต่นอก Display-P3 ได้ เบราว์เซอร์ทำอย่างไรเมื่อหน้าจอไม่สามารถแสดงสีเหล่านั้นได้? มันไม่ได้ตัดสีแบบหักดิบทีละแชนเนล: สเปกกำหนดให้ทำ gamut mapping ที่จะค่อย ๆ ลดค่า chroma ลงในขณะที่ยังคงรักษาความสว่างและเฉดสีไว้ จนกว่าสีจะเข้าไปอยู่ในขอบเขตเป้าหมายได้พอดี คุณสามารถกำหนดเป้าหมายเป็นหน้าจอ wide-gamut ได้อย่างชัดเจนด้วย @media (color-gamut: p3) อีกเครื่องมือหนึ่งสำหรับการผสมสีคือ color-mix() ซึ่งอาร์กิวเมนต์แรกของมัน คือพื้นที่การประมาณค่า (interpolation space) นั้นเปลี่ยนผลลัพธ์ได้อย่างแท้จริง: การผสมสีน้ำเงินกับสีเหลืองแบบ in srgb จะกลายเป็นสีเทา ในขณะที่แบบ in oklch จะเดินทางผ่านเฉดสีที่สดใส

CSS
.badge {
  background: color-mix(in oklch, crimson 70%, white);
  border-color: color-mix(
    in oklch,
    var(--brand),
    transparent 60%
  );
}
การผสมกับ transparent ทำให้ได้ตัวแปรสีแบบโปร่งแสงโดยไม่ต้องเขียนสีซ้ำในรูปแบบ rgba

min(), max() และ clamp() เป็นฟังก์ชันคณิตศาสตร์แบบ มีชนิด (typed): มันยอมรับการผสมหน่วยที่เข้ากันไม่ได้ในช่วงพาร์ส (rem + vw) เพราะการหาค่าเกิดขึ้นในช่วง used-value เมื่อรู้ขนาด viewport แล้ว clamp(MIN, VAL, MAX) เทียบเท่ากับ max(MIN, min(VAL, MAX)) อย่างเคร่งครัด ซึ่งผลที่ตามมาจากสเปกคือ: หาก MIN มากกว่า MAX แล้ว MIN จะชนะ สำหรับการจัดขนาดตัวอักษรแบบลื่นไหล (fluid typography) ให้ใส่ส่วนประกอบที่เป็น rem ไว้ในค่ากลางเสมอ: font-size: clamp(1rem, 2.5vw, 3rem) ที่ไม่มี rem จะเพิกเฉยต่อการซูมข้อความของผู้ใช้ ซึ่งเป็นปัญหาการเข้าถึง (accessibility) อย่างแท้จริง

CSS
h1 {
  font-size: clamp(1.5rem, 1.1rem + 2vw, 3rem);
}
.sidebar {
  width: min(30%, 20rem);
  padding-left: max(1rem, env(safe-area-inset-left));
}
การจัดขนาดตัวอักษรแบบลื่นไหลที่เข้าถึงได้ และช่องว่างขอบที่เคารพรอยบากของหน้าจอมือถือ

ทดสอบความรู้

ตรวจสอบว่าคุณจำประเด็นสำคัญของบทเรียนนี้ได้ครบถ้วน

  1. oklch มีข้อได้เปรียบชี้ขาดอะไรเหนือ hsl?
    • ไวยากรณ์ที่สั้นกว่าในการเขียน
    • ค่าความสว่าง L ที่มีความสม่ำเสมอเชิงการรับรู้ระหว่างเฉดสีต่าง ๆ
    • การรับประกันว่าจะอยู่ภายในขอบเขต sRGB
    • เป็นพื้นที่สีเดียวที่รองรับแชนเนลอัลฟา
  2. เบราว์เซอร์ทำอย่างไรเมื่อสี oklch เกินขอบเขตของหน้าจอ?
    • มันเพิกเฉยต่อการประกาศและคงสีเดิมไว้
    • มันทำ gamut mapping ที่ลดค่า chroma เป็นหลัก
    • มันตัดแต่ละแชนเนล RGB แยกกันโดยไม่มีการประมวลผลเพิ่มเติม
  3. ใน clamp(MIN, VAL, MAX) จะเกิดอะไรขึ้นหากค่า MIN ที่คำนวณได้เกิน MAX?
    • การประกาศจะใช้ไม่ได้และถูกเพิกเฉย
    • MAX ชนะและจำกัดผลลัพธ์ไว้ที่เพดาน
    • MIN ชนะ เพราะ clamp ขยายเป็น max(MIN, min(VAL, MAX))