2 คะแนน โดย GN⁺ 2025-05-19 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • ฟังก์ชัน contrast-color() ช่วยให้เบราว์เซอร์เลือก สีตัวอักษรเป็นสีดำหรือสีขาว ให้อัตโนมัติตามสีพื้นหลังที่หลากหลาย เช่น ปุ่ม
  • แม้ในโปรเจ็กต์ขนาดใหญ่ก็ช่วยให้ รักษาความอ่านง่ายของข้อความ ได้ง่ายขึ้น และเพิ่มประสิทธิภาพในการดูแลรักษา
  • ปัจจุบันใน Safari Technology Preview ใช้อัลกอริทึมทางการของ WCAG 2 ซึ่งอาจไม่สอดคล้องกับการรับรู้ของมนุษย์จริง
  • กำลังมีการหารือเรื่องการนำอัลกอริทึม APCA รุ่นถัดไปมาใช้ในกระบวนการพัฒนา WCAG 3 และคาดว่าจะช่วยให้ การประเมินคอนทราสต์ด้านความสว่าง ดีขึ้น
  • นอกเหนือจากคอนทราสต์ขาวดำแบบง่าย ๆ แล้ว ในอนาคตยังมีแนวโน้มจะเพิ่มตัวเลือกสีที่หลากหลายและฟีเจอร์ ปรับปรุงการเข้าถึง เพิ่มเติม

ภาพรวมและที่มาของการนำ contrast-color() มาใช้

  • ในงานออกแบบที่มีการใช้สีพื้นหลังหลากหลายกับปุ่มหรือองค์ประกอบอินเทอร์เฟซต่าง ๆ สีตัวอักษร (text color) ที่อ่านง่ายถือว่าสำคัญมาก
  • ก่อนหน้านี้นักพัฒนาต้องจับคู่สีพื้นหลังกับสีข้อความด้วยตัวเองทีละจุด แต่ในโปรเจ็กต์ขนาดใหญ่จะมี ความซับซ้อนในการจัดการและความเสี่ยงต่อความผิดพลาด สูง
  • เมื่อใช้ ฟังก์ชัน CSS contrast-color() นักพัฒนาเพียงกำหนดสีพื้นหลัง แล้วเบราว์เซอร์จะเลือกสีตัวอักษรระหว่างสีดำหรือสีขาวที่มีคอนทราสต์สูงกว่าให้อัตโนมัติ
  • วิธีนี้ช่วยเพิ่ม ประสิทธิภาพของงานดูแลรักษาและงานออกแบบ ได้อย่างมาก
  • สามารถประกาศใช้งานแบบง่าย ๆ เช่น color: contrast-color(สี);

ตัวอย่างการใช้งาน contrast-color()

  • กำหนดสีที่ต้องการให้กับตัวแปรสีพื้นหลังของปุ่ม แล้วให้ contrast-color() เลือกสีข้อความขาวหรือดำที่ตัดกันโดยอัตโนมัติ
  • เพราะต้องดูแลเพียงสีเดียวในแต่ละครั้ง จึงทำให้การเปลี่ยนนโยบายดีไซน์หรือการรองรับโหมดมืด/สว่างทำ maintenance ได้ง่าย
button {
  background-color: var(--button-color);
  color: contrast-color(var(--button-color));
}
  • หากใช้ Relative Color Syntax ก็จะจัดการสีพื้นหลังและสีข้อความของสถานะ hover ให้สอดคล้องกันได้เช่นกัน

ประเด็นด้านการเข้าถึงและคำอธิบายอัลกอริทึม

  • การใช้ contrast-color() ไม่ได้แก้ทุกปัญหาเรื่อง การเข้าถึง (Accessibility) ได้โดยอัตโนมัติ
  • สำหรับสีพื้นหลังที่มีความสว่างระดับกลางบางสี อาจเกิดกรณีที่ทั้งสีดำและสีขาวไม่ผ่านเกณฑ์ที่ต้องการ
  • ปัจจุบัน อัลกอริทึม WCAG 2 ที่ใช้ใน Safari Technology Preview เป็นมาตรฐานทางการด้านการเข้าถึงเว็บ
    • อัลกอริทึมนี้เลือกโดยอิงจากอัตราส่วนคอนทราสต์ แต่บางครั้งผลลัพธ์อาจไม่ตรงกับคอนทราสต์ด้านความสว่างที่ตามนุษย์มองเห็นจริง
  • ตัวอย่างเช่น บนพื้นหลังสีน้ำเงิน #317CFF ระบบคำนวณอาจตัดสินว่าสีดำมีคอนทราสต์สูงกว่า แต่ในความเป็นจริงสีขาวกลับอ่านได้ดีกว่า
  • จากคำวิจารณ์และความต้องการให้ปรับปรุง จึงมีการหารือเพื่อนำ APCA (Accessible Perceptual Contrast Algorithm) ซึ่งดีกว่าเดิม มาใช้ใน มาตรฐานการเข้าถึงยุคถัดไป (WCAG 3)
  • APCA คำนวณคอนทราสต์ของสีโดยสะท้อน ลักษณะการรับรู้ของมนุษย์ จึงช่วยรับประกันความอ่านง่ายในโลกจริงได้ดีกว่า

การให้คอนทราสต์ที่เพียงพอในสภาพแวดล้อมจริง

  • สามารถใช้ media query ของ CSS อย่าง @media (prefers-contrast: more) เพื่อใช้สไตล์คอนทราสต์สูงเพิ่มเติมตาม ความต้องการด้านการเข้าถึงของผู้ใช้
@media (prefers-contrast: more) {
  /* กำหนดสไตล์ที่มีคอนทราสต์สูงขึ้น */
}
  • ตัวอย่างเช่น หากสีหลักของแบรนด์เป็นสีเขียวสว่างอย่าง #2DAD4E แม้ในอนาคต contrast-color() จะเลือกสีขาว ก็อาจยังมีคอนทราสต์ไม่เพียงพอสำหรับข้อความขนาดเล็ก
  • เมื่อใช้อัลกอริทึม APCA จะสามารถอ้างอิงเกณฑ์คอนทราสต์ขั้นต่ำที่ต้องการได้อย่างละเอียดตามขนาดและความหนาของฟอนต์ ช่วยในการตัดสินใจด้านดีไซน์ในการทำงานจริง
    • ตัวอย่างเช่น ข้อความขนาด 24px/น้ำหนัก 400 เหมาะกับการใช้สีขาว แต่ถ้าเป็น FONT ที่บางกว่านี้หรือข้อความขนาดเล็กกว่า ก็ควรใช้สีพื้นหลังที่เข้มขึ้น
  • ทีมออกแบบสามารถจัดการพาเลตสีด้วยตัวแปรให้เหมาะกับแต่ละเงื่อนไขได้ง่าย โดยคำนึงถึง light/dark mode และค่ากำหนด prefers-contrast เป็นต้น
--button-color: #2DAD4E;

@media (prefers-contrast: more) {
  @media (prefers-color-scheme: light) {
    --button-color: #419543;
  }
  @media (prefers-color-scheme: dark) {
    --button-color: #77CA8B;
  }
}
button {
  background-color: var(--button-color);
  color: contrast-color(var(--button-color));
  font-size: 1.5rem;
  font-weight: 500;
}
  • แก่นสำคัญคือด้วย contrast-color() เราจะจัดการเพียงสีโดยยึดสีพื้นหลังเป็นศูนย์กลาง ส่วนคู่สีข้อความที่มีคอนทราสต์เหมาะสม เบราว์เซอร์จะสร้างให้โดยอัตโนมัติ

ก้าวข้ามสีดำและสีขาว

  • ปัจจุบัน contrast-color() ยังเลือกได้เพียง 2 แบบคือขาวหรือดำ แต่ในเวอร์ชันแรกเริ่มนั้นเคยมีแนวคิดให้เลือกจากหลายสีได้
  • CSS Working Group ต้องการรองรับการเปลี่ยนอัลกอริทึมในอนาคตและความเข้ากันได้ จึงเริ่มจากเวอร์ชันเรียบง่ายก่อนคือเลือกเฉพาะขาว/ดำ และมีแผนจะขยายในอนาคต เช่น ตัวเลือกสีกำหนดเอง และการระบุเกณฑ์คอนทราสต์ขั้นต่ำที่ต้องการ
  • สำหรับความต้องการทั่วไป ฟังก์ชันนี้ก็มีประโยชน์มากอยู่แล้ว
  • ฟังก์ชันนี้สามารถประยุกต์ใช้ได้หลากหลาย ไม่ใช่แค่กับ สีพื้นหลัง แต่ยังรวมถึงเส้นขอบและองค์ประกอบด้านภาพอื่น ๆ ด้วย

บทสรุปและข้อมูลอ้างอิง

  • เมื่อมาตรฐานการเข้าถึงยุคถัดไปถูกนำมาใช้ contrast-color() ก็จะเปลี่ยนอัลกอริทึมเพื่อรองรับการเลือกคอนทราสต์อัตโนมัติที่ดียิ่งขึ้น
  • จนกว่าจะถึงตอนนั้น ฟังก์ชันนี้จะมีประโยชน์เป็นพิเศษเมื่อสีพื้นหลังหลักมีความสว่างหรือความมืดชัดเจน
  • สามารถนำไปใช้ได้กว้างกับองค์ประกอบ UI หลากหลาย ไม่ได้จำกัดเฉพาะข้อความ
  • ควรติดตามอัลกอริทึมด้านการเข้าถึงสมัยใหม่อย่าง APCA (Accessible Perceptual Contrast Algorithm) ต่อไป

เอกสารอ้างอิง

  • สามารถดูตัวอย่างและเกณฑ์การประเมินเพิ่มเติมได้จากเอกสารทางการของ APCA และ APCA Contrast Calculator
  • กำลังมีการหารือเรื่องมาตรฐานของ ฟังก์ชัน contrast-color ของ CSSWG
  • สามารถร่วมแบ่งปันความคิดเห็นและส่งฟีดแบ็กได้ผ่าน WebKit หรือคอมมูนิตี้ที่เกี่ยวข้อง

1 ความคิดเห็น

 
GN⁺ 2025-05-19
ความคิดเห็นจาก Hacker News
  • ฉันกำลังพัฒนาเครื่องมือสำหรับสร้างพาเลตสีเพื่อแก้ปัญหานี้ โดยให้คู่สีมีอัตราส่วนคอนทราสต์ WCAG/ACPA ที่เรียบง่ายและคาดเดาได้ตั้งแต่ขั้นตอนออกแบบ ดูฟีเจอร์เพิ่มเติมบนเดสก์ท็อปได้ที่ https://www.inclusivecolors.com/ วิธีหนึ่งคือสร้างสวอตช์สีเป็นระดับตั้งแต่ 100 (สีอ่อน) ถึง 900 (สีเข้ม) แล้วปรับความสว่างให้เช่น สีระดับ 700 ตัดกับระดับ 100 ได้ชัดเจน และระดับ 800 ตัดกับระดับ 200 ได้ชัดเจน แบบนี้ก็จะรู้ได้ว่าอย่าง red-700 vs gray-100 หรือ green-800 vs yellow-200 ให้คอนทราสต์ที่ชัดเจนแน่นอนโดยไม่ต้องเช็กค่าความสว่าง ในเมนู Contrast ยังสามารถสำรวจได้ด้วยว่าอัลกอริทึม APCA เข้มงวดกว่า WCAG แค่ไหน โดยเฉพาะกับข้อความสีเข้มบนพื้นหลังสว่างด้วย นี่จึงเป็นเหตุผลว่าทำไมไม่ควรใช้ WCAG กับธีมมืด ในเมนู Examples ถ้าดูตัวอย่างพาเลตของ Tailwind และ IBM Carbon จะเห็นว่าแต่ละระดับมีการเปลี่ยน saturation และ hue แบบไม่เชิงเส้น ดังนั้นแม้การเลือกสีที่ตัดกันที่สุดระหว่างดำกับขาวจะทำได้ง่าย แต่พาเลตที่แบรนด์มีความสำคัญนั้นเป็นปัญหาที่ซับซ้อนกว่า ไม่ใช่แค่ปรับความสว่างอย่างเดียวก็พอ

  • มีวิธีทำอะไรคล้ายกันด้วย lch

     --text: lch(from var(--bg) calc((49.44 - l) * infinity) 0 0);
    

    ที่มา: https://til.jakelazaroff.com/css/…

    • LCH ก็ดีมาก แต่ OKLCH ดีกว่าอีก https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl/… บทความนี้เปลี่ยนวิธีคิดของฉันไปเลย เป็นเครื่องมือที่ยอดเยี่ยมมาก น่าแปลกที่เพื่อนนักออกแบบของฉันหลายคนไม่รู้จัก OKLCH วิธีนี้แก้ปัญหาได้เยอะมาก

    • นี่เป็นครั้งแรกที่ฉันเห็นฟังก์ชัน CSS ที่รับพารามิเตอร์ด้วย callback แบบนี้ น่าสนใจมาก อยากรู้ว่ามีนอกจาก lch แล้ว ยังมีฟังก์ชันสไตล์นี้อีกไหม

    • Lea Verou มีบทความดี ๆ เกี่ยวกับวิธีเลี่ยงแบบคล้ายกันนี้อยู่ https://lea.verou.me/blog/2024/contrast-color/

  • บทความนี้สรุปข้อดีข้อเสียของการเลือกคอนทราสต์อัตโนมัติได้ยอดเยี่ยมมาก ถ้าคุณกำลังทำเว็บง่าย ๆ วิธีนี้ให้คอนทราสต์ที่ถูกต้องได้แบบง่ายและตรงไปตรงมา
    แต่ถ้าต้องรองรับ WCAG compliance ในระบบขนาดใหญ่ ควรหลีกเลี่ยง และควรมี semantic formatting token hierarchy ที่แท้จริงแทน semantic token ช่วยให้พัฒนาได้เร็วขึ้น และยังทำให้คอนทราสต์ดูสวยงามกว่าการสลับแค่ดำ/ขาว จุดดีของชั้น semantic token คือทำธีมได้ง่ายมาก ทำให้มี light/dark theme ได้แทบไม่เพิ่มต้นทุนเลย ถ้าสีแบรนด์ติดข้อจำกัดของ WCAG2 ก็สามารถทำธีมแยกสำหรับ WCAG2/APCA เพื่อให้ผ่าน compliance และยังให้คอนทราสต์ที่ดีกว่าได้
    ฉันดูแลส่วน variables/tokens stream ใน Figma และเคยมีส่วนร่วมกับการทำ dark mode ของทั้ง Figma และ Atlassian ถ้ามีคำถามเรื่อง token, theme หรือสีเพื่อการเข้าถึง ถามมาได้เลย

    • อยากรู้ว่า semantic token หมายถึงอะไรอย่างเป็นรูปธรรม โปรเจกต์ใหญ่ที่ฉันทำเคยต้องใช้ CSS-in-JS เพื่อคำนวณสีแบบ relative และสีคอนทราสต์เพราะมีความต้องการแบบนี้ หวังว่าเทคนิคพวกนี้จะถูกนำไปใช้แพร่หลายเร็ว ๆ นี้

    • เนื้อหาช่วงท้าย 2/3 ดูเยิ่นเย้อเกินไปจนออกแนวอวดภูมิ สำหรับเว็บ/แอปบริษัท การพึ่งฟังก์ชันแบบนี้เสี่ยงเพราะผลลัพธ์สีคาดเดาไม่ได้ เช่น WebKit แก้บั๊กแล้วสีที่ได้อาจเปลี่ยนไป

  • ฉันยังรู้สึกว่ายอมรับได้ยากว่าการให้เบราว์เซอร์ตัดสินสีคอนทราสต์จะถูกต้องเสมอหรือคาดเดาได้เสมอ อยากรู้ว่าจะมีเกณฑ์ที่แน่นอนจนทุกเบราว์เซอร์ให้ผลเหมือนกันไหม ฟังก์ชันนี้ดูเหมือนเครื่องมือสนับสนุนทีม UX ในขั้นตอนออกแบบมากกว่า

    • ตามบทความ เขาบอกว่ามาตรฐานระบุวิธีคำนวณไว้อย่างชัดเจน

    • คำว่า 'เลือก' (choose) ฟังดูคลุมเครือ จริง ๆ แล้วมันคืออัลกอริทึมที่คำนวณสีออกมา

    • ถ้าตัดส่วนที่ผิดหรือชวนสับสนออกจากสูตรตัวอย่าง APCA ในลิงก์ มันทำงานได้ถูกต้อง 100% ถ้าอยากให้สอดคล้องกันอย่างสมบูรณ์ เวลาที่สีตัวเลือกทั้งสองฝั่ง (ทั้งสว่างกว่าและมืดกว่า) ใช้ได้พร้อมกัน ก็อาจยึดความสว่าง L* ของพื้นหลังเป็นเกณฑ์ เช่น ถ้า L* ตั้งแต่ 60 ขึ้นไปก็เลือกฝั่งสว่าง แบบนี้จะสม่ำเสมอ 100%

  • ในโปรเจกต์ใหญ่ การคอยระวังไม่ให้ปุ่มกลายเป็นสีที่มองไม่เห็น เช่น พื้นหลังมืดแต่ตัวอักษรดำ นั้นลำบากก็จริง แต่ฉันก็อดคิดไม่ได้ว่าก่อนปล่อยจริงจะตรวจปุ่มทั้งหมดทีละจุดไม่ได้หรือ หรือจะกำหนดกติกาให้ทั้งทีมเลยว่าปุ่มพื้นเข้มห้ามใช้ข้อความสีดำเด็ดขาดก็น่าจะได้ ความแตกต่างระหว่างคอนทราสต์เชิงการรับรู้กับคอนทราสต์เชิงคณิตศาสตร์น่าสนใจมาก ฉันจะเอาไปใช้ใน workflow

    • ในทางปฏิบัติ การตรวจปุ่มทั้งหมดทำได้ แต่ถ้าทำแบบนั้นช่วง regression test ก่อนปล่อยอาจกินเวลาหลายสัปดาห์ หรือหนักสุดเป็นเดือน ๆ ถ้าเป็นโปรเจกต์ใหญ่ ปุ่มอาจมีเป็นพัน และหลายปุ่มจะโผล่เฉพาะในบางชุดตัวเลือกหรือบาง workflow เท่านั้น

    • ถ้าอ้างอิง APCA ก็จะคำนวณคอนทราสต์โดยอิงการรับรู้ได้

  • ฉันเคยทำสไตล์ปุ่มสมัยที่ system colors กำลังนิยม ตอนนั้นมันดูดีมาก แต่ไม่รู้ว่าคอนทราสต์จะเป็นอย่างไร เลยมีคนช่วยคำนวณด้วย JavaScript ผ่าน getComputedStyle ถ้าคอนทราสต์ไม่ผ่านก็ใช้สีตัวเลือกที่สอง หรือถ้าเลี่ยงไม่ได้ก็เพิ่ม text-shadow เพื่อเสริมความต่างรอบตัวอักษร ฉันจำวิธีคำนวณไม่ได้แล้ว แต่รู้สึกว่าแค่เอาค่า RGB ทั้ง 3 มาหาค่าเฉลี่ยแล้วเทียบก็น่าจะพอได้ อย่างน้อยกับสีน้ำเงินค่าเฉลี่ยจะต่ำ ก็อาจให้ตัวอักษรสีขาวมีความสำคัญมากกว่า

  • อย่างน้อยก็น่าจะมีคำแนะนำสีที่เหมาะกับ pseudo-class อย่าง active, focus, hover, link, visited แยกตาม light/dark theme ให้ด้วย ส่วน material UI ไปไกลกว่านั้นโดยมีสถานะ disabled, before, after เพิ่มอีก

  • เมื่อก่อนฉันเคยทำวิดีโอสอนเรื่องการเลือกข้อความสีดำ/ขาวตามสีพื้นหลัง วิธีของฉันเรียบง่ายมาก คือแปลงสีให้เป็น grayscale แล้วค่อยตัดสินว่าจะใช้ดำหรือขาว เป็นงานที่สนุกดี แต่ทักษะทำวิดีโอยังไม่ค่อยดี
    https://youtu.be/tUJvE4xfTgo?si=vFlegFA_7lzijfSR (ระวังว่าเป็นภาษาโปรตุเกส)

    • น่าสนใจตรงที่ในคอมเมนต์อื่นมีคนแนะนำสูตร color space ที่ทำสิ่งนั้นตรง ๆ เลย
      https://news.ycombinator.com/item?id=44015990
      วิดีโอก็ดูโอเคนะ โค้ดก็ดูดี แต่ฉันไม่รู้ภาษาโปรตุเกสเลยประเมินเนื้อหาไม่ได้
  • ถ้าคุณเป็นคนเลือกชุดสีทั้งหมดเอง ฉันสงสัยว่าทำไมการให้ระบบช่วยเลือกสีข้อความบนปุ่มให้ตัดกัน ถึงจะง่ายกว่าการเลือกมันเองตั้งแต่ต้น ฟีเจอร์นี้ดูจะมีประโยชน์เฉพาะในสถานการณ์สุดโต่งมาก ๆ ที่พื้นหลังถูกเลือกแบบสะเปะสะปะตามใจ แต่กลับเลือกสี foreground (สีข้อความบนปุ่ม) เองไม่ได้ ทั้งที่ปัญหาจริงคือกรณีอย่างข้อความบนภาพหรือบนพื้นหลังหลากหลายรูปแบบที่ต้องอ่านได้เสมอ ซึ่งฟีเจอร์นี้ช่วยอะไรไม่ได้เลย ดังนั้นมันจึงดูเป็นฟีเจอร์ที่มีประโยชน์ได้แค่ในกรณีจำกัดมาก แถมยังถึงขั้นสร้างคำกริยาใหม่ขึ้นมา ทั้งที่ความสามารถก็แค่เลือกระหว่างขาวกับดำ และยังใช้อัลกอริทึมคอนทราสต์ที่แย่ที่สุดอย่าง WCAG 2 อีก สุดยอดจริง ๆ

    • น่าเสียดายที่มองข้ามเครื่องมือเพียงเพราะยังไม่เคยเจอสถานการณ์ที่ต้องใช้ มีเว็บจำนวนมากที่เปิดให้ผู้ใช้เลือกสีเองตามใจ หรือดึงสีมาจากสิ่งที่อัปโหลด เว็บที่ใส่ใจ accessibility จึงต้องมีการคำนวณคอนทราสต์อัตโนมัติสำหรับกรณีแบบนี้ การมีฟีเจอร์ใน CSS แบบ built-in จะช่วยให้รองรับ accessibility พื้นฐานได้ง่ายขึ้น แน่นอนว่ามันไม่ได้จำกัดนักพัฒนาที่อยากสร้างประสบการณ์ที่ซับซ้อนกว่านี้เลย ถ้าปรับแต่งได้มากขึ้นแบบแพ็กเกจ contrast-color บน npm ก็คงดี แต่ในบล็อกก็อธิบายไว้ว่าการเลือกแค่ขาว/ดำเป็นเพียงก้าวแรก และมีแผนจะพัฒนาต่อในอนาคต
      ตัวอย่าง: https://coolors.co/8fbfe0-7c77b9-1d8a99-0bc9cd-14fff7

    • สำหรับข้อวิจารณ์ว่าอัลกอริทึมเลือกคอนทราสต์ไม่ดี เขาระบุชัดว่าตอนนี้ใช้ตามอัลกอริทึม WCAG 2 และเมื่อ WCAG 3 กลายเป็นมาตรฐาน ก็สามารถเปลี่ยนไปใช้อัลกอริทึมนั้นได้ไม่ยาก

  • สงสัยว่ามีทางเลือกแบบ build-time สำหรับฟีเจอร์ลักษณะนี้ที่ใช้กับ SASS, Tailwind ฯลฯ ได้ไหม กว่าฟีเจอร์นี้จะถูกใช้อย่างแพร่หลายคงต้องใช้เวลา และก็ยังกังวลด้วยว่าแต่ละแพลตฟอร์มจะทำออกมาเหมือนกันหรือไม่