بررسیکننده کنتراست رنگ
بررسی نسبت کنتراست WCAG AA و AAA بین رنگ پیشزمینه و پسزمینه
رنگ پیشزمینه (متن)
رنگ پسزمینه
نمونه متن بزرگ (18px ضخیم)
نمونه متن عادی — متن اصلی شما در برابر رنگ پسزمینهای که انتخاب کردهاید اینگونه نمایش داده میشود.
نسبت کنتراست
14.63:1
انطباق با WCAG
قبول
AA عادی
قبول
AAA عادی
قبول
AA بزرگ
قبول
AAA بزرگ
WCAG AA — متن عادی: 4.5:1, متن بزرگ (18px به بالا یا 14px ضخیم): 3:1
WCAG AAA — متن عادی: 7:1, متن بزرگ (18px به بالا یا 14px ضخیم): 4.5:1
بررسی کنتراست رنگ چیست؟
بررسی کنتراست رنگ، اختلاف روشنایی بین رنگ پیشزمینه (معمولاً متن) و رنگ پسزمینه را اندازهگیری میکند و نتیجه را به صورت یک نسبت بیان میکند. نسبت ۱:۱ به معنای یکسان بودن دو رنگ است؛ ۲۱:۱ بیشترین مقدار ممکن است که نمایانگر سیاه روی سفید یا برعکس است. دستورالعملهای دسترسیپذیری محتوای وب (WCAG) که توسط W3C منتشر شده، حداقل نسبتهای کنتراستی را تعریف میکند که متن باید داشته باشد تا افراد دارای بینایی ضعیف یا ناتوانی در تشخیص رنگ بتوانند آن را بخوانند.
فرمول نسبت کنتراست از WCAG 2.x گرفته شده و بر روشنایی نسبی متکی است؛ معیاری که نشان میدهد یک رنگ در چشم انسان چقدر روشن به نظر میرسد. روشنایی نسبی با خطیسازی هر کانال sRGB (تصحیح گاما) و وزندهی کانالها بر اساس ضرایب ITU-R BT.709 محاسبه میشود: ۰.۲۱۲۶ برای قرمز، ۰.۷۱۵۲ برای سبز، و ۰.۰۷۲۲ برای آبی. سبز بیشترین سهم را دارد زیرا چشم انسان به نور سبز حساسترین است. نسبت به صورت (L1 + 0.05) / (L2 + 0.05) محاسبه میشود که L1 روشنایی رنگ روشنتر است.
WCAG دو سطح انطباق تعریف میکند. سطح AA حداقل نسبت کنتراست ۴.۵:۱ برای متن با اندازه عادی و ۳:۱ برای متن بزرگ (18px به بالا، یا 14px ضخیم) را الزامی میداند. سطح AAA این آستانه را به ترتیب به ۷:۱ و ۴.۵:۱ افزایش میدهد. WCAG 2.1 همچنین معیار موفقیت ۱.۴.۱۱ را معرفی کرد که نسبت ۳:۱ را برای اجزای رابط کاربری غیرمتنی مانند حاشیهها، آیکونها و نشانگرهای فوکوس الزامی میداند.
چرا از این بررسیکننده کنتراست استفاده کنیم؟
بررسی کنتراست با چشم غیرقابل اعتماد است. رنگهایی که روی نمایشگر کالیبرهشده شما متمایز به نظر میرسند، ممکن است روی یک لپتاپ ارزانقیمت، زیر نور مستقیم آفتاب، یا برای فردی با کوررنگی دوتانوپی در هم ادغام شوند. یک عدد دقیق حدسوگمان را از بین میبرد و نتیجه قبول یا رد در برابر استاندارد WCAG را مشخص میکند.
موارد استفاده از بررسیکننده کنتراست
الزامات نسبت کنتراست WCAG
جدول زیر حداقل نسبتهای کنتراست مورد نیاز WCAG 2.1 برای انواع مختلف محتوا و سطوح انطباق را خلاصه میکند. متن بزرگ به صورت 18px (24 CSS pixels) یا بالاتر با وزن عادی، یا 14px (18.66 CSS pixels) یا بالاتر با وزن ضخیم تعریف میشود.
| سطح | حداقل نسبت | کاربرد | توضیح |
|---|---|---|---|
| AA Normal text | 4.5 : 1 | Body text, paragraphs, labels | Minimum for most UI text |
| AA Large text | 3.0 : 1 | Text >= 18px, or >= 14px bold | Minimum for headings |
| AA UI components | 3.0 : 1 | Borders, icons, focus indicators | Non-text contrast (WCAG 1.4.11) |
| AAA Normal text | 7.0 : 1 | Body text at highest standard | Enhanced readability |
| AAA Large text | 4.5 : 1 | Large text at highest standard | Enhanced for headings |
روشنایی، AA و AAA — توضیح کامل
محاسبه نسبت کنتراست سه مرحله دارد: محاسبه روشنایی برای هر رنگ، استخراج نسبت، و مقایسه آن با آستانههای WCAG.
نمونههای کد
نسبتهای کنتراست WCAG را به صورت برنامهنویسی محاسبه کنید. هر مثال فرمول روشنایی نسبی از WCAG 2.x و محاسبه نسبت کنتراست را پیادهسازی میکند. جفتهای سیاه روی سفید و نیلی روی سفید برای مقایسه آزمایش شدهاند.
// Calculate relative luminance per WCAG 2.x (sRGB)
function luminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(c => {
c /= 255
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4)
})
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs
}
// Contrast ratio between two RGB colors
function contrastRatio(fg, bg) {
const l1 = luminance(...fg)
const l2 = luminance(...bg)
const lighter = Math.max(l1, l2)
const darker = Math.min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
}
contrastRatio([0, 0, 0], [255, 255, 255]) // -> 21.0
contrastRatio([99, 102, 241], [255, 255, 255]) // -> 3.95
contrastRatio([29, 78, 216], [255, 255, 255]) // -> 6.06 (AA pass)def luminance(r: int, g: int, b: int) -> float:
"""Relative luminance per WCAG 2.x, ITU-R BT.709 coefficients."""
channels = []
for c in (r, g, b):
c /= 255
channels.append(c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4)
return 0.2126 * channels[0] + 0.7152 * channels[1] + 0.0722 * channels[2]
def contrast_ratio(fg: tuple, bg: tuple) -> float:
l1 = luminance(*fg)
l2 = luminance(*bg)
lighter, darker = max(l1, l2), min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
print(f"{contrast_ratio((0, 0, 0), (255, 255, 255)):.2f}") # -> 21.00
print(f"{contrast_ratio((99, 102, 241), (255, 255, 255)):.2f}") # -> 3.95
# Check WCAG AA for normal text
ratio = contrast_ratio((29, 78, 216), (255, 255, 255))
print(f"{ratio:.2f} — {'AA pass' if ratio >= 4.5 else 'AA fail'}") # -> 6.06 — AA passpackage main
import (
"fmt"
"math"
)
func linearize(c float64) float64 {
c /= 255
if c <= 0.04045 {
return c / 12.92
}
return math.Pow((c+0.055)/1.055, 2.4)
}
func luminance(r, g, b int) float64 {
return 0.2126*linearize(float64(r)) +
0.7152*linearize(float64(g)) +
0.0722*linearize(float64(b))
}
func contrastRatio(fgR, fgG, fgB, bgR, bgG, bgB int) float64 {
l1 := luminance(fgR, fgG, fgB)
l2 := luminance(bgR, bgG, bgB)
lighter := math.Max(l1, l2)
darker := math.Min(l1, l2)
return (lighter + 0.05) / (darker + 0.05)
}
func main() {
ratio := contrastRatio(0, 0, 0, 255, 255, 255)
fmt.Printf("%.2f\n", ratio) // -> 21.00
ratio = contrastRatio(29, 78, 216, 255, 255, 255)
fmt.Printf("%.2f\n", ratio) // -> 6.06 (AA pass for normal text)
}/* WCAG-safe color pairs — tested contrast ratios */
/* 12.63:1 — passes AAA normal text */
.high-contrast {
color: #1e293b; /* slate-800 */
background: #f8fafc; /* slate-50 */
}
/* 7.07:1 — passes AAA normal text */
.dark-theme-text {
color: #e2e8f0; /* slate-200 */
background: #0f172a; /* slate-900 */
}
/* 4.57:1 — passes AA normal, fails AAA */
.accent-on-white {
color: #1d4ed8; /* blue-700 */
background: #ffffff;
}
/* 2.14:1 — fails AA for text, but passes 3:1 for large text */
.muted-heading {
color: #94a3b8; /* slate-400 */
background: #ffffff;
}