เมื่อสร้างคอมโพเนนต์ UI ที่นำมาใช้ซ้ำได้ (เช่น ป้ายหรือปุ่ม) หรือรองรับธีมแบบไดนามิก การตรวจสอบว่าข้อความอ่านได้เมื่อเทียบกับสีพื้นหลังที่คาดเดาไม่ได้อาจเป็นเรื่องที่ท้าทาย ฟังก์ชัน CSS contrast-color() จะเปลี่ยนเป็น black หรือ white เพื่อเพิ่มอัตราส่วนคอนทราสต์ให้สูงสุดเมื่อเทียบกับสีพื้นหลังที่ระบุ
กำหนดสีข้อความที่เหมาะสมที่สุด
เมื่อองค์ประกอบมีสีพื้นหลังที่แทรกแบบไดนามิกหรือเป็นตัวแปร คุณสามารถใช้เบราว์เซอร์เพื่อคำนวณสีข้อความที่ปลอดภัยที่สุดได้
บังคับ: ตั้งค่าพร็อพเพอร์ตี้ color โดยใช้ฟังก์ชัน contrast-color() โดยส่งสีพื้นหลัง (หรือคุณสมบัติที่กำหนดเอง) เป็นอาร์กิวเมนต์
.badge {
/* Define the background color as a custom property */
--badge-bg: #e02424;
background-color: var(--badge-bg);
/* MANDATORY: Dynamic contrasting color */
color: contrast-color(var(--badge-bg));
}
ไม่ควร: ใช้ contrast-color() สำหรับ background-color โดยออกแบบมาโดยเฉพาะสำหรับสีพื้นหน้า (เช่น ข้อความหรือเส้นขอบ) เพื่อให้ตัดกับสีพื้นหลังที่กำหนด
ผสานรวมกับการกำหนดธีม
เนื่องจาก contrast-color() ยอมรับค่า <color> ที่ถูกต้องทั้งหมด รวมถึงคุณสมบัติที่กำหนดเองของ CSS จึงมีประสิทธิภาพอย่างยิ่งในระบบการออกแบบ การรวมธีมพื้นหลังเป็นตัวแปรจะช่วยให้มั่นใจได้ว่าเนื้อหาที่อยู่เบื้องหน้าจะอัปเดตคอนทราสต์โดยอัตโนมัติเมื่อใดก็ตามที่ธีมเปลี่ยนไป แม้จะเป็นสีที่ผู้ใช้ระบุไว้ก็ตาม
สิ่งที่ควรทำ: อ้างอิงตัวแปรพื้นหลังที่ใช้ร่วมกันภายใน contrast-color() เพื่อรับประกันการซิงค์ข้อมูลในแอปพลิเคชัน
.theme-card {
background-color: var(--theme-surface-color);
color: contrast-color(var(--theme-surface-color));
}
.theme-container[data-theme="light"] {
--theme-surface-color: #f4f4f4;
}
.theme-container[data-theme="dark"] {
--theme-surface-color: #1a1a1a;
}
.theme-container[data-theme="custom"] {
--theme-surface-color: var(--user-custom-theme);
}
ไม่ควร: ฮาร์ดโค้ดสีข้อความแยกต่างหากสำหรับสถานะการโต้ตอบแต่ละสถานะเมื่อพื้นหลังเป็นแบบไดนามิก การดำเนินการดังกล่าวจะทำให้เกิดความไม่ตรงกันซึ่ง contrast-color() มีไว้เพื่อป้องกัน
กลยุทธ์สำรอง
หากต้องการรองรับเบราว์เซอร์ที่ไม่มี contrast-color() คุณต้องระบุทางเลือกสำรอง หากทราบสีพื้นหลังและเป็นสีคงที่ ให้ใช้สีที่ตัดกันซึ่งฮาร์ดโค้ดไว้ สำหรับพื้นหลังแบบไดนามิกที่ไม่ทราบสี ให้เลือกกลยุทธ์จากตารางด้านล่างตามข้อกำหนด UI และเป้าหมายการรองรับเบราว์เซอร์
| กลยุทธ์ | เหมาะสำหรับ... | ข้อควรพิจารณา |
|---|---|---|
| ไวยากรณ์สีสัมพัทธ์ | การคำนวณคอนทราสต์คุณภาพสูงแบบอัตโนมัติที่ใช้ CSS เท่านั้น | วิดีโอสำรองคุณภาพสูงสุดที่ใช้ CSS เท่านั้น |
| เงาข้อความ | เพิ่มความสามารถในการอ่านได้อย่างรวดเร็วบนพื้นหลังทุกประเภท | อาจดู "สกปรก" หรือ "เรืองแสง" และอาจไม่เหมาะกับดีไซน์บางประเภท |
| เส้นขอบข้อความ | คงความหนาของแบบอักษรไว้พร้อมกับตรวจสอบว่าขอบมีคอนทราสต์ | ใช้ paint-order เพื่อหลีกเลี่ยงการทำให้รูปแบบตัวอักษรบางลง (หากมี) |
| การวางซ้อนแบบโปร่งแสง | ตรวจสอบว่ามีพื้นที่คอนทราสต์ขั้นต่ำอยู่ด้านหลังข้อความ | เปลี่ยนรูปลักษณ์ของสีพื้นหลังใต้ข้อความ โดยต้องมีองค์ประกอบของข้อความแยกต่างหาก |
| ฟิลเตอร์ SVG | คอนทราสต์แบบรีแอ็กทีฟที่อัปเดตเมื่อพื้นหลังเปลี่ยนไป | ต้องใช้องค์ประกอบของข้อความแยกต่างหาก ซึ่งเป็นการใช้งานที่ซับซ้อน |
แนะนำ: ไวยากรณ์สีสัมพัทธ์ (RCS)
สำหรับเบราว์เซอร์ที่รองรับ RCS จะเป็นตัวเลือกสำรองอัตโนมัติที่มีประสิทธิภาพที่สุดสำหรับสีแบบไดนามิก
@supports (color: oklch(from red l c h)) {
.badge {
/* Highest threshold that passes WCAG. Higher values may be more legible. */
--threshold: 0.623;
--l: max(0, sign(var(--threshold) - l));
color: oklch(from var(--badge-bg) var(--l) 0 h);
}
}
@supports (color: contrast-color(red)) {
.badge {
color: contrast-color(var(--badge-bg));
}
}
CSS สำรองทางเลือก
สิ่งที่ควรทำ: เลือกทางเลือกสำรองที่ตรงกับข้อจำกัดด้านการออกแบบมากที่สุดหาก RCS ไม่เพียงพอหรือไม่รองรับ
ตัวเลือกที่ 1: เส้นขอบข้อความ
.badge--stroke {
-webkit-text-stroke: 4px black;
}
ตัวเลือกที่ 2: เส้นขอบข้อความที่มี paint-order เพื่อคงรูปแบบตัวอักษรไว้
.badge--stroke {
-webkit-text-stroke: 4px black;
paint-order: stroke fill;
}
ตัวเลือกที่ 3: ภาพซ้อนทับพื้นหลังแบบโปร่งแสง
.badge--overlay {
position: relative;
color: #fff;
overflow: hidden;
}
.badge--overlay::before {
content: "";
position: absolute;
inset: 0;
background-color: rgb(0 0 0 / 0.4);
z-index: 0;
}
.badge--overlay span {
position: relative;
z-index: 1;
}
ตัวเลือกที่ 4: เงาข้อความ
.badge--shadow {
text-shadow: 0 1px 3px rgb(0 0 0 / 0.8);
}
ตัวเลือกที่ 5: ตัวกรอง SVG
โหลดคำจำกัดความของตัวกรอง SVG นี้ คุณต้องเพิ่มลงในเอกสาร HTML โดยตรงหากต้องการรองรับ Safari เวอร์ชันที่ได้รับผลกระทบจากข้อบกพร่องของ WebKit นี้ ซึ่งจะป้องกันการอ้างอิง URL ภายนอกและ URL ข้อมูลสำหรับตัวกรอง หรือควรโหลดจากไฟล์ภายนอก ไม่ว่าจะเป็นไฟล์ SVG หรือแทรกใน CSS
<!-- Technique from https://miunau.com/posts/dynamic-text-contrast-in-css/ --> <svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="0" style="display: none;"> <defs> <filter id="contrast-filter" color-interpolation-filters="sRGB"> <feColorMatrix type="matrix" values="0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0.2126 0.7152 0.0722 0 0 0 0 0 1 0"/> <feMorphology operator="dilate" radius="2"/> <feComponentTransfer> <feFuncR type="linear" slope="-255" intercept="128"/> <feFuncG type="linear" slope="-255" intercept="128"/> <feFuncB type="linear" slope="-255" intercept="128"/> </feComponentTransfer> <feComposite operator="in" in2="SourceGraphic"/> </filter> </defs> </svg>ตัดข้อความขึ้นบรรทัดใหม่ใน
<span><div class="badge--svg"> <span>Badge content</span> </div>ใช้ตัวกรองกับ
<span>
.badge--svg span{
color: var(--badge-bg);
filter: url(#contrast-filter);
}