Buttons
A button set built around the press. Each button sinks the instant it is pressed, lets go if you drag away, and springs back when you release. The solid button wears a satin face; the spotlight adds a breathing glow and sparks. Pin a state with the switcher, or press Publish to watch it load.
Notes
- Technique
- The press is tracked by hand rather than with :active. It turns on the instant the pointer goes down, off while the pointer is dragged away (a release out there doesn’t click), and back on when it returns; Space and Enter press it too. Each button’s looks are layers already painted on its pseudo-elements, the rest sheen on one and the pressed shade on the other, so a press only cross-fades them and moves the button: nothing but opacity and transform animates.
- Timing
- Press: 150ms ease-out to 97% scale, sinking 1px, with the pressed look on at once. Release: 300ms on a critically damped spring sampled into a CSS linear() curve, so it settles without overshoot, while the look fades back over 200ms. The spotlight’s glow breathes every 3.6s, and each spark rises over 2.6–3.6s.
- Interruption
- Transitions start from the value on screen, so pressing again during the release catches the button mid-spring. The switcher pins every button to a state at any moment. Loading keeps each button’s width: the spinner takes the contents’ place without moving the layout.
- Reduced motion
- No shrink and no sink, no sparks, and the glow holds still. The look still changes on press, and the spinner pulses instead of turning.
- Accessibility
- Native buttons. Loading sets aria-busy and aria-disabled rather than disabled, so focus stays on the button while it works; its label is faded rather than hidden, so it keeps its name, and a status region announces the job starting and ending. Icon buttons are named with aria-label, and the small ghost ones keep a 44px target. Hover only applies where a pointer can hover, so a tap never leaves a button lit.