在 Web 开发中,折叠面板(Accordion)是一种常见的交互组件,用于在有限的空间内展示和隐藏内容。很多时候,我们希望自己手动实现这一效果,而不是依赖第三方组件库。

本文将介绍两种实现方式:一种是利用 HTML5 的 <details><summary> 标签,另一种是利用原生 HTML、CSS 和 JavaScript 构建自定义折叠面板。

方法一:使用 <details><summary> 标签

HTML5 提供了 <details><summary> 标签,原生支持折叠和展开的交互功能,非常简单且无需 JavaScript。通过添加适当的 CSS 样式,我们还可以对其进行美化和自定义。

基本实现

1
2
3
4
<details>
<summary>面板标题</summary>
<p>这是折叠面板的内容。你可以在这里放置任意 HTML 内容。</p>
</details>

以下是实现效果:

美化 <details><summary> 的 CSS 样式

下面是一个示例,展示如何为 <details><summary> 标签设置自定义样式,包括指示图标的旋转效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>使用 details/summary 实现折叠面板</title>
<style>
/* 基本样式 */
details {
border: 1px solid #eee;
border-radius: 4px;
margin: 10px 0;
background-color: #fff;
}
summary {
font-size: 0.8em;
font-weight: bold;
cursor: pointer;
list-style: none;
position: relative;
padding-right: 20px;
padding: 8px;
background-color: #fafafa;
}
/* 移除默认的三角图标 */
summary::-webkit-details-marker {
display: none;
}
summary::after {
content: "\25BC"; /* 下箭头 */
position: absolute;
right: 8px;
top: 50%;
transform: translateY(-50%);
transition: transform 0.3s ease;
}
details[open] summary::after {
transform: translateY(-50%) rotate(180deg); /* 展开时旋转 */
}
details p {
padding: 10px;
margin: 0;
}
details img {
padding: 10px;
margin: 0;
}
</style>
</head>
<body>
<div style="display: flex;">
<div style="flex: 1">
<details>
<summary>面板标题</summary>
<p>
这是第一个折叠面板的内容。使用 HTML5 的 details
标签可以轻松实现折叠效果。
</p>
<img
src="https://assets.kiteblog.cn/cdn-cgi/image/format=auto/blog-bg.jpg"
width="300"
alt=""
/>
</details>
</div>
<div style="flex: 1">
<details style="flex: 1; margin-left: 12px;">
<summary>面板标题</summary>
<p>
这是第一个折叠面板的内容。使用 HTML5 的 details
标签可以轻松实现折叠效果。
</p>
<img
src="https://assets.kiteblog.cn/cdn-cgi/image/format=auto/blog-bg.jpg"
width="300"
alt=""
/>
</details>
</div>
</div>
</body>
</html>

实现效果:

说明:

  • 通过 summary::-webkit-details-marker 隐藏默认的图标,然后使用 CSS ::after 伪元素添加自定义的下箭头。
  • 利用 details[open] 选择器,在折叠面板展开时对图标进行旋转,实现直观的状态提示。
  • 设置适当的内外边距和背景色,使面板看起来更加美观。

方法二:使用 HTML、CSS 和 JavaScript 实现自定义折叠面板

如果需要更多的自定义交互效果或兼容性要求,可以使用 HTML、CSS 和 JavaScript 手动实现折叠面板。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<!DOCTYPE html>
<htmllang="zh-CN">
<head>
<metacharset="UTF-8">
<metaname="viewport"content="width=device-width, initial-scale=1">
<title>自定义折叠面板</title>
<style>.accordion {
width: 100%;
max-width: 600px;
margin: 20px auto;
border: 1px solid #ccc;
border-radius: 4px;
overflow: hidden;
}
.accordion-item {
border-top: 1px solid #ccc;
}
.accordion-header {
background-color: #f1f1f1;
padding: 15px;
font-size: 1.2em;
font-weight: bold;
cursor: pointer;
position: relative;
}
.accordion-header::after {
content: "\25BC";
position: absolute;
right: 20px;
top: 50%;
transform: translateY(-50%);
transition: transform 0.3s ease;
}
.accordion-item.active.accordion-header::after {
transform: translateY(-50%) rotate(180deg);
}
.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
padding: 015px;
background-color: #fff;
}
.accordion-item.active.accordion-content {
/* 这里可以使用 auto,但为了动画平滑,通常需要设置具体高度 */max-height: 200px;
padding: 15px;
}
</style>
</head>
<body>

<divclass="accordion">
<divclass="accordion-item">
<divclass="accordion-header">面板标题 1</div>
<divclass="accordion-content">
<p>这是第一个自定义折叠面板的内容。点击标题可展开或收起内容。</p>
</div>
</div>
<divclass="accordion-item">
<divclass="accordion-header">面板标题 2</div>
<divclass="accordion-content">
<p>这是第二个自定义折叠面板的内容。你可以根据需要添加任意HTML元素。</p>
</div>
</div>
</div>

<script>// 为所有折叠面板标题绑定点击事件document.querySelectorAll('.accordion-header').forEach(header => {
header.addEventListener('click', function() {
const accordionItem = this.parentElement;
const isActive = accordionItem.classList.contains('active');

// 如果需要只允许一个面板同时打开,可以先关闭所有document.querySelectorAll('.accordion-item').forEach(item => {
item.classList.remove('active');
});

// 如果当前面板未打开,则打开它;否则关闭if (!isActive) {
accordionItem.classList.add('active');
}
});
});
</script>

</body>
</html>

说明:

  • 每个 .accordion-item 包含一个标题和一个内容部分,初始时内容部分的 max-height 设置为 0,从而隐藏内容。
  • 点击标题时,通过添加或移除 .active 类来控制内容展开和收起,并通过 CSS 过渡效果实现平滑动画。
  • 为了让动画效果更加顺滑,实际项目中可以根据内容动态计算高度,或使用 JavaScript 计算内容高度后设置为具体值。

希望这篇博客能帮你。

Happy Coding!