রঙ কনট্রাস্ট চেকার
ফোরগ্রাউন্ড ও ব্যাকগ্রাউন্ড রঙের মধ্যে 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
রঙ কনট্রাস্ট চেকার কী?
রঙ কনট্রাস্ট চেকার একটি ফোরগ্রাউন্ড রঙ (সাধারণত টেক্সট) এবং একটি ব্যাকগ্রাউন্ড রঙের মধ্যে উজ্জ্বলতার পার্থক্য পরিমাপ করে এবং ফলাফল একটি অনুপাত হিসেবে প্রকাশ করে। 1:1 অনুপাত মানে রঙ দুটি অভিন্ন; 21:1 হলো সর্বোচ্চ, যা সাদার উপর কালো বা বিপরীতটিকে নির্দেশ করে। W3C প্রকাশিত Web Content Accessibility Guidelines (WCAG) টেক্সটের জন্য ন্যূনতম কনট্রাস্ট রেশিও নির্ধারণ করে যাতে দৃষ্টি প্রতিবন্ধী বা বর্ণান্ধ ব্যক্তিরা পড়তে পারেন।
কনট্রাস্ট রেশিওর সূত্রটি WCAG 2.x থেকে নেওয়া এবং এটি আপেক্ষিক উজ্জ্বলতার উপর নির্ভর করে — মানুষের চোখে একটি রঙ কতটা উজ্জ্বল দেখায় তার পরিমাপ। আপেক্ষিক উজ্জ্বলতা গণনা করা হয় প্রতিটি sRGB চ্যানেলকে রৈখিক করে (গামা সরিয়ে) এবং ITU-R BT.709 সহগ দ্বারা চ্যানেলগুলোকে ওজন দিয়ে: লালের জন্য 0.2126, সবুজের জন্য 0.7152 এবং নীলের জন্য 0.0722। সবুজ সবচেয়ে বেশি অবদান রাখে কারণ মানুষের চোখ সবুজ আলোর প্রতি সবচেয়ে সংবেদনশীল। তারপর অনুপাতটি হলো (L1 + 0.05) / (L2 + 0.05), যেখানে L1 হলো হালকা রঙের উজ্জ্বলতা।
WCAG দুটি সম্মতি স্তর নির্ধারণ করে। Level AA সাধারণ আকারের টেক্সটের জন্য কমপক্ষে 4.5:1 এবং বড় টেক্সটের জন্য 3:1 কনট্রাস্ট রেশিও প্রয়োজন (18px বা তার বেশি, অথবা 14px বোল্ড)। Level AAA এই মানদণ্ড যথাক্রমে 7:1 এবং 4.5:1-এ উন্নীত করে। WCAG 2.1 Success Criterion 1.4.11-ও যুক্ত করেছে, যা বর্ডার, আইকন এবং ফোকাস ইন্ডিকেটরের মতো নন-টেক্সট UI উপাদানের জন্য 3:1 অনুপাত প্রয়োজন।
কেন এই কনট্রাস্ট চেকার ব্যবহার করবেন?
চোখ দিয়ে কনট্রাস্ট যাচাই করা অবিশ্বস্ত। আপনার ক্যালিব্রেটেড ডিসপ্লেতে যে রঙগুলো আলাদা মনে হয়, সেগুলো নিম্নমানের ল্যাপটপের স্ক্রিনে, সরাসরি সূর্যালোকে, বা ডিউটেরানোপিয়া আক্রান্ত কারো কাছে একসাথে মিশে যেতে পারে। একটি সংখ্যাগত অনুপাত অনুমানের প্রয়োজন দূর করে এবং WCAG মানদণ্ডের বিপরীতে পাস/ফেল ফলাফল দেয়।
কনট্রাস্ট চেকারের ব্যবহারের ক্ষেত্র
WCAG কনট্রাস্ট রেশিওর প্রয়োজনীয়তা
নিচের টেবিলে বিভিন্ন কন্টেন্ট টাইপ এবং সম্মতি স্তরের জন্য WCAG 2.1 প্রয়োজনীয় ন্যূনতম কনট্রাস্ট রেশিও সংক্ষিপ্ত করা হয়েছে। বড় টেক্সট হলো স্বাভাবিক ওজনে 18px (24 CSS পিক্সেল) বা তার বেশি, অথবা বোল্ড ওজনে 14px (18.66 CSS পিক্সেল) বা তার বেশি।
| স্তর | ন্যূনতম অনুপাত | প্রযোজ্য | মন্তব্য |
|---|---|---|---|
| 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;
}