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

如何实现类似Valorant官网的响应式头部导航(搜索框适配问题)

复刻Valorant导航的问题解决方案

核心思路

原来的逻辑只计算窗口宽度和右侧固定元素(语言图标、Play Now按钮)的宽度,现在得把搜索框展开后的宽度也纳入导航栏的空间计算。这样当搜索框打开时,只要导航栏总宽度超过窗口宽度,就优先把导航项移去MORE菜单,而不是挤压右侧的元素。

具体改法

  1. 跟踪搜索框的开关状态

    • 加个变量isSearchOpen记录搜索框是否展开,点击搜索图标时切换这个状态,同时给搜索容器加个类(比如.search-open),方便后续计算宽度。
  2. 修改导航项移入移出的判断逻辑

    • 计算导航栏可用于放置导航项的宽度时,要减去右侧固定元素的宽度,再减去搜索框展开后的宽度(如果搜索框处于打开状态)。
    • 当显示的导航项总宽度超过这个可用宽度时,把最右侧的项移去MORE菜单;反过来,当有剩余空间时,把MORE里的项移回导航栏。
  3. 关键代码示例

    • JS部分:

      let isSearchOpen = false;
      const searchIcon = document.querySelector('.search-icon');
      const searchContainer = document.querySelector('.search-container');
      const navItems = document.querySelectorAll('.nav-item');
      const moreMenu = document.querySelector('.more-menu');
      const rightElements = document.querySelector('.right-elements'); // 包含语言图标和Play Now的容器
      
      // 点击搜索图标切换状态,同时调整导航项
      searchIcon.addEventListener('click', () => {
        isSearchOpen = !isSearchOpen;
        searchContainer.classList.toggle('active', isSearchOpen);
        adjustNavItems();
      });
      
      // 窗口大小变化时自动调整导航项
      window.addEventListener('resize', adjustNavItems);
      
      // 调整导航项的核心函数
      function adjustNavItems() {
        const navBarTotalWidth = document.querySelector('.nav-bar').offsetWidth;
        const rightElementsWidth = rightElements.offsetWidth;
        // 搜索框展开时加入它的宽度,否则加0
        const searchOccupiedWidth = isSearchOpen ? searchContainer.offsetWidth : 0;
        // 预留10px间距避免元素挤在一起
        const availableWidthForNav = navBarTotalWidth - rightElementsWidth - searchOccupiedWidth - 10;
      
        let currentNavItemsTotalWidth = 0;
        const visibleItems = [];
        const hiddenItems = [];
      
        // 先统计当前显示的导航项总宽度
        navItems.forEach(item => {
          if (!item.classList.contains('hidden')) {
            currentNavItemsTotalWidth += item.offsetWidth;
            visibleItems.push(item);
          } else {
            hiddenItems.push(item);
          }
        });
      
        // 宽度超了,把最后一个可见项移去MORE菜单
        while (currentNavItemsTotalWidth > availableWidthForNav && visibleItems.length > 0) {
          const lastItem = visibleItems.pop();
          lastItem.classList.add('hidden');
          hiddenItems.unshift(lastItem);
          currentNavItemsTotalWidth -= lastItem.offsetWidth;
          moreMenu.appendChild(lastItem);
        }
      
        // 有多余空间,把MORE里的项移回导航栏
        while (currentNavItemsTotalWidth + (hiddenItems[0]?.offsetWidth || 0) <= availableWidthForNav && hiddenItems.length > 0) {
          const firstHiddenItem = hiddenItems.shift();
          firstHiddenItem.classList.remove('hidden');
          visibleItems.push(firstHiddenItem);
          currentNavItemsTotalWidth += firstHiddenItem.offsetWidth;
          // 将项插回MORE按钮的前面
          const moreBtn = document.querySelector('.more-btn');
          moreBtn.before(firstHiddenItem);
        }
      }
      
      // 页面加载时先执行一次调整
      adjustNavItems();
      
    • CSS部分(固定搜索框展开宽度,防止动态挤压):

      .search-container {
        width: 0;
        overflow: hidden;
        transition: width 0.3s ease;
      }
      .search-container.active {
        width: 200px; /* 参考官网搜索框宽度,可自行调整 */
      }
      

额外提醒

  • 计算元素宽度时,可以用getBoundingClientRect()替代offsetWidth,能更精准地获取元素实际占用的宽度(包括padding、border)。
  • 记得给MORE菜单写好样式,确保移入的导航项能正常显示。
  • 多测试不同窗口尺寸下的表现,尤其是搜索框开关时的过渡效果,保证交互流畅不卡顿。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 10:23:27