Skip to content

devsandeepsharma/Glassy-Blog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

3 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Glassy Blog

A simple dark/light mode toggle with a smooth circular zoom animation, made using the View Transition API, vanilla HTML, and CSS. No frameworks, no libraries โ€” just pure frontend experimentation.


How the View Transition API Works

The View Transition API captures the "before" and "after" snapshots of the DOM and lets you animate between them.

Step-by-step:

  1. startViewTransition() captures the current UI (snapshot A).
  2. Inside its callback, you update the DOM (e.g., toggle dark mode).
  3. Browser takes another snapshot (snapshot B).
  4. It animates from A โžก๏ธ B using ::view-transition-old(root) and ::view-transition-new(root) pseudo-elements.

It's like diffing the UI and animating the change โ€” super clean!


How to Use the View Transition API for Theme Toggle

Want to create a smooth, animated theme switch like Telegram? Here's a breakdown of how to implement the View Transition API step-by-step โ€” with fallback support and a clean circular animation.

1๏ธ. Add Fallback Support

This API doesnโ€™t work in Firefox or for users who prefer reduced motion. So, always add a fallback to keep the theme toggle functional:

if (!document.startViewTransition || window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
    body.classList.toggle('dark-mode');
    return;
}

2๏ธ. Calculate Button Center

We want the animation to expand from where the user clicked. So first, find the center of the toggle button:

const { top, left, width, height } = button.getBoundingClientRect();
const x = left + width / 2;
const y = top + height / 2;

3๏ธ. Calculate Max Radius

To make sure the animation fully covers the screen, calculate the maximum radius required:

const right = window.innerWidth - left;
const bottom = window.innerHeight - top;
const maxRadius = Math.hypot(Math.max(left, right), Math.max(top, bottom));

4๏ธ. Trigger the DOM Update Inside View Transition

Now we use the View Transition API to apply the theme change inside a transition. This lets the browser capture the before/after states and animate between them.

await document.startViewTransition(() => {
    body.classList.toggle('dark-mode');
}).ready;

5๏ธ. Animate the New Snapshot

Now apply a circular clip-path animation on the new visual state (pseudo element) starting from the button center:

document.documentElement.animate(
    {
        clipPath: [
            `circle(0px at ${x}px ${y}px)`,
            `circle(${maxRadius}px at ${x}px ${y}px)`,
        ],
    },
    {
        duration: 500,
        easing: 'ease-in-out',
        pseudoElement: '::view-transition-new(root)',
    }
);

6๏ธ. Add CSS for View Transition Elements

Donโ€™t forget this part. Without this, your animation might get unexpected behavior or blend weirdly:

/* Required for View Transition to behave as expected */
::view-transition-old(root),
::view-transition-new(root) {
    animation: none;
    mix-blend-mode: normal;
}

Useful Resources

Preview

About

A simple dark/light mode toggle with a smooth circular zoom animation ๐Ÿ’•๐Ÿ’•

Topics

Resources

Stars

Watchers

Forks