-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmobile-color-contrast.mdc
More file actions
107 lines (79 loc) · 3.18 KB
/
mobile-color-contrast.mdc
File metadata and controls
107 lines (79 loc) · 3.18 KB
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
98
99
100
101
102
103
104
105
106
107
---
description: Flag insufficient color contrast, missing dark mode support, and non-semantic color usage
globs: ["*.ts", "*.tsx", "*.dart"]
alwaysApply: false
standards-version: 1.7.0
---
# Color Contrast & Theme Compliance
## Purpose
Detect color usage patterns that cause accessibility issues or break in dark mode. WCAG 2.1 AA requires 4.5:1 contrast for normal text and 3:1 for large text (≥18pt or 14pt bold).
## Flagged Patterns
### 1. Hardcoded Colors Without Theme Tokens
```tsx
// ❌ Raw hex values - break in dark mode
<View style={{ backgroundColor: "#FFFFFF" }}>
<Text style={{ color: "#333333" }}>Hello</Text>
</View>
// ✅ Use theme tokens
const { colors } = useTheme();
<View style={{ backgroundColor: colors.surface }}>
<Text style={{ color: colors.text }}>Hello</Text>
</View>
```
```dart
// ❌ Hardcoded colors
Container(color: Color(0xFFFFFFFF))
// ✅ Theme-aware colors
Container(color: Theme.of(context).colorScheme.surface)
```
### 2. Known Low-Contrast Pairs
Flag when both background and foreground are specified with insufficient contrast:
- Light gray text (`#999`, `#AAA`, `#BBB`, `#CCC`) on white (`#FFF`, `#FAFAFA`)
- Dark gray text (`#333`, `#444`) on dark backgrounds (`#1C1C1E`, `#000`)
- Red (`#FF0000`) or green (`#00FF00`) on any background below 3:1
- Placeholder text colors below 4.5:1 against their input background
### 3. Missing Dark Mode Handling (React Native)
Flag when `color` or `backgroundColor` is set without either:
- Using `useColorScheme()` or `useTheme()`
- Using a theme token / design token reference
- Being inside a `Platform.select()` or conditional on color scheme
```tsx
// ❌ No dark mode awareness
const styles = StyleSheet.create({
container: { backgroundColor: "#FFFFFF" },
text: { color: "#000000" },
});
// ✅ Theme-aware
const { colors } = useTheme();
const styles = {
container: { backgroundColor: colors.background },
text: { color: colors.text },
};
```
### 4. Missing Dark Mode Handling (Flutter)
Flag when `Color(0x...)` or `Colors.white`/`Colors.black` is used outside of `ThemeData` without `Theme.of(context)`:
```dart
// ❌ Hardcoded - invisible in dark mode
Text('Hello', style: TextStyle(color: Colors.black))
// ✅ Theme-aware
Text('Hello', style: TextStyle(color: Theme.of(context).colorScheme.onSurface))
```
### 5. Non-Semantic Color Names
Flag variables or tokens using visual color names instead of semantic names:
```tsx
// ❌ Visual name - meaning unclear, hard to maintain across themes
const blueColor = "#0A84FF";
const darkGray = "#333333";
// ✅ Semantic name - intent is clear
const primaryColor = "#0A84FF";
const textSecondary = "#333333";
```
## Exceptions
- Colors inside `ThemeData`, `ColorScheme`, or token definition files are expected to be raw values
- Decorative gradients and illustration colors that don't carry meaning
- Third-party component props that require specific color values
- Debug/development-only styling
## Resources
- [WCAG 2.1 Contrast (Minimum)](https://www.w3.org/WAI/WCAG21/Understanding/contrast-minimum.html)
- [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/)
- [Material Design Color System](https://m3.material.io/styles/color/system/overview)