@supports
guard, and no guard can leave an element invisible: the hidden state is only
ever declared inside the block that also says how it comes back.
The full table
“not yet” is true at the time of writing and is the entry most likely to change.
Check caniuse before relying on it.
Safari, specifically
Three things worth knowing if Safari is a first-class target.Scroll-driven animations do not exist yet
Scroll-driven animations do not exist yet
Safari has no
animation-timeline. Every tm-scroll-* class is inside
@supports (animation-timeline: view()), so in Safari not one declaration
applies and the section is ordinary, fully visible content.This is the strongest argument for the CSS approach over an
IntersectionObserver: an observer-based reveal has to hide the content
first and then hope its JavaScript runs.17.4 and 17.5 differ by one frame
17.4 and 17.5 differ by one frame
transition-behavior: allow-discrete shipped in Safari 17.4;
@starting-style shipped in 17.5. TailMotion guards both on the former,
because the two shipped together in Chrome and Firefox.In Safari 17.4 exactly, native exits animate and a panel mounted
already-open appears instead of animating in. Nothing breaks; one frame is
missing.::backdrop inheritance is recent
::backdrop inheritance is recent
::backdrop only started inheriting custom properties from its originating
element in Chrome 122, Firefox 123 and Safari 17.4. Older engines resolve
var() there against nothing.Every fallback in the tm-native-dialog backdrop rules is therefore a
literal matching the dialog’s own unscaled default, so the dialog and its
backdrop stay in step either way. Set --tm-backdrop-duration to pin it
explicitly.tm-view-morphskips its live blur on touch-first devices (@media (hover: none) and (pointer: coarse)), because Safari rasterizes it even on hidden panels.- No blur in the library exceeds 8px. Large blur radii are expensive everywhere and worst in Safari.
How the guards are verified
opacity: 0 or visibility: hidden outside an
@supports guard, without a closed-state selector, and outside the small
allowlist of two-face recipes where the counterpart is always visible.
That is what makes “no guard can leave an element invisible” a checked property
rather than a promise.
Cascade layers
TailMotion’s rules live in native@layer base and @layer utilities.
This only matters where both fight over the same property —
opacity-0 on a
tm-presence-* panel is the realistic case. Let TailMotion own opacity,
translate, scale and visibility on an element it is animating, and the
question never comes up.Not supported
@supports itself, CSS custom properties, and cascade layers are hard
requirements. In practice that means Chrome 99+, Safari 15.4+ and Firefox 97+.
Below that, the stylesheet parses but the @layer blocks are discarded and no
class applies — content stays visible and unstyled by TailMotion, which is the
correct failure mode.