You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

技术求助:为Vertical Menu实现跟随选中区域的垂直线效果

实现跟随菜单项的滑动垂直线效果

我完全理解你想要的效果——一条能平滑跟随hover或选中菜单项滑动的垂直线,而不是简单的颜色切换。下面给你两种实现方案,分别适合固定菜单和动态菜单场景:


方案一:纯CSS实现(适合固定数量的菜单)

这种方案不需要JavaScript,通过CSS选择器和过渡动画就能实现滑动效果,代码简洁直观:

HTML代码

<div id="nav">
  <ul>
    <li class="active"><a href="#">Example 1</a></li>
    <li><a href="#">Example 2</a></li>
    <li><a href="#">Example 3</a></li>
    <li><a href="#">Example 4</a></li>
  </ul>
</div>

CSS代码

#nav {
  width: 220px;
  background-color: #f0f0f0;
}

#nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative; /* 作为滑动线的定位基准 */
}

/* 定义滑动垂直线 */
#nav ul::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 4px;
  height: 44px; /* 和单个菜单项高度一致 */
  background-color: #2563eb; /* 你想要的垂直线颜色 */
  transition: top 0.3s ease; /* 0.3秒平滑过渡 */
}

#nav li {
  height: 44px;
  line-height: 44px;
  padding-left: 24px;
  cursor: pointer;
  transition: background-color 0.2s;
}

#nav li:hover {
  background-color: #e5e7eb;
}

#nav li a {
  color: #333;
  text-decoration: none;
  display: block;
}

/* 为每个菜单项hover时设置滑动线位置 */
#nav li:nth-child(1):hover ~ ::before {
  top: 0;
}
#nav li:nth-child(2):hover ~ ::before {
  top: 44px;
}
#nav li:nth-child(3):hover ~ ::before {
  top: 88px;
}
#nav li:nth-child(4):hover ~ ::before {
  top: 132px;
}

/* 保持active项的滑动线位置 */
#nav li.active:nth-child(1) ~ ::before {
  top: 0;
}
#nav li.active:nth-child(2) ~ ::before {
  top: 44px;
}
#nav li.active:nth-child(3) ~ ::before {
  top: 88px;
}
#nav li.active:nth-child(4) ~ ::before {
  top: 132px;
}

方案二:CSS + JavaScript实现(适合动态菜单)

如果你的菜单项是动态生成的,纯CSS方案就不适用了,这时用JS动态计算位置会更灵活:

HTML代码

<div id="nav">
  <ul>
    <!-- 滑动线元素 -->
    <div class="slider"></div>
    <li class="active"><a href="#">Example 1</a></li>
    <li><a href="#">Example 2</a></li>
    <li><a href="#">Example 3</a></li>
    <li><a href="#">Example 4</a></li>
  </ul>
</div>

CSS代码

#nav {
  width: 220px;
  background-color: #f0f0f0;
}

#nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  position: relative;
}

#nav ul .slider {
  position: absolute;
  left: 0;
  width: 4px;
  background-color: #2563eb;
  transition: top 0.3s ease, height 0.3s ease; /* 支持高度和位置的过渡 */
}

#nav li {
  height: 44px;
  line-height: 44px;
  padding-left: 24px;
  cursor: pointer;
  transition: background-color 0.2s;
}

#nav li:hover {
  background-color: #e5e7eb;
}

#nav li a {
  color: #333;
  text-decoration: none;
  display: block;
}

JavaScript代码

const navUl = document.querySelector('#nav ul');
const navItems = navUl.querySelectorAll('li');
const slider = navUl.querySelector('.slider');

// 设置滑动线位置的核心函数
function setSliderPosition(targetItem) {
  const itemRect = targetItem.getBoundingClientRect();
  const ulRect = navUl.getBoundingClientRect();
  // 计算滑动线相对于ul的top值和高度
  slider.style.top = `${itemRect.top - ulRect.top}px`;
  slider.style.height = `${itemRect.height}px`;
}

// 初始化:设置active项的滑动线位置
const initialActiveItem = navUl.querySelector('.active');
if (initialActiveItem) {
  setSliderPosition(initialActiveItem);
}

// 监听每个菜单项的hover事件
navItems.forEach(item => {
  item.addEventListener('mouseover', () => {
    setSliderPosition(item);
  });

  // 点击菜单项时设置active状态
  item.addEventListener('click', (e) => {
    e.preventDefault();
    // 移除所有项的active类
    navItems.forEach(i => i.classList.remove('active'));
    // 给当前项添加active类
    item.classList.add('active');
    // 更新滑动线位置
    setSliderPosition(item);
  });
});

关键原理说明

  1. 定位基准:给ul设置position: relative,让滑动线(绝对定位)以ul为基准定位
  2. 过渡动画:通过transition属性实现滑动线的平滑移动,提升用户体验
  3. 动态计算:JS方案中使用getBoundingClientRect()获取元素的位置和尺寸,确保滑动线能精准匹配任何菜单项

内容的提问来源于stack exchange,提问作者Eugene2018

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:37:43