使用 JavaScript 和 CSS 创建"动态高亮"导航栏
在本教程中,Blake Lundquist 将带领我们使用纯 JavaScript 和 CSS 实现"动态高亮"导航模式的两种方法。第一种技术使用 getBoundingClientRect 方法,在导航栏项目被点击时显式地动画化边框。第二种方法使用新的 View Transition API 实现相同的功能。
初始标记
假设我们有一个单页面应用,内容变化时页面不会重新加载。起始的 HTML 和 CSS 是标准的导航栏,额外包含一个 id 为 #highlight 的 div 元素。我们给第一个导航项添加.active 类。
#highlight {
z-index: 0;
position: absolute;
height: 100%;
width: 100px;
left: -200px;
border: 2px solid green;
box-sizing: border-box;
transition: all 0.2s ease;
}
复制代码
添加点击事件处理程序
我们希望高亮元素在用户更改.active 导航项时产生动画效果。让我们为 nav 元素添加点击事件处理程序:
const navbar = document.querySelector('nav');
navbar.addEventListener('click', function (event) {
if (!event.target.matches('nav a:not(active)')) {
return;
}
document.querySelector('nav a.active').classList.remove('active');
event.target.classList.add('active');
});
复制代码
移动高亮功能
使用 getBoundingClientRect 获取元素位置和尺寸信息:
const moveHighlight = () => {
const activeNavItem = document.querySelector('a.active');
const highlighterElement = document.querySelector('#highlight');
const width = activeNavItem.offsetWidth;
const itemPos = activeNavItem.getBoundingClientRect();
const navbarPos = navbar.getBoundingClientRect()
const relativePosX = itemPos.left - navbarPos.left;
const styles = {
left: `${relativePosX}px`,
width: `${width}px`,
};
Object.assign(highlighterElement.style, styles);
}
复制代码
使用 View Transition API
对于这种方法,我们不再需要单独的 #highlight 元素:
nav a::after {
content: " ";
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: none;
box-sizing: border-box;
}
nav a.active::after {
border: 2px solid green;
view-transition-name: highlight;
}
复制代码
使用 startViewTransition 方法触发过渡:
navbar.addEventListener('click', async function (event) {
if (!event.target.matches('nav a:not(.active)')) {
return;
}
document.startViewTransition(() => {
document.querySelector('nav a.active').classList.remove('active');
event.target.classList.add('active');
});
});
复制代码
调整视图过渡
为了解决尺寸不一致问题:
::view-transition-old(highlight) {
height: 100%;
}
::view-transition-new(highlight) {
height: 100%;
}
复制代码
最终代码重构
添加回退支持:
const setActiveElement = (elem) => {
document.querySelector('nav a.active').classList.remove('active');
elem.classList.add('active');
}
navbar.addEventListener('click', async function (event) {
if (!event.target.matches('nav a:not(.active)')) {
return;
}
if (!document.startViewTransition) {
setActiveElement(event.target);
return;
}
document.startViewTransition(() => setActiveElement(event.target));
});
复制代码
结论
网站 UI 状态之间的动画和过渡曾经需要大量外部库和复杂代码,但现在 vanilla JavaScript 和 CSS 已经包含了实现类原生应用交互的功能。我们通过两种方法演示了这一点:使用 CSS 过渡结合 getBoundingClientRect()方法,以及使用 View Transition API。
资源
评论