1. css
  2. /view transitions

CSS View Transitions

CSS View Transitions

The View Transitions API provides a way to create smooth transitions between different states of a webpage, whether it's navigating between pages or updating content within the same page.

Browser Support

View Transitions are supported in modern browsers:

  • Chrome 111+
  • Edge 111+
  • Opera 97+
  • Safari 17.2+ (experimental)
  • Firefox (in development)

Basic Concepts

View Transition Process

  1. Capture the old state
  2. Process the new state
  3. Transition between states
/* Enable view transitions */
:root {
  view-transition-name: none;
}

/* Style specific transitions */
.element {
  view-transition-name: element-transition;
}

JavaScript Integration

// Basic page transition
document.startViewTransition(() => {
  // Update the DOM here
  document.body.innerHTML = newContent;
});

// With async operations
async function updateView() {
  const transition = document.startViewTransition(async () => {
    const content = await fetchNewContent();
    document.body.innerHTML = content;
  });
  
  await transition.finished;
}

Practical Examples

Simple Element Transition

.card {
  view-transition-name: card;
}

::view-transition-old(card) {
  animation: fade-out 300ms ease-out;
}

::view-transition-new(card) {
  animation: fade-in 300ms ease-in;
}

@keyframes fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
// Handle navigation
document.addEventListener('click', e => {
  if (e.target.tagName === 'A') {
    e.preventDefault();
    
    document.startViewTransition(async () => {
      const response = await fetch(e.target.href);
      const text = await response.text();
      document.body.innerHTML = text;
      window.history.pushState({}, '', e.target.href);
    });
  }
});
.gallery-image {
  view-transition-name: gallery-image;
}

::view-transition-old(gallery-image),
::view-transition-new(gallery-image) {
  animation: none;
  mix-blend-mode: normal;
}

/* Custom animation for the transition */
::view-transition-image-pair(gallery-image) {
  animation: 300ms ease-in-out both image-fade;
}

@keyframes image-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
function switchImage(newSrc) {
  document.startViewTransition(() => {
    const image = document.querySelector('.gallery-image');
    image.src = newSrc;
  });
}

Advanced Usage

Shared Element Transitions

/* Shared element between views */
.shared-element {
  view-transition-name: shared-element;
}

::view-transition-old(shared-element),
::view-transition-new(shared-element) {
  animation: none;
  mix-blend-mode: normal;
}

::view-transition-image-pair(shared-element) {
  animation: 400ms ease-in-out both scale-up;
}

@keyframes scale-up {
  from {
    transform: scale(0.8);
    opacity: 0;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}

Complex State Changes

async function updateComplexView() {
  const transition = document.startViewTransition(async () => {
    // Remove old content with fade-out
    await animateOut('.old-content');
    
    // Update DOM
    const newContent = await fetchContent();
    updateDOM(newContent);
    
    // Animate new content
    await animateIn('.new-content');
  });
  
  // Handle transition completion
  transition.finished.then(() => {
    console.log('Transition complete');
  });
}

Custom Transition Styles

/* Define different transitions for different screen sizes */
@media (min-width: 768px) {
  ::view-transition-old(root),
  ::view-transition-new(root) {
    animation-duration: 500ms;
    animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  }
}

/* Custom transition for specific elements */
.modal {
  view-transition-name: modal;
}

::view-transition-old(modal) {
  animation: 300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-out;
}

::view-transition-new(modal) {
  animation: 300ms cubic-bezier(0.4, 0, 0.2, 1) both slide-in;
}

Best Practices

1. Performance Optimization

// ✓ Good - Prepare content before transition
async function optimizedTransition() {
  const content = await fetchContent(); // Fetch before transition
  
  document.startViewTransition(() => {
    updateDOM(content); // Quick DOM update
  });
}

// ✗ Bad - Slow transition
document.startViewTransition(async () => {
  const content = await fetchContent(); // Delays transition
  updateDOM(content);
});

2. Progressive Enhancement

// Check for View Transitions support
if (document.startViewTransition) {
  // Use View Transitions
  document.startViewTransition(() => updateDOM());
} else {
  // Fallback behavior
  updateDOM();
}

3. Error Handling

async function safeTransition() {
  try {
    const transition = document.startViewTransition(async () => {
      await updateContent();
    });
    
    await transition.finished;
  } catch (error) {
    console.error('Transition failed:', error);
    // Fallback update
    await updateContent();
  }
}

Common Use Cases

  1. Page Navigation: Smooth transitions between pages
  2. Image Galleries: Transitioning between images
  3. Modal Windows: Animated modal appearances
  4. Content Updates: Smooth content replacements
  5. List Modifications: Animating list changes

Tips and Tricks

1. Debugging Transitions

/* Slow down transitions for debugging */
::view-transition-group(*),
::view-transition-image-pair(*),
::view-transition-old(*),
::view-transition-new(*) {
  animation-duration: 2s !important;
}

2. Custom Animation Timing

/* Define reusable timing variables */
:root {
  --transition-timing: cubic-bezier(0.4, 0, 0.2, 1);
  --transition-duration: 300ms;
}

::view-transition-old(custom),
::view-transition-new(custom) {
  animation-timing-function: var(--transition-timing);
  animation-duration: var(--transition-duration);
}

3. State Management

// Track transition state
let isTransitioning = false;

async function managedTransition() {
  if (isTransitioning) return;
  
  isTransitioning = true;
  
  const transition = document.startViewTransition(async () => {
    await updateContent();
  });
  
  await transition.finished;
  isTransitioning = false;
}

CSS View Transitions provide a powerful way to create smooth, engaging transitions in web applications. They enhance the user experience by making state changes and navigation feel more natural and polished.