Quiet at rest. Precise and alive during interaction.
We admire Apple's attention to micro-interaction, timing and physical feedback — this page borrows that craft, not Apple's visual identity or animation style. Irozon motion is premium, restrained, responsive and technically polished. It is never decorative for its own sake: no flashy reveals, no excessive springs or bouncing, no glow, no large transforms, no animation just because an element can move.
Motion exists to communicate something: a state change, hierarchy, cause and effect, continuity, feedback on input, or a spatial relationship. If a transition doesn't communicate one of those, the interface is better off without it.
Immediate feedback
Interactive controls acknowledge input quickly — feedback lives on press, not on release. A control that waits to respond feels disconnected from the hand that touched it.
Continuity
Elements entering or leaving preserve spatial understanding. Something that opens from a trigger should feel anchored to it; something that closes should retreat along a path the eye can follow, not vanish and reappear elsewhere.
Restraint
Small interactions deserve small movement. A hover color shift doesn't need a scale change; a scale change doesn't need a shadow escalation on top of it. Add exactly one signal, not three.
Hierarchy
The larger or more consequential the change, the more deliberate the transition may be. A button's hover is instant; a drawer taking over part of the screen earns a slower, more considered entrance.
Consistency
The same interaction type feels the same everywhere in an Irozon product. One hover treatment for cards, one press feedback for buttons, one popover behavior — not a different feel per screen because a different person built it.
Two small scales cover almost everything.
Four durations, four easings. Reach for a fifth value only when a real interaction
genuinely can't be served by these — don't let one-off timings creep back in. Every
transition below animates named properties explicitly (transform,
opacity, background…); Irozon interactions never reach for
transition: all as a default, since it silently animates properties
that were never meant to move and makes performance and intent both harder to
reason about.
Duration
Hover a card (or Tab to it) to preview its timing.
--motion-duration-instant — press/active feedback, a toggle's flip.
--motion-duration-fast — hover state changes, a small icon nudge.
--motion-duration-standard — dropdowns, tabs, popovers, selection.
--motion-duration-deliberate — drawers, modals, larger panels.
Easing
All four run at the same duration here so only the curve shape differs. Replay to compare them side by side.
cubic-bezier(.4, 0, .2, 1)
cubic-bezier(0, 0, .2, 1)
cubic-bezier(.4, 0, 1, 1)
cubic-bezier(.2, 0, 0, 1)
How to choose
- Standard — the default when nothing more specific applies: symmetric, unremarkable, correct almost everywhere.
- Enter — fast out of the gate, settles gently. Use whenever something appears (a popover opening, a panel revealing).
- Exit — starts unhurried, then leaves quickly. Use whenever something is dismissed — departure should read as faster than arrival, not a mirror image of it.
- Emphasized — a longer, more pronounced deceleration, reserved for the deliberate tier's largest spatial movement (a drawer or modal). Still no overshoot.
One exception exists outside this scale: a single, deliberately springy easing reserved for the Signature CTA's reveal (see Buttons) and not reused anywhere else. Every other interactive default on this page is critically damped — it settles into place without overshoot or oscillation. A system built on springs everywhere stops feeling premium and starts feeling busy; reserve bounce for the one interaction it was tuned for.
Interact with it, not just read about it.
Every example below is real CSS/JS running on this page, not a video or a description. Try them with a mouse, a touchscreen and a keyboard.
Hover
A navigation link, a button and an interactive card — each gets exactly one signal, never elevation or movement just because an element can respond.
Press / tap
A tiny, single-property scale — never enough to feel unstable. Feedback fires on
press (:active), not on release.
scale(0.97), instant
Focus
Focus is an accessibility state, not decoration — the outline appears the instant a control receives keyboard focus, with no delay and no fade to obscure it. Press Tab to move through these three controls.
Selection
A single indicator layer slides to the selected option, rather than each button independently swapping its own background — the eye tracks one moving shape.
Enter & exit
A popover anchored to its trigger. Entry settles in gently over the standard duration; exit is quicker and more direct — dismissal shouldn't linger. Try opening it, then close it with Esc, an outside click, or the trigger itself.
A small contextual panel — the same pattern a menu, a tooltip-with-actions, or a lightweight settings popover would use.
Drawer / modal
The largest spatial movement in the system: the deliberate duration, emphasized easing, and a dimming backdrop that separates the panel from the page behind it. Bounded to this stage rather than the real viewport — the real navigation drawer elsewhere on this site uses this same recipe. Esc, the close control, or the backdrop all dismiss it.
Panel title
Deliberate duration, emphasized easing, anchored to the edge it travels from.
Cards
Only a card that's genuinely interactive (it navigates, opens, or selects something) responds on hover. A card that merely displays information stays completely still — motion here is a promise about what happens if you click, not a decoration.
Static
Displays information only — stays still.
Status / state change
A label and its indicator dot cross-fade between states. The change draws the eye through color and text, never through a bounce, a scale-up, or a celebratory flourish.
Loading / progress
A spinner is reserved for a button carrying out a committed action — brief, and on the control the user just pressed. Content that's still arriving uses a skeleton surface instead of a spinner; the shape of what's coming communicates progress better than a generic loading icon.
Project loaded
Real content, same footprint as the placeholder it replaced.
Icon state change
Copy → Check: the confirmation this recipe is built from. Both icons occupy the
exact same centered cell — no layout shift, no rotation, no bounce — and crossfade
with a very small scale change at instant speed. The check remains
briefly, then reverts on its own.
Duration and easing, by interaction.
A compact reference, not an exhaustive rulebook — most Irozon products only ever need this table.
| Interaction | Duration | Easing |
|---|---|---|
| Button / link hover | fast · 150ms | standard |
| Button / control press | instant · 100ms | standard |
| Navigation hover | fast · 150ms | standard |
| Card hover (border only) | fast · 150ms | standard |
| Selection indicator move | standard · 220ms | standard |
| Popover / menu enter | standard · 220ms | enter |
| Popover / menu exit | fast · 150ms | exit |
| Drawer / modal open | deliberate · 400ms | emphasized |
| Drawer / modal close | deliberate · 400ms | exit |
| Status / state change | standard · 220ms | standard |
| Skeleton → content swap | standard / fast | enter / exit |
| Icon state change (Copy → Check) | instant · 100ms | standard |
Per-component recipes, not one universal hover.
There is no rule that every component tints green, lifts, or gains a shadow on hover. Each component gets exactly the signal it needs — often less than you'd expect.
Interactive row / interactive surface
A large clickable row (a list item, a table row) stays quiet at rest — no heavy
selected-looking fill, no automatic shadow or lift on hover. If the row already
has a trailing affordance (a chevron, an external-link glyph), emphasize that
instead of tinting the whole row. Where a subtle surface hover genuinely helps,
keep it as a semantic recipe rather than a repeated arbitrary utility value —
roughly primary-surface ~4–5% / primary-border ~10%.
:focus-visible stays independent of hover, and touch never inherits a
sticky mouse-hover state.
Icon button
The canonical square icon-only button — fixed geometry, centered icon, keyboard
accessible, with hover/focus/disabled/press and reduced-motion owned entirely by
the primitive. See Buttons for the
data-icon-only API and its aria-label requirement.
Trailing action indicator
Not the same thing as an icon button. A trailing action indicator (Copy → Check, a chevron, an external-link glyph) is a non-interactive affordance inside a row or control that is already the interaction target — it never gets its own focus stop or click handler. An IconButton is an independently interactive control in its own right. Nesting one inside the other's hit area creates a confusing double target; pick one role per element.
Seven states, not interchangeable.
A control can be in more than one of these at once — but each communicates something the others don't.
| State | Communicates | Rule |
|---|---|---|
| Rest | The default, quiet state | Nothing moves when nobody is interacting. |
| Hover | "This responds to input" | Never the only indication of interactivity — pointer-only, absent on touch. |
| Focus | "Keyboard interaction is here" | Always visible independently of hover; never delayed or obscured. |
| Active / pressed | "Input is landing right now" | Transient — fires on press, releases on release, never persists. |
| Selected | "This is the current choice" | Persists after the pointer leaves — a fundamentally different signal from hover. |
| Disabled | "Not available right now" | Never animates as if active — no hover, no press feedback, no transitions. |
| Loading | "In progress" | Replaces the active affordance; the control that triggered it stays visibly busy, not silent. |
prefers-reduced-motion: reduce is not "no motion."
Reduced motion does not mean removing every state change — it means removing travel. Interactive controls, status, selection and loading must all remain just as clear; only the spatial journey between states goes away.
- Eliminate translation and scale — an element still changes, it just no longer moves to get there.
- Shorten or remove spatial animation on drawers, panels and popovers; a quick cross-fade replaces the slide.
- Preserve immediate visual feedback — hover, press and background/color changes stay, since they don't rely on spatial travel.
- Keep focus, selection, loading and status changes exactly as legible as with motion on.
- An open-ended, looping animation (a marquee, an infinite spinner) needs its own explicit guard — a loop has no natural "end state" to just skip to.
Every transition on this page — including every demonstration above — is wrapped in a
@media (prefers-reduced-motion: reduce) rule (and mirrored here via a
.force-reduced-motion class) that removes transform/scale/opacity travel
and lets the state change land instantly instead. Toggle this on, then scroll back up
and try the drawer, the popover or the segmented control again.