---
title: "Base rule hides an element; only an `@supports (animation-timeline: …)` block undoes it (lint/scroll-timeline-no-fallback)"
description: "lint/scroll-timeline-no-fallback: `animation-timeline: view()/scroll()`, `view-timeline` and `animation-range` have no fallback: a browser that doesn't…"
canonical: https://void-design.vercel.app/rules/lint/scroll-timeline-no-fallback
lastModified: 2026-09-16
---

# Base rule hides an element; only an `@supports (animation-timeline: …)` block undoes it

`lint/scroll-timeline-no-fallback` · severity **warn** · category Lint · detected by `void lint` and `void audit`

## Why it matters

`animation-timeline: view()/scroll()`, `view-timeline` and `animation-range` have no fallback: a browser that doesn't implement them (Firefox, at every version through 151) evaluates the `@supports` condition as false and drops the whole block, keyframes included. If the resting rule for the same selector sets `opacity: 0`, `visibility: hidden`, a zero scale or a large translate and nothing outside that `@supports` block ever undoes it, the element is invisible forever in that browser — not degraded, gone.

## How to fix it

Keyframes own the from-state: keep the resting rule (outside `@supports`) as the finished, visible state and move the hidden value into `@keyframes`, the way `@utility reveal` in packages/tokens/css/base.css does it. See skills/motion/references/fallbacks.md.

## Example

```css
/* flagged: base rule hides it, only @supports undoes it */
.card { opacity: 0; }
@supports (animation-timeline: view()) {
  .card { animation: reveal linear both; animation-timeline: view(); }
}

/* fixed: resting state is visible; the keyframe owns opacity: 0 */
@supports (animation-timeline: view()) {
  .card { animation: reveal linear both; animation-timeline: view(); }
}
@keyframes reveal { from { opacity: 0; } }
```

## References

- https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timeline
- https://caniuse.com/mdn-css_properties_animation-timeline

## More lint rules

`void lint` reports 67 rules in this category. Static source checks with no browser: Tailwind v4 silent failures, Next.js 16 API traps, React render-body bugs, accessibility markup, SEO files and motion hygiene.

- `transition-all` `transition: all` / `transition-all` — [lint/transition-all](https://void-design.vercel.app/rules/lint/transition-all)
- `animate-layout-prop` Animation of layout properties (width/height/top/left/margin/padding) — [lint/animate-layout-prop](https://void-design.vercel.app/rules/lint/animate-layout-prop)
- `outline-none-no-replacement` Focus outline removed without a visible replacement — [lint/outline-none-no-replacement](https://void-design.vercel.app/rules/lint/outline-none-no-replacement)
- `scale-zero-entry` Element enters from `scale(0)` — [lint/scale-zero-entry](https://void-design.vercel.app/rules/lint/scale-zero-entry)
- `ease-in-enter` `ease-in` used for an entrance or hover — [lint/ease-in-enter](https://void-design.vercel.app/rules/lint/ease-in-enter)
- `long-ui-duration` UI feedback transition longer than 500ms — [lint/long-ui-duration](https://void-design.vercel.app/rules/lint/long-ui-duration)
- `no-reduced-motion` Animations present but no `prefers-reduced-motion` handling anywhere — [lint/no-reduced-motion](https://void-design.vercel.app/rules/lint/no-reduced-motion)
- `overflow-x-hidden-sticky` `overflow-x: hidden` on html/body/root wrapper breaks `position: sticky` — [lint/overflow-x-hidden-sticky](https://void-design.vercel.app/rules/lint/overflow-x-hidden-sticky)

Detected by `void lint` and `void audit`. Explain it in a terminal: `void rules lint/scroll-timeline-no-fallback`
