搜索框必须放入navbar-collapse内才能在小屏正常渲染,正确做法是作为独立li嵌入其中;需加me-2防ios viewport溢出,用display切换而非dom操作实现动态过滤,焦点处理需主动调用collapse.hide()。

搜索框必须塞进 navbar-collapse 里,否则小屏下不渲染
Bootstrap 5 的响应式逻辑靠 navbar-collapse 控制显隐。把 input 直接写在 navbar-brand 后面、或和 navbar-nav 并列,小屏折叠后它根本不会出现在 DOM 中——不是“隐藏”,是压根没生成。
正确做法是把它作为独立 li 塞进 navbar-collapse 内部:
<div class="navbar-collapse collapse">
<ul class="navbar-nav me-auto">
<li class="nav-item"><a class="nav-link" href="#">Home</a></li>
</ul>
<ul class="navbar-nav">
<li class="nav-item">
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Search"><button class="btn btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
</li>
</ul>
</div>
- 别用
ms-auto包整个form——它会随其他导航项一起被收进汉堡菜单,用户得先点开菜单才能看到搜索框 - 确保引入了
bootstrap-iconsCSS,否则<i class="bi bi-search"></i>会白屏 - 若想搜索框「始终可见」(含小屏),就放弃
navbar-collapse,改用ms-auto放在nav直接子级,但要手动处理 iOS 键盘遮挡
form-control 必须加 me-2,否则 iOS 会触发 viewport overflow
默认情况下,form-control 在 navbar 里左右 margin 为 0,紧贴相邻元素。小屏下右侧若有 navbar-toggler,iOS Safari 会直接报 viewport overflow 错误:横向滚动条弹出、输入框失焦、软键盘闪退。
me-2 提供 0.5rem 右侧安全缓冲,不是为了“好看”,是 Safari 软键盘弹出时的刚需。
- 若搜索框需左对齐或居中,改用
ms-2或mx-1,别硬套已废弃的ml-2 - 别对
input-group外层再加margin或padding——它内部已有 spacing,叠加会导致错位 - 不加间距的后果不是“难看”,而是真会触发 Safari 的 viewport 溢出保护机制
点击搜索框不收菜单?navbar-collapse 默认不监听 focus
Bootstrap 的折叠逻辑只响应 a 标签或带 data-bs-toggle="collapse" 的按钮点击。input 不触发关闭,所以用户点开键盘后菜单还开着——这不是 bug,是设计如此。
- 最简解法:
<input data-bs-toggle="collapse" data-bs-target="#navbarNav">(目标 ID 和navbar-toggler一致) - 更稳妥做法:监听
focusin事件,用 JS 主动调用bootstrap.Collapse.getInstance(element).hide() - 别依赖
blur收起——用户可能切到别的 App 或点其他输入框,菜单会卡住
动态过滤菜单项时,别删 DOM,用 display 切换
实时搜索匹配后,直接 remove() 或重写 innerHTML 会导致焦点丢失、键盘导航中断、A11Y 属性失效,尤其菜单项超过 50 条时性能暴跌。
正确做法是遍历所有 li.nav-item,根据 textContent 匹配,然后设 style.display = "none" 或 "block":
const input = document.querySelector('.navbar input[type="search"]');
const items = document.querySelectorAll('.navbar .nav-item');
input.addEventListener('input', () => {
const q = input.value.trim().toLowerCase();
items.forEach(item => {
const text = item.textContent.toLowerCase();
item.style.display = q ? (text.includes(q) ? 'block' : 'none') : 'block';
});
});
- 只比对
textContent,别用innerHTML——否则带图标或 badge 的项会误匹配 HTML 标签 - 空搜索时务必恢复全部显示,否则用户清空输入框后菜单空白
- 如果菜单含多级
collapse,过滤后要手动调用bootstrap.Collapse.getInstance(el).hide()关闭不匹配的子菜单
me-2、focusin 和 display 切换的细节里。











