1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
| /**
* 颜色对比度计算
* WCAG AA级别要求:
* - 普通文本:至少4.5:1
* - 大文本(18pt+或14pt+粗体):至少3:1
* - UI组件:至少3:1
*/
class ColorContrast {
/**
* 计算相对亮度
*/
static getLuminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(c => {
c = c / 255;
return c <= 0.03928
? c / 12.92
: Math.pow((c + 0.055) / 1.055, 2.4);
});
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
}
/**
* 计算对比度
*/
static getContrastRatio(color1, color2) {
const lum1 = this.getLuminance(...color1);
const lum2 = this.getLuminance(...color2);
const lighter = Math.max(lum1, lum2);
const darker = Math.min(lum1, lum2);
return (lighter + 0.05) / (darker + 0.05);
}
/**
* 检查对比度是否符合WCAG标准
*/
static checkContrast(foreground, background, isLargeText = false) {
const ratio = this.getContrastRatio(foreground, background);
const requirements = isLargeText
? { AA: 3.0, AAA: 4.5 }
: { AA: 4.5, AAA: 7.0 };
return {
ratio: ratio.toFixed(2),
AA: ratio >= requirements.AA,
AAA: ratio >= requirements.AAA,
pass: ratio >= requirements.AA
};
}
/**
* 解析颜色为RGB
*/
static parseColor(color) {
// 十六进制颜色
if (color.startsWith('#')) {
const hex = color.slice(1);
if (hex.length === 3) {
return [
parseInt(hex[0] + hex[0], 16),
parseInt(hex[1] + hex[1], 16),
parseInt(hex[2] + hex[2], 16)
];
} else if (hex.length === 6) {
return [
parseInt(hex.slice(0, 2), 16),
parseInt(hex.slice(2, 4), 16),
parseInt(hex.slice(4, 6), 16)
];
}
}
// rgb()格式
const rgbMatch = color.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
if (rgbMatch) {
return [
parseInt(rgbMatch[1]),
parseInt(rgbMatch[2]),
parseInt(rgbMatch[3])
];
}
throw new Error(`无法解析颜色: ${color}`);
}
}
// 使用示例
const foreground = ColorContrast.parseColor('#3b82f6');
const background = ColorContrast.parseColor('#ffffff');
const result = ColorContrast.checkContrast(foreground, background);
console.log(result);
// { ratio: "5.12", AA: true, AAA: false, pass: true }
|