无 JS 的几种实现下拉菜单的方法
前几天让 AI 搓个文章目录的时候才想起来纯 HTML 也能实现这种效果。
一般想到下拉菜单都下意识觉得要用 JS,比如点击按钮后给下拉菜单修改 class 或者是 style。 但如果是比较简单的下拉菜单那倒是不用 JS。
CSS
最简单和常见的思路就是利用 :focus-within 或者是 :hover,不过 :hover 不用点击就能展开对我来说有点反直觉
大概思路就是点击按钮以后让它获得焦点,然后根据这个状态把下面的菜单显示出来。
:focus 也是可以的,不过实际上使用起来会用奇奇怪怪的小问题。
比如点击子元素后会取消按钮的 :focus 状态导致菜单收回。
而 :focus-within 则可以同时对子元素生效。
<div class="menu">
<button>产品</button>
<div class="dropdown">
<a href="#">产品一</a>
<a href="#">产品二</a>
<a href="#">产品三</a>
</div>
</div>
.menu{position:relative}
.dropdown{display:none;position:absolute}
.menu:focus-within .dropdown{display:block}
.dropdown 默认为 display:none。
而当 .menu 里的 <button> 被点击获得焦点后,状态匹配 :focus-within。
因此触发了第三行 CSS,.dropdown 被设置为 display:block。
这种方式严格来说不是根据按钮的点击切换,而是根据焦点状态控制显示。
还有另一种方法是 :checked,逻辑上不太一样。
通过 <label> 和 <input> 绑定,点击 <label> 来给 <input> 转发操作。
当然直接嵌套也是可以的。
<div class="menu">
<input type="checkbox" id="menu" />
<label for="menu">产品</label>
<div class="dropdown">
<a href="#">产品一</a>
<a href="#">产品二</a>
<a href="#">产品三</a>
</div>
</div>
.menu{position:relative}
.menu input{display:none}
.dropdown{display:none;position:absolute}
.menu input:checked+label+.dropdown{display:block}
.dropdown 默认为 display:none。
而当 <label> 被点击后,将操作转发到 <input> 使 checkbox 的选中状态发生切换,从而匹配 :checked。
因此触发了第四行 CSS,.dropdown 被设置为 display:block。
HTML
更简单和便捷的方法也就是使用 HTML 里的 <details>,自带打开和关闭两个状态,也就直接省去了我们前面想方设法用 CSS 实现的步骤。
<details>
<summary>点我展开</summary> <!-- 控件 -->
<p>这里是隐藏的内容。</p> <!-- 需要隐藏的内容 -->
<p>这里是更多内容。</p> <!-- 需要隐藏的内容 -->
</details>
浏览器会自动渲染为:
▶ 点我展开
---
▼ 点我展开
这里是隐藏的内容。
这里是更多内容。
<summary> 会自带一个箭头指示,这个箭头可以用 list-style: none 来隐藏。
或者也可以这样来自定义箭头的文字:
summary::marker{content:"▶ "}
<summary> 除了作为按钮的信息文本展示之外,也是整个 <details> 的主要控件。且 <summary> 必须是 <details> 的第一个子元素。
打开和关闭的状态靠 <details> 里的 open 属性,点击 <summary> 会切换这个属性。也可以直接在默认状态下就加入这个属性以让其默认展开。
针对这个属性也可以这样写 CSS:
details[open]{background:#eee}
/* 或者是 */
details:open{background:#eee}
不过自带折叠事件了倒也不太需要用这个选择器了?