color-elements
Version:
A set of web components for working with color. A Color.js project.
70 lines (64 loc) • 3 kB
CSS
/* A <color-scale>'s points are its swatches, exposed as the "color-swatch" part.
Those live in the scale's shadow tree, so hue-wheel can only reach them from the
document scope, where `hue-wheel color-scale::part(color-swatch)` resolves — a
shadow ::slotted() rule can't chain into ::part(). (A directly-slotted
<color-swatch> doesn't have this problem and is placed from hue-wheel.css via
::slotted().) The dots' *appearance* comes from <color-swatch>'s own dot mode,
triggered by --swatch-style (inherited from the <hue-wheel> host); this file only
positions and sizes them. The same approach <color-chart> uses for its swatches. */
@property --_scale {
syntax: "<number>";
initial-value: 1;
inherits: false;
}
/* Polar placement: the same model as hue-wheel.css's marker/::slotted rule, here in
document scope. --hue (angle) + --channel (raw value) are set on each swatch by
JS; --channel-min / --channel-max are set on the <hue-wheel> host and inherit
down. Go to the angle, move out by --_r, rotate back so the dot stays upright. */
hue-wheel color-scale::part(color-swatch) {
position: absolute;
top: 50%;
left: 50%;
margin: 0;
/* A scale renders size="large" swatches, whose host is large, contains its own
size, and is a flex column whose block size collapses below the dot. Undo all
that and force the host square so it shrink-wraps its dot (like a default-size
swatch) — then the centring translate below lands the *dot* (not just the host)
on the point, and the host doesn't intercept hover between dots. ::part wins
over the swatch's inner :host([size=large]) rules. */
contain: none;
container-type: normal;
inline-size: max-content;
min-inline-size: 0;
min-block-size: 0;
aspect-ratio: 1;
--_channel-progress: clamp(
0,
(var(--channel) - var(--channel-min)) / (var(--channel-max) - var(--channel-min)),
1
);
--_r: calc(var(--_channel-progress) * 50cqi);
translate: -50% -50%;
/* scale() is innermost so the hover-grow stays centred on the point. Folding it
into the transform avoids the individual `scale` property (applied after
`transform`), which would scale the position and fling the dot outward. Only
--_scale transitions, so dot positions don't animate on (re)placement. */
transform: rotate(calc(-1 * var(--hue))) translateX(var(--_r)) rotate(var(--hue))
scale(var(--_scale));
transition: 150ms --_scale;
/* Grow a point on hover so a cluster stays explorable; its details are in the
tooltip (color-swatch upgrades it to a popover). */
&:hover {
--_scale: 1.6;
z-index: 1;
}
}
/* No channel → every point rides the middle of the ring. */
hue-wheel:state(ring) color-scale::part(color-swatch) {
--_r: calc((1 - var(--ring-thickness, 0.35) / 2) * 50cqi);
}
/* The scale itself generates no box, so it neither takes up layout space nor
intercepts hover between the dots; its points position against the wheel. */
hue-wheel color-scale {
display: contents;
}