Skip to content

Build1 publisher3 min readPublished

The infinite transition: a two-line CSS latch that keeps hover state and stores nothing

A dev.to post shows how transition-duration: calc(infinity * 1s) makes a hover style stick without JavaScript. The paint changes; the DOM does not, and that is the whole tradeoff.

The Engineer · Build desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

Illustration accompanying The infinite transition: a two-line CSS latch that keeps hover state and stores nothing
Generated illustration

What happened

  • A dev.to post from frontendfacile, titled in Italian as making a hover permanent with a single line of CSS and without JavaScript, describes a trick using transition-duration and calc() so that the element's return to its base state takes 'infinite' time.
  • The post explains a transition has two moments: the forward change when the element enters :hover or :focus, and the return to the base style when it leaves; normally a single transition-duration applies in both directions.
  • The technique sets an infinite duration in the base state, so the return never occurs (it requires infinite time), and a normal duration such as 0.5s in the :hover / :focus state to animate the forward change.
  • The post's minimal example is: a, h1 { color: black; transition-property: color; transition-duration: calc(infinity * 1s); } and a:hover, a:focus, h1:hover, h1:focus { color: red; transition-duration: 0.5s; }
  • The post states that transition-duration requires a time value (s or ms), that infinity is a valid numeric value in CSS but is not by itself a time, and that calc(infinity * 1s) converts it into a duration.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

A post from frontendfacile on dev.to documents a CSS trick for making a hover effect stick: give the base state an infinite transition duration and the interactive state a normal one, and the element never travels back [1][3]. That is the smallest available substitute for a very common JavaScript pattern, adding a class on pointer entry and never removing it, and it is worth knowing exactly what it gives up.

The mechanism depends on the fact that a transition runs in two directions: forward when the element enters `:hover` or `:focus`, and back to the base style when it leaves, with one `transition-duration` normally governing both [2]. The post splits them:

```css a, h1 { color: black; transition-property: color; transition-duration: calc(infinity * 1s); } a:hover, a:focus, h1:hover, h1:focus { color: red; transition-duration: 0.5s; } ```

The `calc()` is not decoration. According to the post, `transition-duration` requires a time in `s` or `ms`, and `infinity` is a valid CSS number but not a time on its own, so multiplying it by `1s` produces a duration [5]. Pointer in, the colour reaches red in 0.5s; pointer out, the return transition is scheduled for infinity, so in practice the element stays red [6].

Two notes on the framing. Despite the headline's "one line," the effect needs two declarations across two rules, one for the base duration and one for the hover duration [10]. And the post is explicit that this is not a toggle in the application sense: no state is stored, and the persistence is only the visual consequence of a return that is postponed indefinitely [7].

That second point is where the cost lands. The rules change nothing but `color` and `transition-duration` [4], so there is no attribute, no class, and no DOM change for anything else to read [12]. Nothing to submit with a form, nothing for a sibling selector to key off, nothing to restore after a re-render. The selector list also includes `:focus` [4], which means keyboard traversal latches too: tab across a page of links and every one you pass through stays in the hovered style, with no way back [11]. If you want a real persistent state that survives clicks, focus changes and keyboard navigation, the post itself points to `:checked` with input and label, `:target`, or JavaScript [8]. Its stated fit is narrower: demos, prototypes, playful microinteractions, and temporary highlights that do not need to be true at the state level [9].

What to watch: the post does not discuss browser support for `calc(infinity * 1s)`, nor what happens if the element's computed styles are recalculated while a nominally infinite transition is in flight [13]. Test the latch under a media query change, a class swap on an ancestor, and a framework re-render before you ship it anywhere the highlight is meant to mean something. If it has to mean something, use the checkbox.

Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories