Skip to content

Framework7 Animations and Transitions — Motion Effects, Page Transitions, and Custom Animations

DodaTech Updated 2026-06-28 7 min read

In this tutorial, you will learn about Framework7 Animations and Transitions. We cover key concepts, practical examples, and best practices to help you master this topic.

Framework7 provides built-in page transitions (fade, slide, parallax, flip), CSS animation utilities, animated page elements, and smooth scrolling — all hardware-accelerated for mobile performance.

What You'll Learn

  • Built-in page transition types
  • Custom CSS animations
  • Parallax and scroll effects
  • Animated page elements
  • Transition events and timing
  • Performance optimization

Why It Matters

Smooth animations make mobile apps feel native. Framework7 transitions between pages use hardware-accelerated CSS transforms, while custom animations add polish to loading states, notifications, and UI interactions.

Real-World Use

A news reader app with parallax scrolling effects on article images, fade transitions between sections, animated loading skeletons, and smooth scroll-to-top on the navigation bar tap.

Animation Architecture

flowchart TD
    A[Animations] --> B[Page Transitions]
    A --> C[CSS Animations]
    A --> D[Parallax]
    A --> E[Smooth Scroll]
    B --> F[Slide]
    B --> G[Fade]
    B --> H[Parallax]
    B --> I[Flip]
    C --> J[Keyframes]
    C --> K[Transitions]
    D --> L[Scroll Effects]
    E --> M[Scroll To Top]
    style A fill:#e6f3ff,stroke:#4a90d9,stroke-width:2px

Page Transitions

// Configure default transitions
var app = new Framework7({
  // Default page transition
  iosPageTransition: 'slide',  // 'slide', 'fade', 'parallax', 'flip'
  materialPageTransition: 'fade', // 'fade', 'flip', 'cover-v', 'cover-h'
});

// Override per navigation
mainView.router.navigate('/page1/', { transition: 'fade' });
mainView.router.navigate('/page2/', { transition: 'parallax' });
mainView.router.navigate('/page3/', { transition: 'flip' });
mainView.router.navigate('/page4/', { transition: 'cover-v' });
mainView.router.navigate('/page5/', { transition: 'cover-h' });

// Disable transition for specific navigation
mainView.router.navigate('/page/', { animate: false });

// Custom transition duration
mainView.router.navigate('/page/', {
  transition: 'slide',
  transitionDuration: 500 // ms
});

Expected output: Pages transition with the specified animation type. iOS defaults to slide (left-to-right push). Material defaults to fade. Each transition type has a unique visual effect.

Transition Events

// Page transition animation events
$$(document).on('page:beforein', '.page', function(e) {
  var page = e.detail.page;
  console.log('Page entering:', page.name);
  // Start entry animation for page elements
  animatePageContent(page);
});

$$(document).on('page:afterin', '.page', function(e) {
  console.log('Page fully entered:', e.detail.page.name);
  // Animation complete, remove loading states
});

$$(document).on('page:beforeout', '.page', function(e) {
  console.log('Page leaving:', e.detail.page.name);
  // Clean up animations
});

$$(document).on('page:afterout', '.page', function(e) {
  console.log('Page fully left:', e.detail.page.name);
});

function animatePageContent(page) {
  // Animate elements sequentially
  $$(page.el).find('.animate-item').each(function(index, el) {
    $$(el)
      .css('transition-delay', (index * 100) + 'ms')
      .addClass('animated-in');
  });
}

Expected output: Elements inside the page animate with staggered delays when the page enters. Transition events synchronize custom animations with the page transition.

Custom CSS Animations

/* Keyframe animation */
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
  20%, 40%, 60%, 80% { transform: translateX(5px); }
}

@keyframes slideInRight {
  from { transform: translateX(100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

/* Animation utility classes */
.animate-fade-in-up {
  animation: fadeInUp 0.5s ease forwards;
  opacity: 0;
}

.animate-pulse {
  animation: pulse 2s ease-in-out infinite;
}

.animate-shake {
  animation: shake 0.5s ease-in-out;
}

.animate-slide-in-right {
  animation: slideInRight 0.4s ease forwards;
}

/* Staggered animation delays */
.stagger-1 { animation-delay: 0.1s; }
.stagger-2 { animation-delay: 0.2s; }
.stagger-3 { animation-delay: 0.3s; }
.stagger-4 { animation-delay: 0.4s; }
.stagger-5 { animation-delay: 0.5s; }
<div class="page-content">
  <div class="block animate-fade-in-up stagger-1">
    <h2>Welcome</h2>
  </div>
  <div class="block animate-fade-in-up stagger-2">
    <p>This content fades in with staggered delay.</p>
  </div>
  <div class="card animate-fade-in-up stagger-3">
    <div class="card-content card-content-padding">
      <p>Each card animates in sequence.</p>
    </div>
  </div>
</div>

Expected output: Elements animate with fadeInUp effect, each appearing 100ms after the previous one, creating a cascade effect as the page loads.

Parallax Scrolling

<div class="page">
  <div class="page-content">
    <!-- Parallax hero image -->
    <div class="parallax">
      <div class="parallax-image" style="background-image:url(https://picsum.photos/800/400)"></div>
    </div>
    <!-- Content that scrolls over the parallax -->
    <div class="block block-strong">
      <h2>Mountain View</h2>
      <p>The parallax image above moves slower than the scroll, creating depth.</p>
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
      <p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
      <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
    </div>
  </div>
</div>
// Parallax is enabled by default on images with the parallax class
// The parallax-image moves at a slower rate than the scroll

// Programmatic parallax
app.parallax.create({
  el: '.parallax',
  // Speed relative to scroll: 0.1 - 0.9 (lower = slower)
  speed: 0.3
});

// Parallax events
$$(document).on('parallax:scroll', '.parallax', function(e) {
  var progress = e.detail.progress;
  console.log('Parallax scroll progress:', progress);
});

Expected output: The hero image moves slower than the scrolling content, creating a depth effect. The parallax speed controls how much slower the image moves.

Scroll Animations

// Animate elements on scroll using IntersectionObserver
function setupScrollAnimations() {
  var observer = new IntersectionObserver(function(entries) {
    entries.forEach(function(entry) {
      if (entry.isIntersecting) {
        entry.target.classList.add('scroll-animated');
        observer.unobserve(entry.target);
      }
    });
  }, { threshold: 0.2 });

  $$('.scroll-animate').each(function() {
    observer.observe(this);
  });
}

// Smooth scroll to element
$$('.scroll-to-top').on('click', function() {
  app.utils.scrollTo(0, 0, 300); // x, y, duration
});

$$('.scroll-to-section').on('click', function() {
  var target = $$('#section-2');
  if (target.length) {
    app.utils.scrollTo(0, target.offset().top - 50, 400);
  }
});
.scroll-animate {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.scroll-animate.scroll-animated {
  opacity: 1;
  transform: translateY(0);
}

Expected output: Elements with the scroll-animate class fade in as they enter the viewport during scrolling. The scroll-to functionality smoothly moves to specified positions.

Animated Icons and Loading States

<!-- Animated loading skeleton -->
<div class="skeleton-text skeleton-effect-fade" id="loading-skeleton">
  <div class="skeleton-text-line"></div>
  <div class="skeleton-text-line"></div>
  <div class="skeleton-text-line" style="width:60%"></div>
</div>

<!-- Spinner animations -->
<div class="preloader"></div>
<div class="preloader preloader-color-blue"></div>

<!-- Animated icon (Material ripple) -->
<div class="ripple">Tap for ripple effect</div>

<!-- Skeleton blocks -->
<div class="skeleton-block skeleton-effect-blink" style="height:200px;margin:16px"></div>
// Show skeleton while loading
$$('#loading-skeleton').show();
fetch('/api/data')
  .then(function(res) { return res.json(); })
  .then(function(data) {
    $$('#loading-skeleton').hide();
    // Render actual data
  });

Expected output: Skeleton loaders show animated placeholders while data loads. Preloaders spin continuously. Ripple effects appear on tap.

Performance Optimization

// Disable animations on low-end devices
if (app.device.android && app.device.androidVersion < 8) {
  app.params.animate = false;
}

// Reduce motion based on user preference
var prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
if (prefersReducedMotion.matches) {
  app.params.animate = false;
  document.documentElement.classList.add('reduce-motion');
}

// Use transform3d for GPU acceleration
// Framework7 uses translate3d by default for page transitions

// Limit animation duration
app.params.iosPageTransitionDuration = 300;
app.params.materialPageTransitionDuration = 250;

// Debounce scroll handlers
function debounce(fn, delay) {
  var timer;
  return function() {
    clearTimeout(timer);
    timer = setTimeout(fn, delay);
  };
}

window.addEventListener('scroll', debounce(function() {
  // Expensive scroll calculations
}, 100));
/* Reduce motion preference */
.reduce-motion *,
.reduce-motion *::before,
.reduce-motion *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
}

Expected output: Animations are disabled on low-end devices and when the user prefers reduced motion. GPU acceleration ensures smooth transitions on capable devices.

Common Mistakes

  1. Animating layout properties - Animating width, height, or margin triggers layout recalculations. Use transform and opacity for GPU-accelerated animations.

  2. Overusing animations - Too many simultaneous animations cause jank on mobile. Limit to 2-3 concurrent animations and use will-change for complex ones.

  3. Not respecting reduced motion - Users with vestibular disorders can experience discomfort from animations. Always check prefers-reduced-motion.

  4. Forgetting animation-fill-mode - Elements animated from hidden states need animation-fill-mode: forwards or initial opacity: 0 to prevent flashing.

  5. Ignoring transition events for cleanup - Use page:afterout or animationend events to clean up animated elements and prevent memory leaks.

Practice Questions

  1. What page transition types does Framework7 support?
  2. How do you add staggered animation delays to page elements?
  3. What is the purpose of the parallax component?
  4. How do you create scroll-triggered animations?
  5. How do you optimize animations for low-end devices?

Challenge: Build a landing page with: a parallax hero image with scroll speed 0.3, staggered fade-in animations for content sections, scroll-triggered element reveals using IntersectionObserver, a loading skeleton while data fetches, smooth scroll-to-top button, and reduced-motion support that disables all animations.

FAQ

Are Framework7 animations GPU-accelerated?

Yes. Framework7 uses CSS transforms (translate3d) and opacity for all page transitions, which are GPU-accelerated in modern browsers.

Can I create custom page transitions?

Yes. Override the CSS transition classes (.router-transition-forward, .router-transition-backward) with your own CSS transitions and keyframes.

How do I animate between routes in a tabbed view?

Tab transitions use the same router animations. Configure transition types per tab or use the default page transition.

How do I disable specific component animations (like accordion)?

Set animate: false on the specific component config, or use CSS to set transition-duration: 0 on that component's animations.

Do animations work with Framework7 React/Vue?

Yes. Page transitions, parallax, and CSS animations work identically in all Framework7 integrations.

Mini Project

Build an animated product showcase app with: a parallax hero section for each product, staggered fade-in of product details, scroll-triggered feature reveals, a loading skeleton simulating API fetch, smooth page transitions (parallax between sections), a "sold out" shake animation on the buy button, reduced-motion support, and performance optimizations for low-end devices.

What's Next

Animations make apps feel polished. Learn how Framework7 PWA and Service Workers make your app installable and work offline.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro