前端实战12:手风琴效果

大家好,我是宝哥。

今天讲50个项目50天,前端实战12:手风琴效果。

58d3b215061fefa3deca4fc8caf477da.png

本项目是一个常见的面板式问答交互组件,也被称为手风琴效果。点击问题标题可以展开或收起对应的答案内容。项目注重于简洁的设计和易用性,使用纯 CSS 实现展开/收起的动画效果。

源码下载地址

https://github.com/bradtraversy/50projects50days/tree/master/faq-collapse

在线预览(文末原文链接直达):

https://qdkfweb.cn/50projects50days/faq-collapse/

前端实战项目系列正在更新:12/50

基本原理

  1. 项目通过 HTML 结构定义多个问答内容区块 (div.faq)。

  2. 每个问答区块包含一个问题标题 (h3.faq-title) 和一个答案内容 (p.faq-text)。

  3. 还包含一个按钮 (button.faq-toggle),用来控制答案内容的展开和收起。

  4. 按钮的图标 (<i>) 使用 Font Awesome 字体图标库。

  5. CSS 样式定义了问答区块的样式、按钮的样式以及展开/收起的动画效果。

  6. JavaScript 代码通过遍历所有按钮 (faq-toggle),为每个按钮添加点击事件监听器。

  7. 点击按钮时,会切换其父元素 (faq) 的类名 (active),从而控制答案内容的显示和隐藏,并根据状态切换按钮的图标。

HTML 结构

  • 首先包含一个标题 (<h1>),用来显示 “Frequently Asked Questions” (常见问题解答)。

  • 然后,包含一个容器 (div.faq-container),用来容纳所有的问答区块。

  • 每个问答区块 (div.faq) 包含以下内容:

    • 问题标题 (h3.faq-title)

    • 答案内容 (p.faq-text)

    • 控制按钮 (button.faq-toggle)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />
    <link rel="stylesheet" href="style.css" />
    <title>FAQ</title>
  </head>
  <body>
    <h1>Frequently Asked Questions</h1>
    <div class="faq-container">
      <div class="faq active">
        <h3 class="faq-title">
          Why shouldn't we trust atoms?
        </h3>

        <p class="faq-text">
          They make up everything
        </p>

        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>

      <div class="faq">
        <h3 class="faq-title">
          What do you call someone with no body and no nose?
        </h3>
        <p class="faq-text">
          Nobody knows.
        </p>
        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>
      
      <div class="faq">
        <h3 class="faq-title">
          What's the object-oriented way to become wealthy?
        </h3>
        <p class="faq-text">
          Inheritance.
        </p>
        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>
      
      <div class="faq">
        <h3 class="faq-title">
          How many tickles does it take to tickle an octopus?
        </h3>
        <p class="faq-text">
          Ten-tickles!
        </p>
        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>
      
      <div class="faq">
        <h3 class="faq-title">
          What is: 1 + 1?
        </h3>
        <p class="faq-text">
          Depends on who are you asking.
        </p>
        <button class="faq-toggle">
          <i class="fas fa-chevron-down"></i>
          <i class="fas fa-times"></i>
        </button>
      </div>
    </div>
    <script src="script.js"></script>
  </body>
</html>

CSS 样式

  • 定义整体的样式 (body, h1)。

  • 设置问答区块的样式 (div.faq),包括背景色、边框、圆角、间距、填充等。

  • 关键在于使用 transition 属性定义内容展开/收起过程的动画效果。

  • 另外定义激活状态下的问答区块样式 (faq.active)。

    • 使用伪元素 (::before::after) 在激活状态下添加额外的装饰性图标。

    • 设置问题标题 (h3.faq-title) 和 答案内容 (p.faq-text) 的样式。

    • 设置按钮的样式 (button.faq-toggle),并定义激活状态下按钮图标的切换 (faq.active .faq-toggle).

@import url('https://fonts.googleapis.com/css?family=Muli&display=swap');

* {
  box-sizing: border-box;
}

body {
  font-family: 'Muli', sans-serif;
  background-color: #f0f0f0;
}

h1 {
  margin: 50px 0 30px;
  text-align: center;
}

.faq-container {
  max-width: 600px;
  margin: 0 auto;
}

.faq {
  background-color: transparent;
  border: 1px solid #9fa4a8;
  border-radius: 10px;
  margin: 20px 0;
  padding: 30px;
  position: relative;
  overflow: hidden;
  transition: 0.3s ease;
}

.faq.active {
  background-color: #fff;
  box-shadow: 0 3px 6px rgba(0, 0, 0, 0.1), 0 3px 6px rgba(0, 0, 0, 0.1);
}

.faq.active::before,
.faq.active::after {
  content: '\f075';
  font-family: 'Font Awesome 5 Free';
  color: #2ecc71;
  font-size: 7rem;
  position: absolute;
  opacity: 0.2;
  top: 20px;
  left: 20px;
  z-index: 0;
}

.faq.active::before {
  color: #3498db;
  top: -10px;
  left: -30px;
  transform: rotateY(180deg);
}

.faq-title {
  margin: 0 35px 0 0;
}

.faq-text {
  display: none;
  margin: 30px 0 0;
}

.faq.active .faq-text {
  display: block;
}

.faq-toggle {
  background-color: transparent;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  padding: 0;
  position: absolute;
  top: 30px;
  right: 30px;
  height: 30px;
  width: 30px;
}

.faq-toggle:focus {
  outline: 0;
}

.faq-toggle .fa-times {
  display: none;
}

.faq.active .faq-toggle .fa-times {
  color: #fff;
  display: block;
}

.faq.active .faq-toggle .fa-chevron-down {
  display: none;
}

.faq.active .faq-toggle {
  background-color: #9fa4a8;
}

JavaScript 代码

  • 获取所有控制按钮的 DOM 元素集合 (querySelectorAll)

  • 遍历每个按钮,并为其添加点击事件监听器。

  • 点击按钮时,触发事件监听器函数,该函数通过切换父元素 (faq) 的类名 (active) 来控制内容的显隐,并根据状态调整按钮图标。

const toggles = document.querySelectorAll('.faq-toggle')

toggles.forEach(toggle => {
    toggle.addEventListener('click', () => {
        toggle.parentNode.classList.toggle('active')
    })
})

总结

本项目中,巧妙地利用了伪元素在激活状态下呈现额外的装饰性图标,配合 transition 属性的设定,实现了内容展开/收起的视觉反馈效果。

在线预览(点底部原文链接可直达):https://qdkfweb.cn/50projects50days/faq-collapse/

最后

如果你觉得宝哥今天的尝试对你有帮助,就给我点个赞,关注一波。分享出去,也许你的转发能给别人带来一点启发。

推荐链接

10张脑图带你快速入门Vue3 | 附高清原图

前端程序员简历模板整理和下载

小抄学习法: 4张图掌握JS核心要点

58a86fc157ac304e03392958cf8f2f3c.png

分享和在看就是最大的支持❤️

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值