I'm experimenting a smooth tab switch animation using the View Transition API.
In my CodePen example (https://codepen.io/moorthy-g/pen/ByaQZBv), switching from 'Introduction' to 'Technology' is smooth because the tab widths are almost equal. However, switching to 'Storytelling in a Small Village' causes the active element to scale. How can I prevent this scaling behavior and maintain a smooth slide animation for all tab width transitions?
The issue occurs only if the tab widths are different
<div class="content">
<div class="tabs">
<div class="tab active" data-tab="1">Introduction</div>
<div class="tab" data-tab="2">Storytelling in a Small Village</div>
<div class="tab" data-tab="3">Technology</div>
</div>
<div class="tab-content">
<div data-tab-content="1" style="display: block">
<p>Lorem ipsum dolor sit amet.</p>
</div>
<div data-tab-content="2" style="display: none">
<p>In a faraway land, there was a small village.</p>
</div>
<div data-tab-content="3" style="display: none">
<p>Technology has transformed the world.</p>
</div>
</div>
</div>
.tabs {
position: relative;
}
.tab {
padding: 10px;
background-color: #f0f0f0;
cursor: pointer;
position: relative;
z-index: 0;
overflow: hidden;
display: inline-block;
}
.tab:hover {
background-color: #fff;
}
.tab.active {
color: #fff;
}
.tab.active::after {
view-transition-name: tab;
content: "";
position: absolute;
left: 0;
bottom: 0;
width: 100%;
height: 100%;
background-color: #007bff;
z-index: -1;
}
.tab-content {
padding: 20px;
}
::view-transition-group(tab) {
animation-duration: 0.5s;
}
const tabs = document.querySelectorAll(".tab");
const tabContents = document.querySelectorAll(".tab-content > div");
let currentTab = 0;
tabs.forEach((tab, index) => {
tab.addEventListener("click", () => {
currentTab = index;
document.startViewTransition(() => {
tabs.forEach((t, i) => {
if (i === currentTab) {
t.classList.add("active");
} else {
t.classList.remove("active");
}
});
});
tabContents.forEach((tc, i) => {
if (i === currentTab) {
tc.style.display = "block";
} else {
tc.style.display = "none";
}
});
});
});
// Set the first tab as default
document.querySelector(".tab").click();
When view transitions are applied, apart from default cross-fade animation this is what happens:
height
and width
are transitioned using a smooth scaling animationposition
and transform
are transitioned using a smooth movement animationSo in your case you need to disable the height animation by setting a fixed height in both old and new views:
::view-transition-old(tab),
::view-transition-new(tab) {
height: 100%;
}
So only the width is scaled up/down. And the transition looks smooth like this: