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

Svelte中W3C响应式菜单窄屏时无法显示垂直菜单项

Svelte中W3C响应式菜单窄屏时无法显示垂直菜单项

我太懂你这种挫败感了——把W3C官网好好的响应式菜单搬到Svelte里,结果窄屏模式下点汉堡按钮,菜单就是不出来,甚至在Playground里点一下还会刷新页面,折腾半天找不到问题在哪!别着急,咱们一步步来解决:

第一个问题:汉堡按钮点击导致页面刷新

你代码里的汉堡按钮用的是<a href="#">,默认情况下点击a标签会触发页面跳转(哪怕是#也会触发滚动或刷新),这就是Playground里页面刷新的原因。解决办法很简单,要么阻止默认行为,要么干脆把a标签换成更合适的button:

方案1:阻止a标签默认行为

修改汉堡按钮的onclick事件,加上event.preventDefault():

<a href="#" class="icon" onclick={(event) => {
  event.preventDefault();
  myFunction();
}}>&#9776</a>

方案2:换成button标签(更推荐,因为这是按钮行为)

把a标签改成button,然后调整样式去掉默认按钮的边框、背景:

<button class="icon" onclick={myFunction}>&#9776</button>

然后在style里给button.icon加样式:

.topnav .icon {
  display: none;
  border: none;
  background: transparent;
  cursor: pointer;
}

第二个问题:DOM操作的可靠性问题

你用document.getElementById("myTopnav")来获取元素,在Svelte里有时候会遇到DOM还没渲染完成就执行代码的情况,导致获取不到元素。咱们用Svelte自带的元素绑定来替代,更可靠:

  1. 在topnav元素上绑定变量:
<div class="topnav" bind:this={topnav}>
  1. 在script里声明变量,然后修改myFunction:
<script>
  let topnav; // 绑定的DOM元素

  function myFunction() {
    if (!topnav) return; // 防止元素未加载
    topnav.classList.toggle("responsive"); // 直接用toggle简化代码,不用判断加/减
    console.log(topnav.className);
  }
</script>

这里用classList.toggle()还能简化你的判断逻辑,一行代码搞定添加/移除类。

第三个问题:确认CSS样式是否正确生效

检查你的媒体查询样式,确保.topnav.responsive相关的样式能正确覆盖窄屏时的display:none。你现有的CSS看起来是对的,但如果还是有问题,可以把样式放到Svelte的全局样式文件里(比如app.css),或者在组件样式里用:global()包裹(不过一般组件内的样式只要元素在组件里就没问题)。

修改后的完整代码示例

<div class="topnav" bind:this={topnav}>
  <a href="#home" class="active">Home</a>
  <a href="#news">News</a>
  <a href="#contact">Contact</a>
  <div class="dropdown">
    <button class="dropbtn">Dropdown 
      <i class="fa fa-caret-down"></i>
    </button>
    <div class="dropdown-content">
      <a href="#">Link 1</a>
      <a href="#">Link 2</a>
      <a href="#">Link 3</a>
    </div>
  </div> 
  <a href="#about">About</a>
  <!-- 用阻止默认行为的a标签 -->
  <a href="#" class="icon" onclick={(event) => {
    event.preventDefault();
    myFunction();
  }}>&#9776</a>
</div>

<script>
  let topnav;

  function myFunction() {
    if (!topnav) return;
    topnav.classList.toggle("responsive");
    console.log(topnav.className);
  }
</script>

<style>
  .topnav {
    overflow: hidden;
    background-color: #333;
  }

  .topnav a {
    font-size: 17px;
    float: left;
    display: block;
    color: #f2f2f2;
    text-align: center;
    padding: 14px 16px;
    text-decoration: none;
  }

  .active {
    background-color: #04AA6D;
    color: white;
  }

  .topnav .icon {
    display: none;
  }

  .dropdown {
    float: left;
    overflow: hidden;
  }

  .dropdown .dropbtn {
    font-size: 17px;
    border: none;
    outline: none;
    color: white;
    padding: 14px 16px;
    background-color: inherit;
    font-family: inherit;
    margin: 0;
  }

  .dropdown-content {
    display: none;
    position: absolute;
    background-color: #f9f9f9;
    min-width: 160px;
    box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
    z-index: 1;
  }

  .dropdown-content a {
    float: none;
    color: black;
    padding: 14px 16px;
    text-decoration: none;
    display: block;
    text-align: left;
  }

  .topnav a:hover, .dropdown:hover .dropbtn {
    background-color: #555;
    color: white;
  }

  .dropdown-content a:hover {
    background-color: #ddd;
    color: black;
  }

  .dropdown:hover .dropdown-content {
    display: block;
  }

  @media screen and (max-width: 600px) {
    .topnav a:not(:first-child), .dropdown .dropbtn {
      display: none;
    }
    .topnav a.icon {
      float: right;
      display: block;
    }
  }

  @media screen and (max-width: 600px) {
    .topnav.responsive {position: relative;}
    .topnav.responsive .icon {
      position: absolute;
      right: 0;
      top: 0;
    }
    .topnav.responsive a {
      float: none;
      display: block;
      text-align: left;
    }
    .topnav.responsive .dropdown {float: none;}
    .topnav.responsive .dropdown-content {position: relative;}
    .topnav.responsive .dropdown .dropbtn {
      display: block;
      width: 100%;
      text-align: left;
    }
  }
</style>

这样修改后,窄屏模式下点击汉堡按钮应该就能正常展开垂直菜单了,也不会出现页面刷新的问题。

备注:内容来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 15:34:50