-
Notifications
You must be signed in to change notification settings - Fork 0
high contrast theme
ArtisanPack UI Livewire Components includes a comprehensive high-contrast theme system designed for accessibility. This system provides WCAG AAA compliant themes, automatic system preference detection, reduced motion support, enhanced focus indicators, and larger text options.
The high-contrast theme system is designed to meet the needs of users who require:
- Maximum contrast ratios for better readability
- Enhanced focus indicators for keyboard navigation
- Reduced motion for vestibular disorders
- Larger text options for visual impairments
- System preference detection via CSS media queries
- WCAG AAA Compliance: High-contrast presets achieve 7:1 contrast ratios for normal text
- WCAG AA Compliance: Enhanced contrast presets achieve 4.5:1 contrast ratios
-
Automatic Detection: Respects
prefers-contrastandprefers-reduced-motionmedia queries - Independent of Light/Dark Mode: Works alongside your existing light/dark theme toggle
- Screen Reader Friendly: Semantic tokens and proper focus management
To generate only the high-contrast CSS file:
php artisan artisanpack:generate-theme --high-contrast-onlyThis creates a CSS file with all accessibility features at the configured output path (default: resources/css/artisanpack-high-contrast.css).
Apply a specific preset as the default:
php artisan artisanpack:generate-theme --high-contrast-only --accessibility-preset=high-contrast-lightWhen generating your full theme, high-contrast CSS is included by default:
php artisan artisanpack:generate-theme --primary=blue --secondary=slate --accent=amberThis generates both your color theme and the high-contrast accessibility CSS.
If you don't need the high-contrast file:
php artisan artisanpack:generate-theme --primary=blue --no-high-contrast| Preset | Description | WCAG Level | Mode |
|---|---|---|---|
high-contrast-light |
Maximum contrast on light backgrounds | AAA | Light |
high-contrast-dark |
Maximum contrast on dark backgrounds | AAA | Dark |
enhanced-contrast-light |
Improved contrast on light backgrounds | AA | Light |
enhanced-contrast-dark |
Improved contrast on dark backgrounds | AA | Dark |
- WCAG AAA: 7:1 contrast ratio for normal text, 4.5:1 for large text
- WCAG AA: 4.5:1 contrast ratio for normal text, 3:1 for large text
Import the high-contrast CSS file in your main CSS:
/* resources/css/app.css */
@import './artisanpack-high-contrast.css';
@import "tailwindcss";
/* Your other styles */Add the preset class to your HTML element:
<html class="high-contrast-light">
<body>
<!-- All content inherits high-contrast tokens -->
</body>
</html>Apply presets to specific containers:
<div class="high-contrast-dark p-6 rounded-lg">
<h2>High Contrast Section</h2>
<p>This section uses high-contrast dark mode.</p>
</div>Toggle presets with data attributes for JavaScript-based switching:
<html data-accessibility="high-contrast-light">
<!-- Content -->
</html>// Toggle accessibility preset
function setAccessibilityPreset(preset) {
document.documentElement.dataset.accessibility = preset;
localStorage.setItem('accessibility-preset', preset);
}
// Load saved preference
const savedPreset = localStorage.getItem('accessibility-preset');
if (savedPreset) {
setAccessibilityPreset(savedPreset);
}The high-contrast theme provides the following CSS custom properties:
/* Base colors */
--hc-background: /* Background color */
--hc-foreground: /* Text color */
--hc-foreground-muted: /* Secondary text color */
/* Primary colors */
--hc-primary: /* Primary action color */
--hc-primary-foreground: /* Text on primary */
--hc-primary-hover: /* Primary hover state */
--hc-primary-active: /* Primary active state */
/* Secondary colors */
--hc-secondary: /* Secondary action color */
--hc-secondary-foreground: /* Text on secondary */
/* Accent colors */
--hc-accent: /* Accent color */
--hc-accent-foreground: /* Text on accent */
/* Semantic colors */
--hc-success: /* Success state */
--hc-warning: /* Warning state */
--hc-error: /* Error state */
--hc-info: /* Info state */
/* Border colors */
--hc-border: /* Default border */
--hc-border-muted: /* Subtle border */
--hc-border-focus: /* Focus border */
/* Surface colors */
--hc-surface: /* Card/panel background */
--hc-surface-elevated: /* Elevated surfaces */
--hc-surface-sunken: /* Sunken surfaces */--hc-focus-ring-color: /* Focus ring color */
--hc-focus-ring-width: /* Focus ring width (default: 3px for AAA, 2px for AA) */
--hc-focus-ring-offset: /* Focus ring offset */
--hc-focus-ring-style: /* Focus ring style (solid) */--hc-text-scale: /* Base text scale multiplier */
--hc-text-base: /* Base text size */
--hc-text-sm: /* Small text size */
--hc-text-lg: /* Large text size */
--hc-text-xl: /* Extra large text size */
--hc-line-height: /* Default line height */
--hc-letter-spacing: /* Default letter spacing */--hc-min-target-size: /* Minimum interactive target size (44px) */
--hc-min-tap-target: /* Minimum tap target for touch (48px) */
--hc-disabled-opacity: /* Opacity for disabled elements */The generated CSS automatically applies high-contrast styles when users have enabled high contrast in their system settings:
@media (prefers-contrast: more) {
:root {
/* High contrast tokens applied automatically */
}
}
@media (prefers-contrast: less) {
:root {
/* Enhanced contrast tokens for reduced contrast preference */
}
}This works with:
- Windows High Contrast Mode
- macOS Increase Contrast setting
- iOS/Android accessibility settings
Animations and transitions are automatically reduced when users request reduced motion:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}The high-contrast theme includes enhanced focus indicators for keyboard navigation:
.high-contrast-focus :focus-visible,
[data-high-contrast="true"] :focus-visible {
outline: var(--hc-focus-ring-width) solid var(--hc-focus-ring-color);
outline-offset: var(--hc-focus-ring-offset);
}A skip link component is included for keyboard users to bypass navigation:
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<nav><!-- Navigation --></nav>
<main id="main-content">
<!-- Main content -->
</main>The skip link is visually hidden until focused:
.skip-link {
position: absolute;
top: -100%;
left: 0;
z-index: 9999;
/* ... */
}
.skip-link:focus {
top: 0;
}Two text scaling classes are provided for users who need larger text:
<div class="text-larger">
<p>This text is 12.5% larger than normal.</p>
</div><div class="text-extra-large">
<p>This text is 25% larger than normal.</p>
</div><div class="flex gap-2">
<button onclick="setTextSize('normal')" class="btn">Normal</button>
<button onclick="setTextSize('larger')" class="btn">Larger</button>
<button onclick="setTextSize('extra-large')" class="btn">Extra Large</button>
</div>
<script>
function setTextSize(size) {
document.body.classList.remove('text-larger', 'text-extra-large');
if (size !== 'normal') {
document.body.classList.add(`text-${size}`);
}
localStorage.setItem('text-size', size);
}
// Load saved preference
const savedSize = localStorage.getItem('text-size');
if (savedSize && savedSize !== 'normal') {
document.body.classList.add(`text-${savedSize}`);
}
</script>When running the theme generator in interactive mode, you can select accessibility presets:
php artisan artisanpack:generate-theme --interactiveThe interactive wizard will prompt you to select an accessibility preset along with your color choices.
When exporting theme configuration to JSON, accessibility settings are included:
php artisan artisanpack:generate-theme --primary=blue --accessibility-preset=high-contrast-light --jsonThe JSON file will include:
{
"version": "2.0.0",
"generated": "2024-01-01T00:00:00+00:00",
"colors": {
"primary": "blue",
"secondary": "slate",
"accent": "amber"
},
"accessibility": {
"preset": "high-contrast-light",
"compliance": "AAA",
"mode": "light",
"tokens": {
"hc-background": "#ffffff",
"hc-foreground": "#000000",
...
}
}
}Configure high-contrast settings in your published configuration file:
// config/artisanpack/livewire-ui-components.php
return [
// ... other settings ...
'high_contrast' => [
'enabled' => true,
'output_path' => resource_path('css/artisanpack-high-contrast.css'),
],
];While these presets meet WCAG guidelines, always test with users who rely on accessibility features.
The CSS respects system preferences via media queries. Avoid overriding these unless the user explicitly requests it.
High-contrast themes work best when combined with:
- Proper semantic HTML
- ARIA labels and roles
- Keyboard navigation support
- Screen reader testing
Give users the ability to toggle accessibility features:
<div class="accessibility-controls">
<label>
<input type="checkbox" onchange="toggleHighContrast(this.checked)">
High Contrast Mode
</label>
<label>
<input type="checkbox" onchange="toggleLargerText(this.checked)">
Larger Text
</label>
<label>
<input type="checkbox" onchange="toggleReducedMotion(this.checked)">
Reduce Motion
</label>
</div>Use the built-in contrast verification:
use ArtisanPack\LivewireUiComponents\Styling\HighContrastTheme;
$theme = new HighContrastTheme;
// Verify a color combination meets WCAG AAA
$isCompliant = $theme->verifyContrast('#000000', '#ffffff', 'AAA');
// Calculate the actual contrast ratio
$ratio = $theme->calculateContrastRatio('#000000', '#ffffff');
// Returns ~21.0 (maximum contrast)- Ensure the CSS file is imported after your theme CSS
- Check that the preset class or data attribute is applied to the correct element
- Verify the CSS file was generated successfully
- Check browser support for
prefers-contrastandprefers-reduced-motion - Verify system accessibility settings are enabled
- Some browsers may require a restart after changing system settings
- Ensure the
.high-contrast-focusor[data-high-contrast="true"]attribute is applied - Check for CSS that might be overriding the focus styles
- Verify
--focus-ring-colorhas sufficient contrast with the background