使用JavaScript和CSS创建"移动高亮"导航栏

本文详细介绍了两种创建"移动高亮"导航栏的方法:第一种使用getBoundingClientRect方法实现精确动画,第二种利用新兴的View Transition API简化实现过程,展示了现代前端开发中实现流畅动画的技术演进。

使用JavaScript和CSS创建"移动高亮"导航栏

在本教程中,Blake Lundquist将带我们学习使用纯JavaScript和CSS创建"移动高亮"导航栏的两种方法。第一种技术使用getBoundingClientRect方法在导航项被点击时显式地动画化边框。第二种方法使用新的View Transition API实现相同的功能。

初始标记

假设我们有一个单页应用,内容变化时页面不会重新加载。起始HTML和CSS是标准的导航栏,额外包含一个id为#highlight的div元素。我们给第一个导航项添加.active类。

1
2
3
4
5
6
7
<nav>
  <div id="highlight"></div>
  <a href="#" class="active">Home</a>
  <a href="#services">Services</a>
  <a href="#about">About</a>
  <a href="#contact">Contact</a>
</nav>

添加点击事件处理程序

我们希望当用户改变.active导航项时,高亮元素能够动画移动。我们为nav元素添加点击事件处理程序,然后过滤仅由匹配我们选择器的元素触发的事件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
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,我们可以获取元素位置和大小的信息。我们计算活动导航项的宽度及其相对于父元素左边界的偏移量,然后将样式分配给高亮元素。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
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

View Transition API提供了在网站视图之间创建动画过渡的功能。对于这种方法,我们不再需要单独的#highlight元素,而是可以直接使用伪选择器来样式化.active导航项。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
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;
}

触发视图过渡

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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状态之间的动画和过渡曾经需要大量外部库,但现在原生JavaScript和CSS已经包含了实现类似原生应用交互的功能。我们通过两种方法实现了"移动高亮"导航模式:结合CSS过渡和getBoundingClientRect()方法,以及使用View Transition API。

资源

  • getBoundingClientRect()方法文档
  • View Transition API文档
  • Jake Archibald的"视图过渡:处理宽高比变化"
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计