Color Picker
Here we are using 3 sliders for the hue, saturation and lightness values.
The color is then calculated using the hsl() function and
placed into the style="" property as a css variable.
<script>
let color = { h: 40, s: 50, l: 90 };
$: styles = `
--hue: ${color.h}deg;
--saturation: ${color.s}%;
--lightness: ${color.l}%;
--color: hsl( var(--hue), var(--saturation), var(--lightness) );
--picker-color: hsla( var(--hue), 60%, 70%, 1 );
`;
</script>
<div class="color-ui" style="{styles}">
<RangeSlider id="h" float prefix="h: " suffix="°" bind:value={color.h} max={360} />
<RangeSlider id="s" float prefix="s: " suffix="%" bind:value={color.s} max={100} />
<RangeSlider id="l" float prefix="l: " suffix="%" bind:value={color.l} max={100} />
{#if styles}
<div class="color">
--hue: {color.h}deg;
--saturation: {color.s}%;
--lightness: {color.l}%;
</div>
{/if}
</div>/** border and frame for the color ui */
.color {
padding: 1em;
background-color: var(--color);
transition: all 0.5s ease;
}
/** color picker slider */
.color-ui .rangeSlider.rangeSlider {
margin-block: 2em;
/* replace the default accent colors with the color from JS */
--slider-accent: var(--picker-color);
--slider-accent-100: var(--picker-color);
}
/** always show the floating values, and place them over the handles */
.color-ui .rangeSlider.rangeSlider .rangeFloat,
.color-ui .rangeSlider.rangeSlider.rsFocus .rangeFloat,
.color-ui .rangeSlider.rangeSlider:hover .rangeFloat {
opacity: 1;
translate: -50% 100%;
border-radius: 1em;
padding: 0.5em 0.75em;
pointer-events: all;
}
/** Simple Styling for the outer UI */
.color-ui {
border-radius: 0.5rem;
border: 2px solid var(--color);
color: var(--color);
transition: all 0.5s ease;
user-select: none;
font-family: var(--font-mono);
}
/** Advanced css to invert the text color and add a vibrant shadow */
.color-ui {
color: hsla(
var(--hue),
calc(var(--saturation) / 2),
calc((var(--lightness) - 50%) * -1 + 100%),
1
);
text-shadow: 0 1px 1px
hsla(var(--hue), calc(var(--saturation) / 2), calc(var(--lightness) - 50%), 1);
box-shadow:
0 1px 1px 2px
hsla(var(--hue), calc(var(--saturation) / 2), max(calc(var(--lightness) - 10%), 30%), 1),
0 4px 4px 1px
hsla(var(--hue), calc(var(--saturation) / 2), max(calc(var(--lightness) - 10%), 30%), 0.5),
0 8px 10px 5px
hsla(var(--hue), calc(var(--saturation) / 2), max(calc(var(--lightness) - 10%), 30%), 0.5);
}
.color-ui #h.rangeSlider {
--s: var(--saturation);
--l: var(--lightness);
background-image: linear-gradient(
to right,
hsl(0, var(--s), var(--l)),
hsl(60, var(--s), var(--l)),
hsl(120, var(--s), var(--l)),
hsl(180, var(--s), var(--l)),
hsl(240, var(--s), var(--l)),
hsl(300, var(--s), var(--l)),
hsl(360, var(--s), var(--l))
);
}
.color-ui #s.rangeSlider {
--h: var(--hue);
--l: var(--lightness);
background-image: linear-gradient(
to right,
hsl(var(--h), 0%, var(--l)),
hsl(var(--h), 100%, var(--l))
);
}
.color-ui #l.rangeSlider {
--h: var(--hue);
--s: var(--saturation);
background-image: linear-gradient(
to right,
hsl(var(--h), var(--s), 0%),
hsl(var(--h), var(--s), 50%),
hsl(var(--h), var(--s), 100%)
);
}