16 CSS Fade In Animation Designs05 / 16

CSS + JSMIT licensed

Scroll-Triggered Observer Fade

An activity feed list where items observe viewport entry via IntersectionObserver and acquire a .fi-05--visible class, triggering CSS transitions to slide and fade in staggered.

Published

Live Demo
Try it

The code

<div class="fi-05" id="fi-05-root">
  <div class="fi-05__title">Activity Feed</div>
  <div class="fi-05__items">
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">Deployment successful</div><div class="fi-05__meta">production · 2 min ago</div></div><span class="fi-05__badge">Live</span></div>
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">Pull request merged</div><div class="fi-05__meta">feature/auth · 14 min ago</div></div><span class="fi-05__badge">Done</span></div>
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">Build failed on main</div><div class="fi-05__meta">CI pipeline · 1 hr ago</div></div><span class="fi-05__badge">Error</span></div>
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">New user signup spike</div><div class="fi-05__meta">analytics · 3 hr ago</div></div><span class="fi-05__badge">Alert</span></div>
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">Database backup complete</div><div class="fi-05__meta">storage · 6 hr ago</div></div><span class="fi-05__badge">Done</span></div>
  </div>
</div>
.fi-05 {
  --bg: #0b1120;
  --sky: #38bdf8;
  --emerald: #34d399;
  --rose: #fb7185;
  --text: #f0f9ff;
  font-family: 'Inter',sans-serif;
  min-height: 360px;
  border-radius: 20px;
  padding: 32px;
  overflow: hidden;
}

.fi-05 *,
.fi-05 *::before,
.fi-05 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.fi-05 ::selection {
  background: var(--sky);
  color: #000;
}

.fi-05__title {
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: rgba(240,249,255,.35);
  margin-bottom: 24px;
}

.fi-05__items {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* Items start hidden; JS adds .fi-05--visible via IntersectionObserver */

.fi-05__item {
  display: flex;
  gap: 16px;
  align-items: center;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.07);
  border-radius: 12px;
  padding: 16px 20px;
  opacity: 0;
  transform: translateX(-24px);
  transition: opacity .6s cubic-bezier(.16,1,.3,1),transform .6s cubic-bezier(.16,1,.3,1);
}

.fi-05__item.fi-05--visible {
  opacity: 1;
  transform: translateX(0);
}

.fi-05__item:hover {
  background: rgba(255,255,255,.06);
  border-color: rgba(56,189,248,.2);
}

.fi-05__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.fi-05__item:nth-child(1) .fi-05__dot {
  background: var(--sky);
  box-shadow: 0 0 8px rgba(56,189,248,.5);
}

.fi-05__item:nth-child(2) .fi-05__dot {
  background: var(--emerald);
  box-shadow: 0 0 8px rgba(52,211,153,.5);
}

.fi-05__item:nth-child(3) .fi-05__dot {
  background: var(--rose);
  box-shadow: 0 0 8px rgba(251,113,133,.5);
}

.fi-05__item:nth-child(4) .fi-05__dot {
  background: var(--sky);
  box-shadow: 0 0 8px rgba(56,189,248,.5);
}

.fi-05__item:nth-child(5) .fi-05__dot {
  background: var(--emerald);
  box-shadow: 0 0 8px rgba(52,211,153,.5);
}

.fi-05__body {
  flex: 1;
}

.fi-05__name {
  font-size: .9rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 3px;
}

.fi-05__meta {
  font-size: .75rem;
  color: rgba(240,249,255,.4);
}

.fi-05__badge {
  font-size: .68rem;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 8px;
}

.fi-05__item:nth-child(1) .fi-05__badge {
  background: rgba(56,189,248,.15);
  color: var(--sky);
}

.fi-05__item:nth-child(2) .fi-05__badge {
  background: rgba(52,211,153,.15);
  color: var(--emerald);
}

.fi-05__item:nth-child(3) .fi-05__badge {
  background: rgba(251,113,133,.15);
  color: var(--rose);
}

.fi-05__item:nth-child(4) .fi-05__badge {
  background: rgba(56,189,248,.15);
  color: var(--sky);
}

.fi-05__item:nth-child(5) .fi-05__badge {
  background: rgba(52,211,153,.15);
  color: var(--emerald);
}

@media (prefers-reduced-motion: reduce) {
  .fi-05__item {
    transition: none;
    opacity: 1;
    transform: none;
  }
}
(function(){
  const items = document.querySelectorAll('#fi-05-root .fi-05__item');
  const obs = new IntersectionObserver((entries)=>{
    entries.forEach(e=>{
      if(e.isIntersecting){
        const el = e.target;
        const idx = [...items].indexOf(el);
        setTimeout(()=>el.classList.add('fi-05--visible'), idx * 100);
        obs.unobserve(el);
      }
    });
  },{threshold:0.2});
  items.forEach(el=>obs.observe(el));
})();
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Fade In Animation Design from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Scroll-Triggered Observer Fade
Source: https://codefronts.com/motion/css-fade-in-animation/scroll-triggered-observer-fade/

An activity feed list where items observe viewport entry via IntersectionObserver and acquire a .fi-05--visible class, triggering CSS transitions to slide and fade in staggered.
## HTML
```html
<div class="fi-05" id="fi-05-root">
  <div class="fi-05__title">Activity Feed</div>
  <div class="fi-05__items">
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">Deployment successful</div><div class="fi-05__meta">production · 2 min ago</div></div><span class="fi-05__badge">Live</span></div>
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">Pull request merged</div><div class="fi-05__meta">feature/auth · 14 min ago</div></div><span class="fi-05__badge">Done</span></div>
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">Build failed on main</div><div class="fi-05__meta">CI pipeline · 1 hr ago</div></div><span class="fi-05__badge">Error</span></div>
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">New user signup spike</div><div class="fi-05__meta">analytics · 3 hr ago</div></div><span class="fi-05__badge">Alert</span></div>
    <div class="fi-05__item"><div class="fi-05__dot"></div><div class="fi-05__body"><div class="fi-05__name">Database backup complete</div><div class="fi-05__meta">storage · 6 hr ago</div></div><span class="fi-05__badge">Done</span></div>
  </div>
</div>
```
## CSS
```css
.fi-05 {
  --bg: #0b1120;
  --sky: #38bdf8;
  --emerald: #34d399;
  --rose: #fb7185;
  --text: #f0f9ff;
  font-family: 'Inter',sans-serif;
  min-height: 360px;
  border-radius: 20px;
  padding: 32px;
  overflow: hidden;
}

.fi-05 *,
.fi-05 *::before,
.fi-05 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.fi-05 ::selection {
  background: var(--sky);
  color: #000;
}

.fi-05__title {
  font-size: .75rem;
  font-weight: 600;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: rgba(240,249,255,.35);
  margin-bottom: 24px;
}

.fi-05__items {
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* Items start hidden; JS adds .fi-05--visible via IntersectionObserver */

.fi-05__item {
  display: flex;
  gap: 16px;
  align-items: center;
  background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.07);
  border-radius: 12px;
  padding: 16px 20px;
  opacity: 0;
  transform: translateX(-24px);
  transition: opacity .6s cubic-bezier(.16,1,.3,1),transform .6s cubic-bezier(.16,1,.3,1);
}

.fi-05__item.fi-05--visible {
  opacity: 1;
  transform: translateX(0);
}

.fi-05__item:hover {
  background: rgba(255,255,255,.06);
  border-color: rgba(56,189,248,.2);
}

.fi-05__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex-shrink: 0;
}

.fi-05__item:nth-child(1) .fi-05__dot {
  background: var(--sky);
  box-shadow: 0 0 8px rgba(56,189,248,.5);
}

.fi-05__item:nth-child(2) .fi-05__dot {
  background: var(--emerald);
  box-shadow: 0 0 8px rgba(52,211,153,.5);
}

.fi-05__item:nth-child(3) .fi-05__dot {
  background: var(--rose);
  box-shadow: 0 0 8px rgba(251,113,133,.5);
}

.fi-05__item:nth-child(4) .fi-05__dot {
  background: var(--sky);
  box-shadow: 0 0 8px rgba(56,189,248,.5);
}

.fi-05__item:nth-child(5) .fi-05__dot {
  background: var(--emerald);
  box-shadow: 0 0 8px rgba(52,211,153,.5);
}

.fi-05__body {
  flex: 1;
}

.fi-05__name {
  font-size: .9rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 3px;
}

.fi-05__meta {
  font-size: .75rem;
  color: rgba(240,249,255,.4);
}

.fi-05__badge {
  font-size: .68rem;
  font-weight: 700;
  padding: 3px 10px;
  border-radius: 8px;
}

.fi-05__item:nth-child(1) .fi-05__badge {
  background: rgba(56,189,248,.15);
  color: var(--sky);
}

.fi-05__item:nth-child(2) .fi-05__badge {
  background: rgba(52,211,153,.15);
  color: var(--emerald);
}

.fi-05__item:nth-child(3) .fi-05__badge {
  background: rgba(251,113,133,.15);
  color: var(--rose);
}

.fi-05__item:nth-child(4) .fi-05__badge {
  background: rgba(56,189,248,.15);
  color: var(--sky);
}

.fi-05__item:nth-child(5) .fi-05__badge {
  background: rgba(52,211,153,.15);
  color: var(--emerald);
}

@media (prefers-reduced-motion: reduce) {
  .fi-05__item {
    transition: none;
    opacity: 1;
    transform: none;
  }
}
```

## JavaScript
```js
(function(){
  const items = document.querySelectorAll('#fi-05-root .fi-05__item');
  const obs = new IntersectionObserver((entries)=>{
    entries.forEach(e=>{
      if(e.isIntersecting){
        const el = e.target;
        const idx = [...items].indexOf(el);
        setTimeout(()=>el.classList.add('fi-05--visible'), idx * 100);
        obs.unobserve(el);
      }
    });
  },{threshold:0.2});
  items.forEach(el=>obs.observe(el));
})();
```

How this works

Each .fi-05__item starts with opacity: 0; transform: translateX(-24px) and two CSS transition properties on opacity and transform. JavaScript creates an IntersectionObserver with threshold: 0.2 — the callback fires when 20% of the element enters the viewport. Inside the callback, a setTimeout indexed by the item's position in the NodeList adds 100ms × index before appending .fi-05--visible, which sets opacity: 1; transform: translateX(0).

This approach is superior to pure CSS animation for scroll content: animations only trigger when the user actually scrolls to the element, and each item animates exactly once (the observer calls unobserve after triggering). Without JS, items remain at opacity: 0 — to degrade gracefully, add a .no-js .fi-05__item { opacity: 1; transform: none } rule.

Make it yours

  • Reduce the threshold in IntersectionObserver from 0.2 to 0.05 to trigger earlier.
  • Increase the per-item stagger from 100ms to 150ms for a more dramatic cascade.
  • Add a reverse animation on IntersectionObserver isIntersecting: false to re-hide items on scroll-out.
  • Change the transition direction from translateX(-24px) to translateY(20px) for a bottom-up reveal.

Gotchas — read before shipping

  • If the component mounts outside the viewport (e.g. in a modal), IntersectionObserver won't fire until the modal opens and the element enters the viewport — this is the desired behaviour, but test for it.
  • The !important override on hover requires the hover rule to be more specific than the animation's fill-mode, or use a JS class toggle instead.
  • Without calling obs.unobserve(el) after triggering, the observer fires again on every scroll intersection, re-triggering the animation each time the element enters and leaves the viewport.

Browser support

ChromeSafariFirefoxEdge
58+12.1+55+58+

IntersectionObserver requires polyfill for IE11 and older Safari

Techniques used in this demo

Search CodeFronts

Loading…