Einen Farbwähler als Web Component von Grund auf bauen
Embed This Widget
Add the script tag and a data attribute to embed this widget.
Embed via iframe for maximum compatibility.
<iframe src="https://colorfyi.com/iframe/entity//" width="420" height="400" frameborder="0" style="border:0;border-radius:10px;max-width:100%" loading="lazy"></iframe>
Paste this URL in WordPress, Medium, or any oEmbed-compatible platform.
https://colorfyi.com/entity//
Add a dynamic SVG badge to your README or docs.
[](https://colorfyi.com/entity//)
Use the native HTML custom element.
Das native <input type="color"> ist ein grobes Werkzeug. Es delegiert an den OS-Farbwähler — der auf jeder Plattform anders aussieht, nicht gestylt werden kann und keine programmatische Kontrolle über das Layout bietet. Für Design-Tools, Barrierefreiheitsprüfer oder jedes Produkt, bei dem der Farbwähler eine zentrale Interaktion ist, muss man seinen eigenen bauen.
Web Components sind die richtige Architektur für einen Farbwähler. Sie sind Framework-unabhängig, kapseln ihren internen Zustand mit Shadow DOM, feuern Standard-DOM-Events und funktionieren in React, Vue, Angular oder purem HTML ohne Anpassung. Einmal bauen, überall verwenden.
Dieser Leitfaden implementiert einen vollständigen Farbwähler: eine 2D-Farbfläche als Canvas, einen Farbton-Schieberegler, einen Alpha-Kanal-Schieberegler, eine Hex-Eingabe und vollständige Tastaturnavigation mit ARIA-Labels.
Web Component-Grundlagen für UI
Die Custom Element API
Eine Web Component ist eine Klasse, die HTMLElement erweitert. Der Browser registriert sie mit einem Tag-Namen, und sie verhält sich wie jedes eingebaute Element — einschließlich Unterstützung für Attribute, Eigenschaften, Events und geslottete Kinder:
class ColorPicker extends HTMLElement {
// Wird aufgerufen, wenn das Element erstmals mit dem DOM verbunden wird
connectedCallback() {}
// Wird aufgerufen, wenn das Element aus dem DOM entfernt wird
disconnectedCallback() {}
// Beobachtete Attribute lösen attributeChangedCallback aus
static get observedAttributes() {
return ['value', 'alpha'];
}
// Wird aufgerufen, wenn sich ein beobachtetes Attribut ändert
attributeChangedCallback(name, oldValue, newValue) {}
}
customElements.define('color-picker', ColorPicker);
Verwendung überall in HTML:
<color-picker value="#FF5733" alpha="true"></color-picker>
Oder in React (mit einem Ref für die Event-Verarbeitung):
import { useRef, useEffect } from 'react';
function App() {
const pickerRef = useRef(null);
useEffect(() => {
const picker = pickerRef.current;
const handler = (e) => console.log(e.detail.hex);
picker.addEventListener('color-change', handler);
return () => picker.removeEventListener('color-change', handler);
}, []);
return <color-picker ref={pickerRef} value="#FF5733" />;
}
Shadow DOM zur Kapselung
Shadow DOM gibt der Komponente einen privaten DOM-Baum, der vom Hauptdokument isoliert ist. Externes CSS kann interne Elemente nicht versehentlich umgestalten, und interne IDs stehen nicht mit Seiten-IDs in Konflikt:
class ColorPicker extends HTMLElement {
constructor() {
super();
// Shadow Root anhängen — 'open' erlaubt externem JS den Zugriff via element.shadowRoot
this.shadow = this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.shadow.innerHTML = `
<style>
:host {
display: inline-block;
width: 280px;
font-family: system-ui, -apple-system, sans-serif;
}
.picker-area {
position: relative;
width: 100%;
height: 200px;
border-radius: 8px;
overflow: hidden;
cursor: crosshair;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
</style>
<div class="picker-area">
<canvas id="color-area" width="280" height="200"></canvas>
<div class="picker-cursor" role="presentation"></div>
</div>
<div class="sliders">
<div class="slider-row">
<canvas id="hue-slider" width="280" height="20" role="slider"
aria-label="Hue" aria-valuemin="0" aria-valuemax="360"></canvas>
</div>
</div>
`;
}
}
Canvas-basiertes Farbflächen-Rendering
Die Farbfläche
Die Hauptfarbfläche ist ein 2D-Verlauf: Die horizontale Achse zeigt die Sättigung (0 % bis 100 %), die vertikale Achse den Wert/die Helligkeit (100 % oben, 0 % unten). Der Farbton wird durch den Farbton-Schieberegler festgelegt. Dies ist das HSV-Farbmodell — verschieden von HSL, das die Helligkeit anders abbildet.
function drawColorArea(canvas, hue) {
const ctx = canvas.getContext('2d');
const { width, height } = canvas;
// Den Basis-Farbton als horizontalen Weiß-zu-Farbton-Verlauf zeichnen
const hueGradient = ctx.createLinearGradient(0, 0, width, 0);
hueGradient.addColorStop(0, 'white');
hueGradient.addColorStop(1, `hsl(${hue}, 100%, 50%)`);
ctx.fillStyle = hueGradient;
ctx.fillRect(0, 0, width, height);
// Einen vertikalen transparent-zu-schwarz-Verlauf überlagern
const darkGradient = ctx.createLinearGradient(0, 0, 0, height);
darkGradient.addColorStop(0, 'rgba(0, 0, 0, 0)');
darkGradient.addColorStop(1, 'rgba(0, 0, 0, 1)');
ctx.fillStyle = darkGradient;
ctx.fillRect(0, 0, width, height);
}
Die Kombination eines horizontalen Weiß-zu-Farbton-Verlaufs und eines vertikalen transparent-zu-schwarz-Verlaufs erzeugt den vollständigen HSV-Raum für diesen Farbton. Die obere linke Ecke ist weiß (S=0, V=100), die obere rechte ist der reine Farbton (S=100, V=100), die untere rechte ist schwarz (beliebiges S, V=0) und die untere linke ebenfalls schwarz.
Pixelfarbe aus dem Canvas lesen
Wenn der Benutzer in der Farbfläche klickt oder zieht, die Farbe an dieser Position mit getImageData lesen:
function getColorAtPosition(canvas, x, y) {
const ctx = canvas.getContext('2d');
const pixel = ctx.getImageData(
Math.max(0, Math.min(x, canvas.width - 1)),
Math.max(0, Math.min(y, canvas.height - 1)),
1, 1
).data;
return {
r: pixel[0],
g: pixel[1],
b: pixel[2],
};
}
Den Cursor zeichnen
Der über dem Canvas überlagerte Cursor zeigt den aktuellen Auswahlpunkt an. Als absolut positionierten Kreis zeichnen:
.picker-cursor {
position: absolute;
width: 16px;
height: 16px;
border-radius: 50%;
border: 2px solid white;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.4), 0 2px 4px rgba(0, 0, 0, 0.3);
transform: translate(-50%, -50%);
pointer-events: none;
}
Durch Setzen von left und top als Prozentsatz der Canvas-Dimensionen positionieren:
function updateCursorPosition(cursor, x, y, canvasWidth, canvasHeight) {
cursor.style.left = `${(x / canvasWidth) * 100}%`;
cursor.style.top = `${(y / canvasHeight) * 100}%`;
}
Implementierung von Farbton- und Alpha-Schieberegler
Farbton-Schieberegler
Der Farbton-Schieberegler ist ein horizontales Canvas, das mit dem vollständigen Regenbogenspektrum von 0° bis 360° gefüllt ist:
function drawHueSlider(canvas) {
const ctx = canvas.getContext('2d');
const { width, height } = canvas;
const gradient = ctx.createLinearGradient(0, 0, width, 0);
gradient.addColorStop(0, 'hsl(0, 100%, 50%)');
gradient.addColorStop(0.167, 'hsl(60, 100%, 50%)');
gradient.addColorStop(0.333, 'hsl(120, 100%, 50%)');
gradient.addColorStop(0.5, 'hsl(180, 100%, 50%)');
gradient.addColorStop(0.667, 'hsl(240, 100%, 50%)');
gradient.addColorStop(0.833, 'hsl(300, 100%, 50%)');
gradient.addColorStop(1, 'hsl(360, 100%, 50%)');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
}
function hueFromX(x, canvasWidth) {
return Math.round((x / canvasWidth) * 360);
}
function xFromHue(hue, canvasWidth) {
return (hue / 360) * canvasWidth;
}
Alpha-Schieberegler
Der Alpha-Schieberegler benötigt einen Schachbretthintergrund (der Standardindikator für Transparenz) unter dem Farbe-zu-transparent-Verlauf:
function drawAlphaSlider(canvas, hex) {
const ctx = canvas.getContext('2d');
const { width, height } = canvas;
// Schachbrettmuster über CSS-Hintergrund auf dem Container,
// oder manuell für Canvas-only gezeichnet:
const size = 6;
for (let row = 0; row < Math.ceil(height / size); row++) {
for (let col = 0; col < Math.ceil(width / size); col++) {
ctx.fillStyle = (row + col) % 2 === 0 ? '#CCCCCC' : '#FFFFFF';
ctx.fillRect(col * size, row * size, size, size);
}
}
// Overlay: Farbe-zu-transparent-Verlauf
const gradient = ctx.createLinearGradient(0, 0, width, 0);
gradient.addColorStop(0, `${hex}00`); // transparent
gradient.addColorStop(1, hex); // opak
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
}
Einheitliche Schieberegler-Interaktion
Beide Schieberegler teilen dasselbe Zieh-Interaktionsmuster. In einem wiederverwendbaren Helfer extrahieren:
function makeDraggable(element, onMove) {
let dragging = false;
const getX = (e) => {
const rect = element.getBoundingClientRect();
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
return Math.max(0, Math.min(clientX - rect.left, rect.width));
};
element.addEventListener('mousedown', (e) => {
dragging = true;
onMove(getX(e));
});
element.addEventListener('touchstart', (e) => {
dragging = true;
onMove(getX(e));
}, { passive: true });
document.addEventListener('mousemove', (e) => {
if (dragging) onMove(getX(e));
});
document.addEventListener('touchmove', (e) => {
if (dragging) onMove(getX(e));
}, { passive: true });
document.addEventListener('mouseup', () => { dragging = false; });
document.addEventListener('touchend', () => { dragging = false; });
}
Die mousemove- und mouseup-Handler auf document-Ebene stellen sicher, dass das Ziehen auch dann fortgesetzt wird, wenn der Cursor die Grenzen des Schiebereglers verlässt — entscheidend für die Benutzerfreundlichkeit.
Farbwechsel-Events auslösen
Custom Event-Muster
CustomEvent mit einem detail-Payload verwenden, der die vollständigen Farbdaten enthält. Mit einem Namespace-Präfix benennen, um Konflikte zu vermeiden:
function dispatchColorChange(element, color) {
const event = new CustomEvent('color-change', {
bubbles: true, // Propagiert im DOM-Baum nach oben
composed: true, // Überquert Shadow DOM-Grenzen
detail: {
hex: color.hex,
rgb: color.rgb,
hsl: color.hsl,
alpha: color.alpha,
hexWithAlpha: color.alpha < 1
? `${color.hex}${Math.round(color.alpha * 255).toString(16).padStart(2, '0').toUpperCase()}`
: color.hex,
},
});
element.dispatchEvent(event);
}
composed: true ist essenziell — ohne es werden innerhalb von Shadow DOM ausgelöste Events nicht über die Grenze übertragen und sind für Code im Hauptdokument unsichtbar.
Internes Zustandsmanagement
Den Farbzustand als HSV + Alpha verwalten (das natürlichste Modell für einen visuellen Wähler) und bei der Ausgabe in andere Formate konvertieren:
class ColorPicker extends HTMLElement {
#state = {
h: 0, // Farbton 0-360
s: 100, // Sättigung 0-100 (HSV)
v: 100, // Wert/Helligkeit 0-100 (HSV)
a: 1, // Alpha 0-1
};
get #hex() {
const { r, g, b } = hsvToRgb(this.#state.h, this.#state.s, this.#state.v);
return `#${[r, g, b].map(v => v.toString(16).padStart(2, '0')).join('').toUpperCase()}`;
}
#update(changes) {
this.#state = { ...this.#state, ...changes };
this.#render();
dispatchColorChange(this, {
hex: this.#hex,
rgb: hsvToRgb(this.#state.h, this.#state.s, this.#state.v),
hsl: rgbToHsl(hsvToRgb(this.#state.h, this.#state.s, this.#state.v)),
alpha: this.#state.a,
});
}
}
Die #update-Methode wird aufgerufen, wenn sich ein beliebiger Teil der Farbe ändert — beim Ziehen des Farbton-Schiebereglers, beim Klicken auf die Farbfläche oder beim Eingeben in das Hex-Feld. Sie aktualisiert den Zustand, rendert betroffene Canvas-Elemente neu und feuert das Event.
Hex-Eingabe-Synchronisierung
Das Hex-Eingabefeld soll die aktuelle Farbe widerspiegeln und Benutzereingaben akzeptieren:
setupHexInput(hexInput) {
// Zustand bei jeder Aktualisierung in die Eingabe spiegeln
this.addEventListener('_internal-state-change', () => {
if (document.activeElement !== hexInput) {
hexInput.value = this.#hex;
}
});
// Eingabe parsen und Zustand aktualisieren, wenn der Benutzer tippt
hexInput.addEventListener('input', (e) => {
const raw = e.target.value.trim();
const match = raw.match(/^#?([0-9A-Fa-f]{6}|[0-9A-Fa-f]{3})$/);
if (!match) return; // Unvollständige Eingabe still ignorieren
const full = match[1].length === 3
? match[1].split('').map(c => c + c).join('')
: match[1];
const r = parseInt(full.slice(0, 2), 16);
const g = parseInt(full.slice(2, 4), 16);
const b = parseInt(full.slice(4, 6), 16);
const { h, s, v } = rgbToHsv(r, g, b);
this.#update({ h, s, v });
});
}
Das Überspringen der Aktualisierung, wenn die Eingabe fokussiert ist, verhindert eine Rückkopplungsschleife, bei der das Eingeben von #FF eine Zustandsaktualisierung auslöst, die das Hex-Eingabefeld mitten im Tippen überschreibt.
Barrierefreiheit: Tastaturnavigation, ARIA-Labels, Screenreader
Die Barrierefreiheits-Herausforderung
Ein Canvas-Element ist für Screenreader undurchsichtig — getImageData gibt Pixelwerte zurück, aber diese Pixel vermitteln assistiver Technologie keine semantische Bedeutung. Einen Farbwähler barrierefrei zu machen erfordert das Überlagern semantischer Informationen auf das visuelle Canvas.
ARIA-Rollen für Schieberegler
Die Farbfläche, der Farbton-Schieberegler und der Alpha-Schieberegler funktionieren alle als zweidimensionale Schieberegler. role="slider" mit dem vollständigen ARIA-Schieberegler-Attributsatz verwenden:
<!-- Farbfläche: 2D, zwei separate Schieberegler für die Achsen verwenden -->
<div
role="slider"
id="color-area-saturation"
aria-label="Color saturation"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="75"
aria-valuetext="75% saturation"
tabindex="0"
></div>
<div
role="slider"
id="color-area-brightness"
aria-label="Color brightness"
aria-valuemin="0"
aria-valuemax="100"
aria-valuenow="90"
aria-valuetext="90% brightness"
tabindex="0"
></div>
<!-- Farbton-Schieberegler -->
<div
role="slider"
id="hue-slider"
aria-label="Hue"
aria-valuemin="0"
aria-valuemax="360"
aria-valuenow="120"
aria-valuetext="120 degrees, green"
tabindex="0"
></div>
aria-valuenow und aria-valuetext in der #update-Methode aktualisieren:
#updateAriaAttributes() {
const hueEl = this.shadow.querySelector('#hue-slider');
hueEl.setAttribute('aria-valuenow', this.#state.h);
hueEl.setAttribute('aria-valuetext', `${this.#state.h} degrees`);
const satEl = this.shadow.querySelector('#color-area-saturation');
satEl.setAttribute('aria-valuenow', Math.round(this.#state.s));
satEl.setAttribute('aria-valuetext', `${Math.round(this.#state.s)}% saturation`);
}
Tastaturnavigation
Jedes Schieberegler-Element muss auf Pfeiltasten reagieren. Die standardmäßige Schieberegler-Tastaturinteraktion ist: - Pfeil rechts / Pfeil oben: Wert um eine Einheit erhöhen (oder 5 mit Umschalt für gröbere Schritte) - Pfeil links / Pfeil unten: Wert verringern - Pos1: Auf Minimum setzen - Ende: Auf Maximum setzen
setupKeyboardNavigation(hueSlider) {
hueSlider.addEventListener('keydown', (e) => {
let delta = 0;
const step = e.shiftKey ? 10 : 1;
switch (e.key) {
case 'ArrowRight':
case 'ArrowUp':
delta = step;
break;
case 'ArrowLeft':
case 'ArrowDown':
delta = -step;
break;
case 'Home':
this.#update({ h: 0 });
e.preventDefault();
return;
case 'End':
this.#update({ h: 360 });
e.preventDefault();
return;
default:
return;
}
e.preventDefault();
this.#update({ h: Math.max(0, Math.min(360, this.#state.h + delta)) });
});
}
Für die 2D-Farbfläche alle vier Pfeiltasten verarbeiten, um sich in beide Dimensionen zu bewegen:
setupColorAreaKeyboard(colorArea) {
colorArea.addEventListener('keydown', (e) => {
const step = e.shiftKey ? 5 : 1;
let { s, v } = this.#state;
switch (e.key) {
case 'ArrowRight': s = Math.min(100, s + step); break;
case 'ArrowLeft': s = Math.max(0, s - step); break;
case 'ArrowUp': v = Math.min(100, v + step); break;
case 'ArrowDown': v = Math.max(0, v - step); break;
default: return;
}
e.preventDefault();
this.#update({ s, v });
});
}
Live-Region für Screenreader-Ankündigungen
Damit ein Screenreader die ausgewählte Farbe ankündigt, wenn der Benutzer mit dem Wähler interagiert, eine ARIA-Live-Region hinzufügen:
<div
role="status"
aria-live="polite"
aria-atomic="true"
class="sr-only"
id="color-announcement"
></div>
Bei jeder Farbänderung aktualisieren:
#announceColor() {
const announcement = this.shadow.querySelector('#color-announcement');
const { h, s, v, a } = this.#state;
announcement.textContent = `Selected color: ${this.#hex}, ` +
`hue ${h} degrees, saturation ${Math.round(s)}%, ` +
`brightness ${Math.round(v)}%` +
(a < 1 ? `, ${Math.round(a * 100)}% opacity` : '');
}
Die Einstellung aria-live="polite" kündigt Änderungen an, wenn der Benutzer nicht aktiv mit anderen Elementen interagiert. Für einen Farbwähler, bei dem der Benutzer wahrscheinlich zieht, ist polite korrekt — assertive würde jede Ankündigung mit der nächsten unterbrechen.
Fokus-Indikatoren
Sicherstellen, dass Fokusringe innerhalb des Shadow DOM sichtbar sind. Die Pseudoklasse :focus-visible bietet nur-Tastatur-Fokusringe, ohne Mausinteraktionen zu stören:
/* Innerhalb des Shadow DOM <style> */
[role="slider"]:focus-visible {
outline: 2px solid #2563EB;
outline-offset: 2px;
}
.hex-input:focus-visible {
outline: 2px solid #2563EB;
outline-offset: 1px;
border-radius: 4px;
}
Die vollständige barrierefreie Komponente
Alles zusammenfassend richtet connectedCallback der Komponente alle interaktiven Elemente mit ihren ARIA-Rollen und Tastatur-Handlern ein, bevor eine visuelle Interaktion stattfindet:
connectedCallback() {
this.shadow.innerHTML = this.#template();
this.#setupColorArea();
this.#setupHueSlider();
this.#setupAlphaSlider();
this.#setupHexInput();
this.#setupKeyboardNavigation();
this.#render();
}
#template() {
return `
<style>${this.#css()}</style>
<div class="color-picker" role="group" aria-label="Color picker">
<!-- 2D Farbfläche -->
<div class="picker-area-wrapper">
<canvas id="color-area" width="280" height="200"
aria-hidden="true"></canvas>
<div class="cursor" role="presentation"></div>
<div id="color-area-interactive"
role="slider"
aria-label="Color saturation and brightness"
aria-valuemin="0" aria-valuemax="100"
aria-valuenow="100" aria-valuetext="full saturation, full brightness"
tabindex="0"
class="interactive-overlay">
</div>
</div>
<!-- Farbton-Schieberegler -->
<div class="slider-wrapper">
<canvas id="hue-canvas" width="280" height="20" aria-hidden="true"></canvas>
<div id="hue-thumb" class="slider-thumb" role="slider"
aria-label="Hue" aria-valuemin="0" aria-valuemax="360"
aria-valuenow="0" aria-valuetext="0 degrees, red"
tabindex="0"></div>
</div>
<!-- Alpha-Schieberegler -->
<div class="slider-wrapper" id="alpha-wrapper">
<canvas id="alpha-canvas" width="280" height="20" aria-hidden="true"></canvas>
<div id="alpha-thumb" class="slider-thumb" role="slider"
aria-label="Opacity" aria-valuemin="0" aria-valuemax="100"
aria-valuenow="100" aria-valuetext="100% opacity"
tabindex="0"></div>
</div>
<!-- Hex-Eingabe -->
<div class="hex-row">
<label for="hex-input" class="hex-label">HEX</label>
<input id="hex-input" type="text" class="hex-input"
value="#FF5733" maxlength="7"
aria-label="Hex color code"
autocomplete="off" spellcheck="false" />
</div>
<!-- Screenreader-Live-Region -->
<div role="status" aria-live="polite" aria-atomic="true"
id="color-announcement" class="sr-only"></div>
</div>
`;
}
Das aria-hidden="true" auf den Canvas-Elementen teilt Screenreadern mit, den Pixelinhalt vollständig zu ignorieren — die semantische Bedeutung wird durch die interaktiven Overlay-Elemente daneben bereitgestellt.
Veröffentlichen und Verwenden der Komponente
Auf npm veröffentlichen
Eine Web Component ist nur ein JavaScript-Modul. Mit einem minimalen package.json veröffentlichen:
{
"name": "@yourscope/color-picker",
"version": "1.0.0",
"type": "module",
"main": "./dist/color-picker.js",
"exports": {
".": "./dist/color-picker.js"
},
"files": ["dist/"]
}
In einem beliebigen Projekt importieren:
import '@yourscope/color-picker';
// Jetzt ist <color-picker> global registriert
Mit dem ColorFYI-Konverter verwenden
Den Farbwähler mit der Farbkonverter-API koppeln, um vollständige Farbdaten neben dem visuellen Wähler anzuzeigen:
document.querySelector('color-picker').addEventListener('color-change', async (e) => {
const hex = e.detail.hex.replace('#', '');
const response = await fetch(`/api/color/${hex}`);
const data = await response.json();
document.querySelector('#hex-display').textContent = data.hex;
document.querySelector('#rgb-display').textContent = data.rgb.css;
document.querySelector('#hsl-display').textContent = data.hsl.css;
document.querySelector('#oklch-display').textContent = data.oklch.css;
});
Und den Palettengenerator verwenden, um harmonische Farben für jeden ausgewählten Wert anzuzeigen — und so ein vollständiges Farbentdeckungs-Erlebnis rund um den Wähler zu schaffen.
Das Wichtigste in Kürze
- Web Components mit Shadow DOM sind Framework-unabhängig, stilgekapselt und feuern Standard-DOM-Events — die richtige Architektur für wiederverwendbare UI wie Farbwähler.
- Die Farbfläche verwendet zwei überlagerte Canvas-Verläufe: horizontal Weiß-zu-Farbton für Sättigung, vertikal transparent-zu-schwarz für Wert/Helligkeit.
getImageDataliest die Pixelfarbe an jeder Ziehposition. - Farbton- und Alpha-Schieberegler verwenden dasselbe ziehbare Canvas-Muster; entscheidend ist es,
mousemoveundmouseupandocumentzu hängen, nicht an das Element, damit das Ziehen auch funktioniert, wenn der Cursor den Schieberegler verlässt. CustomEventmitcomposed: trueauslösen, damit Events Shadow DOM-Grenzen überqueren und für übergeordneten Dokumentcode sichtbar sind.- Canvas-Elemente sind für Screenreader undurchsichtig — semantische Bedeutung durch
role="slider"-Overlay-Elemente bereitstellen, mitaria-valuenowundaria-valuetext, die bei jeder Zustandsänderung aktualisiert werden. - Vollständige Pfeiltastennavigation auf jedem Schieberegler implementieren: Einzelschritt bei Pfeiltasten, Fünfschritt mit Umschalt, Pos1/Ende für Min/Max.
- Eine
aria-live="polite"-Statusregion hinzufügen, die die vollständige Farbbeschreibung (Hex, Farbton, Sättigung, Helligkeit, Opazität) bei jeder Änderung ankündigt. - Mit der Farbkonverter-API kombinieren, um vollständige Format-Aufschlüsselungen anzuzeigen, und dem Palettengenerator, um harmonische Farben neben jedem gewählten Wert zu zeigen.