Skip to main content
Version: 4.x

On Visible

On Visible animates elements once when they become visible in the viewport. Unlike scroll animations that continuously respond to scroll position, the animation plays once and the element remains in its final state.

How It Works

On Visible uses the Intersection Observer API via a small JavaScript file. When an element with a .on-visible--* class enters the viewport:

  1. The acss-visible class is added to the element
  2. CSS transitions animate from the initial state to the final state
  3. The animation plays once and doesn't reverse when scrolling back

Available Effects

ClassEffect
.on-visible--fadeFades from transparent to opaque
.on-visible--floatFloats up from below
.on-visible--sinkSinks down from above
.on-visible--slide-leftSlides in from the right
.on-visible--slide-rightSlides in from the left
.on-visible--growGrows from a smaller scale
.on-visible--shrinkShrinks from a larger scale
.on-visible--blurStarts blurred, then sharpens

Basic Usage

<div class="on-visible--fade">
This element fades in when it becomes visible
</div>

Composable Effects

Combine multiple On Visible effects:

<div class="on-visible--fade on-visible--float on-visible--grow">
Fades in, floats up, and grows simultaneously
</div>

Animating Children

Use the -all variant to animate direct children:

<div class="on-visible-all--fade on-visible-all--float">
<div>Child 1 animates in</div>
<div>Child 2 animates in</div>
<div>Child 3 animates in</div>
</div>

The animation triggers when the parent becomes visible, and all children animate together.

Timing Settings

Duration and Easing

VariableDefaultDescription
--visible-duration0.6sAnimation duration
--visible-timingvar(--ease-smooth)Easing function
--visible-delay0sDefault delay
.slow-reveal {
--visible-duration: 1s;
--visible-timing: var(--ease-gentle);
}

Visibility Threshold

Control how much of the element must be visible before triggering:

VariableDefaultDescription
--visible-threshold0.2Percentage visible (0-1)
.late-trigger {
--visible-threshold: 0.5; /* Must be 50% visible */
}

Staggered Children

Add .on-visible--stagger to a parent using -all classes to automatically stagger each child's animation:

<div class="on-visible-all--fade on-visible-all--float on-visible--stagger">
<div>Child 1 — animates first</div>
<div>Child 2 — delayed by stagger interval</div>
<div>Child 3 — delayed by 2× stagger interval</div>
</div>

Configure the stagger interval in the dashboard under the Timing section. The default interval is 0.1s.

note

Stagger uses CSS sibling-index(), which has limited browser support. In unsupported browsers, all children animate simultaneously.

Customization

Starting Opacity

For fade effect:

.my-element {
--visible-opacity-start: 0.2; /* Start at 20% opacity instead of fully transparent */
}

Distance

Each movement effect has its own distance variable:

.my-element {
--visible-float-distance: 60px; /* Float distance */
--visible-sink-distance: 60px; /* Sink distance */
--visible-slide-distance: 60px; /* Slide distance */
}

Scale

For grow and shrink effects:

.my-element {
--visible-scale-start: 0.8; /* Grow: start at 80% */
--visible-scale-shrink: 1.2; /* Shrink: start at 120% */
}

Blur

For blur effect:

.my-element {
--visible-blur-amount: 12px;
}

On Visible vs. Entrance Effects

Choose based on your needs:

FeatureOn VisibleEntrance Effects
TriggerOnce when visibleContinuously on scroll
ReversesNoYes (on scroll back)
TechnologyIntersection Observer (JS)Scroll-driven animations (CSS)
Browser SupportAll modern browsersChrome/Edge 115+
Best ForOne-time reveals, content loadingInteractive scroll experiences

When to Use On Visible

  • Content that should "pop in" once
  • Below-the-fold content on load
  • Elements that shouldn't re-animate on scroll back
  • Maximum browser compatibility needed

When to Use Entrance Effects

  • Hero sections with scroll-linked animation
  • Content that should animate both in and out
  • Parallax-style effects
  • Scrubbing/progress-based animations

Staggered Content Example

Create a staggered reveal for a card grid:

<div class="grid on-visible-all--fade on-visible-all--float on-visible--stagger">
<div class="card">Card 1</div>
<div class="card">Card 2</div>
<div class="card">Card 3</div>
<div class="card">Card 4</div>
</div>

Each card automatically receives an increasing delay based on its position — no manual delay classes needed.

Manual Visibility Control

By default, the Intersection Observer automatically adds the acss-visible class when elements scroll into view. For elements where you control visibility yourself — such as menus, modals, or dropdowns — add data-skip-acss-visible to tell the observer to ignore the element entirely.

You then add and remove acss-visible via JavaScript when you're ready to trigger the animation. Removing acss-visible resets the element to its hidden state so the animation replays each time.

Example: Animating Menu Items

Add the effect classes and data-skip-acss-visible to your menu list in the HTML:

<ul class="nav__list on-visible-all--fade on-visible-all--blur on-visible--stagger" data-skip-acss-visible>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/services">Services</a></li>
<li><a href="/contact">Contact</a></li>
</ul>

Then toggle acss-visible in your menu's open/close logic:

const navList = document.querySelector('.nav__list');

function openMenu() {
navList.classList.add('acss-visible');
}

function closeMenu() {
navList.classList.remove('acss-visible');
}

When the menu opens, each list item fades in with a blur-to-sharp transition, staggered one after the other. When the menu closes and acss-visible is removed, the items return to their hidden state so the animation replays on the next open.

tip

data-skip-acss-visible is useful any time elements are already in the DOM but hidden by your own logic (menus, tabs, accordions, modals). The effect classes define the animation — you just control when it fires by toggling acss-visible.

Accessibility

On Visible respects prefers-reduced-motion:

@media (prefers-reduced-motion: reduce) {
[class*="on-visible--"] {
transition: none !important;
opacity: 1;
translate: none;
scale: none;
filter: none;
}
}

Elements appear immediately without animation for users who prefer reduced motion.