Relative Color Palette
Palette de dix teintes dérivées en cascade depuis une seule propriété CSS — luminosités et harmonies OKLCH se recalculent instantanément à chaque changement de teinte de base.
Vous aurez accès à la démo interactive avec un compte gratuit.
Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Backgrounds comprend 50 effets, dont 6 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
L'effet repose entièrement sur la propriété personnalisée --base-hue posée sur le container [data-relcolor]. Tous les descendants héritent de cette valeur via var(--base-hue) dans leurs déclarations oklch(). La première rangée décline cinq variantes de luminosité à chroma progressivement réduit : oklch(.85 .15 H) (très clair), .75 .20, .60 .25 (base), .45 .20, .30 .15 (très foncé). L'espace OKLCH étant perceptuellement uniforme, chaque saut de lightness paraît visuellement équivalent quelle que soit la teinte — ce qu'HSL ne garantit pas.
La deuxième rangée expose cinq harmonies chromatiques calculées par calc() sur la teinte : complément à H + 180, analogues à H ± 30, triadiques à H + 120 et H + 240. Le moteur CSS résout ces expressions nativement — zéro calcul JavaScript. Le chroma des harmonies est légèrement réduit (0.22 vs 0.25 pour la base) afin que les couleurs de relation restent distinctes sans saturation agressive.
Le JavaScript est intentionnellement minimal : querySelectorAll("[data-relcolor]") initialise chaque instance avec t = 250 (bleu-indigo) puis pose --base-hue via element.style.setProperty(). Au clic sur le container, t = (t + 47) % 360 fait avancer la teinte de 47° — un nombre premier qui parcourt les 360° sans jamais retomber sur des voisins proches avant d'avoir visité des angles très différents. Plusieurs instances sur la même page fonctionnent sans conflit car chaque itération forEach ferme sur son propre t.
Le hover des pastilles (transform: scale(1.2) translateY(-4px), transition 0,4 s) est la seule animation du composant. Sans JavaScript, la palette reste visible grâce aux valeurs oklch() calculées par CSS — seule la rotation de teinte au clic est inactive.
Accessibilité
- prefers-reduced-motion absent du code. La seule animation est le hover
scale(1.2)sur les pastilles (transition CSS 0,4 s) — mouvement léger et déclenché par l'utilisateur. Si ce point est critique dans votre contexte, ajoutez@media (prefers-reduced-motion: reduce) { .relcolor-swatch { transition: none } }. - Le container
[data-relcolor]ne porte niroleniaria-labelnatifs — il est traité comme décoratif. Si le composant joue un rôle fonctionnel (choix de thème), ajoutezrole="group"etaria-label="Sélecteur de couleur de base". - Clavier : le container n'est pas focusable (pas de
tabindex), la rotation de teinte au clic n'est pas accessible au clavier. Pour un accès complet, wrappez le déclencheur dans un<button>natif. - Contraste : les pastilles OKLCH à luminosité uniforme sont visuellement distinctes entre elles, mais le rapport de contraste texte/fond n'est pas calculé dynamiquement — à vérifier selon la teinte choisie avant usage dans un sélecteur fonctionnel.
- Les attributs
titleHTML sur chaque pastille ("Lighter", "Light", "Base"…) fournissent un label de survol minimal accessible aux technologies d'assistance.
Compatibilité navigateur
Nécessite la fonction CSS oklch() et calc() sur des propriétés personnalisées — Baseline 2023, disponible dans tous les navigateurs modernes depuis mi-2023.
Sur les navigateurs antérieurs sans support <code>oklch()</code>, les pastilles affichent un fond transparent — aucune erreur JS, le layout reste intact. Ajoutez une déclaration <code>background: #888</code> avant chaque règle OKLCH pour un repli visible sur les UA anciens.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="relcolor-container" data-relcolor="" style="--base-hue: 250">
<div class="relcolor-base-row">
<div class="relcolor-base"></div>
<span class="relcolor-base-label">Base</span>
</div>
<div class="relcolor-palette">
<div class="relcolor-swatch sw-lighter" title="Lighter"></div>
<div class="relcolor-swatch sw-light" title="Light"></div>
<div class="relcolor-swatch sw-base" title="Base"></div>
<div class="relcolor-swatch sw-dark" title="Dark"></div>
<div class="relcolor-swatch sw-darker" title="Darker"></div>
</div>
<div class="relcolor-palette">
<div class="relcolor-swatch sw-complement" title="Complement"></div>
<div class="relcolor-swatch sw-analogous1" title="Analogous +30"></div>
<div class="relcolor-swatch sw-analogous2" title="Analogous -30"></div>
<div class="relcolor-swatch sw-triadic1" title="Triadic +120"></div>
<div class="relcolor-swatch sw-triadic2" title="Triadic +240"></div>
</div>
<span class="relcolor-label">cliquez pour changer la couleur de base</span>
</div>
HTML + CSS + JS complet, prêt à coller — avec des centaines d'effets premium.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
| --base-hue (style inline) | 250 | Teinte de départ OKLCH (0–359). 0 = rouge, 120 = vert, 180 = cyan, 250 = bleu-indigo, 300 = violet. Modifiez la valeur inline ou via JS : el.style.setProperty('--base-hue', 160). |
| t + 47 (JS, 3e ligne) | 47 | Pas de rotation de teinte par clic. 47 = nombre premier qui évite les voisins proches. Essayez 30 (douzaines régulières) ou 60 (six couleurs espacées de 60° pour une roue complète en 6 clics). |
| .sw-base { background: oklch(.6 .25 …) } | L=0.6, C=0.25 | Lightness et chroma de la pastille de référence. Montez C jusqu'à 0.37 (max sRGB) pour plus de saturation, descendez L à 0.5 pour une base plus sombre. |
| .sw-lighter { background: oklch(.85 .15 …) } | L=0.85, C=0.15 | Variante la plus claire. Gardez C inférieure à la base pour rester dans le gamut sRGB à haute luminosité. Ajustez L entre 0.78 et 0.92 selon la clarté souhaitée. |
| .relcolor-swatch { width; height; border-radius } | 36px, 36px, 8px | Dimensions et forme des pastilles. Passez à 48 × 48 px pour un affichage documentation, ou 24 × 24 px pour un sélecteur compact en barre d'outils. |
| .relcolor-base { width; height; border-radius } | 50px, 50px, 12px | Taille de la pastille de base mise en avant. Augmentez à 64 × 64 px pour un affichage hero de la couleur de référence. |
| .relcolor-container { gap; padding; background } | 16px, 20px, #0f0f1a | Espacement entre rangées, marges internes et fond du widget. Passez background: transparent pour l'intégrer dans une carte existante. |
FAQ
--base-hue. En JavaScript, convertissez votre hex en OKLCH avec une bibliothèque comme culori : const h = oklch(parse('#3b82f6')).h, puis injectez le résultat avant que le script s'exécute via el.style.setProperty('--base-hue', h).<div class="relcolor-swatch"> dans la deuxième rangée avec des classes CSS dédiées : .sw-split1 { background: oklch(.58 .21 calc(var(--base-hue) + 150)) } et .sw-split2 { background: oklch(.58 .21 calc(var(--base-hue) + 210)) }. Aucune modification du JavaScript n'est nécessaire — les pastilles héritent automatiquement de --base-hue.hsl(60 100% 50%) paraît bien plus lumineux qu'un bleu à hsl(240 100% 50%) à lightness identique. OKLCH garantit que oklch(.6 .25 60) et oklch(.6 .25 240) ont la même luminosité perçue — les palettes dérivées sont visuellement cohérentes quel que soit l'angle de teinte choisi.