color-elements
Version:
A set of web components for working with color. A Color.js project.
215 lines (189 loc) • 6.38 kB
CSS
:host {
display: flex;
position: relative;
/* Establish a container so the out-of-gamut overlay can size and position each range in `cqi`
(1cqi = 1% of the track width). That lets the overlay layers use lengths for background-position
instead of percentages, sidestepping the "% is relative to area − image" rule. */
container-type: inline-size;
--_oog-color: var(--oog-color, hsl(from canvas h s l / 90%));
--_oog-pattern: var(
--oog-pattern,
repeating-linear-gradient(-45deg, var(--_oog-color) 0 0.37em, transparent 0 0.57em)
);
}
.color-slider,
.slider-tooltip {
--transparency-cell-size: 1.5em;
--_transparency-cell-size: var(--transparency-cell-size, 0.5em);
--_transparency-background: var(--transparency-background, transparent);
--_transparency-darkness: var(--transparency-darkness, 5%);
--_transparency-grid: var(
--transparency-grid,
repeating-conic-gradient(
transparent 0 25%,
rgb(0 0 0 / var(--_transparency-darkness)) 0 50%
)
0 0 / calc(2 * var(--_transparency-cell-size)) calc(2 * var(--_transparency-cell-size))
content-box border-box var(--_transparency-background)
);
--_slider-color-stops: var(--slider-color-stops, transparent 0% 100%);
--_slider-gradient: var(
--slider-gradient,
linear-gradient(to right var(--in-space,), var(--_slider-color-stops))
);
--_slider-height: var(--slider-height, 2.2em);
/* Out-of-gamut overlay layers, set by the component when a gamut is in effect: one background
layer per range, ending in a trailing comma so they splice ahead of the color band. Empty
when nothing is out of gamut. */
--_gamut-overlay: var(--slider-gamut-overlay,);
--_slider-thumb-width: var(--slider-thumb-width, 1em);
--_slider-thumb-height-offset: var(--slider-thumb-height-offset, 2px);
--_slider-thumb-height: var(
--slider-thumb-height,
calc(var(--_slider-height) + var(--_slider-thumb-height-offset))
);
--_slider-thumb-radius: var(--slider-thumb-radius, 0.16em);
--_slider-thumb-background: var(--slider-thumb-background, var(--color, transparent));
--_slider-thumb-border: var(--slider-thumb-border, 1px solid oklab(0.2 0 0));
--_slider-thumb-border-active: var(--slider-thumb-border-active, 2px solid oklab(0.4 0 0));
--_slider-thumb-scale-active: var(--slider-thumb-scale-active, 1.1);
--_tooltip-background: var(--tooltip-background, hsl(0 0 0 / 80%));
--_tooltip-border-radius: var(--tooltip-border-radius, 0.3em);
--_tooltip-pointer-height: var(--tooltip-pointer-height, 0.3em);
--_tooltip-pointer-angle: var(--tooltip-pointer-angle, 90deg);
}
.color-slider {
@supports (background: linear-gradient(in oklab, red, tan)) {
--in-space: in var(--color-space, oklab) var(--hue-interpolation,);
}
display: block;
margin: 0;
width: 100%;
-moz-appearance: none;
-webkit-appearance: none;
/* No comma between the overlay and the band: --_gamut-overlay carries its own trailing comma
when present, and collapses to nothing when in gamut. */
background:
var(--_gamut-overlay) var(--_slider-gradient),
var(--_transparency-grid);
background-origin: border-box;
background-clip: border-box;
height: var(--_slider-height);
border-radius: 0.3em;
border: 1px solid rgb(0 0 0 / 8%);
&::-webkit-slider-thumb {
-webkit-appearance: none;
box-sizing: content-box;
width: var(--_slider-thumb-width);
height: var(--_slider-thumb-height);
border-radius: var(--_slider-thumb-radius);
border: var(--_slider-thumb-border);
box-shadow: 0 0 0 1px white;
background: var(--color, transparent);
transition:
200ms,
0s background;
}
&::-moz-range-thumb {
box-sizing: content-box;
width: var(--_slider-thumb-width);
height: var(--_slider-thumb-height);
border-radius: var(--_slider-thumb-radius);
border: var(--_slider-thumb-border);
box-shadow: 0 0 0 1px white;
background: var(--color, transparent);
transition:
200ms,
0s background;
}
&::-moz-range-thumb:active {
border: var(--_slider-thumb-border-active);
scale: var(--_slider-thumb-scale-active);
}
&::-moz-range-track {
background: none;
}
}
/* For some reason, the &::-webkit-slider-thumb:active rule (previously used inside the above rule) doesn't work 🤷♂️ */
/* DO NOT MOVE IT BACK! :) */
.color-slider::-webkit-slider-thumb:active {
border: var(--_slider-thumb-border-active);
scale: var(--_slider-thumb-scale-active);
}
.slider-tooltip {
position: absolute;
left: clamp(
-20%,
100% * var(--progress) - (var(--progress) - 0.5) * var(--_slider-thumb-width) / 2
/* center on slider thumb */,
100%
);
bottom: calc(100% + 3px);
translate: -50%;
transform-origin: bottom;
display: flex;
padding-block: 0.3em;
padding-inline: 0.4em;
border: var(--_tooltip-pointer-height) solid transparent;
border-radius: calc(var(--_tooltip-border-radius) + var(--_tooltip-pointer-height));
text-align: center;
color: white;
background:
conic-gradient(
from calc(-1 * var(--_tooltip-pointer-angle) / 2) at bottom,
var(--_tooltip-background) var(--_tooltip-pointer-angle),
transparent 0
)
border-box bottom / 100% var(--_tooltip-pointer-height) no-repeat,
var(--_tooltip-background) padding-box;
color-scheme: dark;
transition:
visibility 0s 200ms,
opacity 200ms,
scale 200ms,
width 100ms,
left 200ms cubic-bezier(0.17, 0.67, 0.49, 1.48);
&::after {
content: var(--tooltip-suffix);
}
input {
all: unset;
&:where([type="number"]) {
--content-width: calc(var(--value-length) * 1ch);
width: calc(var(--content-width, 2ch) + 1.2em);
min-width: calc(2ch + 1.2em);
box-sizing: content-box;
&::-webkit-textfield-decoration-container {
gap: 0.2em;
}
@container style(--tooltip-suffix) {
&::-webkit-textfield-decoration-container {
flex-flow: row-reverse;
}
}
/* Don’t auto hide the spin buttons */
&::-webkit-inner-spin-button {
opacity: 1;
}
}
@supports (field-sizing: content) {
field-sizing: content;
width: auto;
}
/* Prevent input from moving all over the place as we type */
&:focus {
transition-delay: 0.5s;
}
}
&:not(:is(:focus-within, :hover) > *, .color-slider:is(:focus, :hover) + *, :focus, :hover) {
visibility: hidden;
opacity: 0;
scale: 0.5;
}
}
:host(:not([tooltip])) .slider-tooltip {
display: none;
}
:host([tooltip="progress"]) .slider-tooltip {
--tooltip-suffix: "%";
}