5张卡片的魔法秀:Flex布局+Transition实现高级展开动效

前言

在这篇技术博客中,我将详细解析一个流行的卡片展开效果实现方案,这个效果在GitHub最受欢迎的50个项目中占有一席之地。我们将从布局、CSS样式到JavaScript交互进行全面讲解。

让我们先来瞅瞅大概的动画效果吧🚀🚀🚀

项目概述

这个项目展示了一组卡片,默认状态下所有卡片均匀分布,当用户点击某个卡片时,该卡片会展开显示更多内容,同时其他卡片会收缩。这种交互方式在图片展示、产品特性介绍等场景非常实用。

HTML结构分析

构建一个初始的框架可以用一行代码解决:.container>(.qq-panel>h3.qq-panel__title)*5,然后其他的背景属性什么的慢慢加

html 复制代码
<div class="container">
      <div class="qq-panel qq-panel_active" style="background-image: url('https://images.unsplash.com/photo-1558979158-65a1eaa08691?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
        <h3 class="qq-panel__title">Explore The World</h3>
      </div>
      <div class="qq-panel" style="background-image: url('https://images.unsplash.com/photo-1572276596237-5db2c3e16c5d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
        <h3 class="qq-panel__title">Wild Forest</h3>
      </div>
      <div class="qq-panel" style="background-image: url('https://images.unsplash.com/photo-1507525428034-b723cf961d3e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1353&q=80')">
        <h3 class="qq-panel__title">Sunny Beach</h3>
      </div>
      <div class="qq-panel" style="background-image: url('https://images.unsplash.com/photo-1551009175-8a68da93d5f9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1351&q=80')">
        <h3 class="qq-panel__title">City on Winter</h3>
      </div>
      <div class="qq-panel" style="background-image: url('https://images.unsplash.com/photo-1549880338-65ddcdfd017b?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1350&q=80')">
        <h3 class="qq-panel__title">Mountains - Clouds</h3>
      </div>
</div>
  • 使用BEM命名规范(Block Element Modifier)命名类名
  • 卡片背景图片通过内联样式设置,便于动态更改
  • 初始状态下第一个卡片有qq-panel_active类,这个类是用来区分有没有点击的,初始状态下,只有第一张卡片是被点击的

CSS样式详解

全局重置与基础设置

css 复制代码
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
  • *选择器应用于所有元素
  • 重置margin和padding为0,消除浏览器默认样式差异

box-sizing: border-box 让元素尺寸计算更符合直觉:

  1. 传统模式 (content-box)
  • width: 100px 仅指内容宽度

  • 实际占用宽度 = 100px + padding + border

  • 容易导致布局溢出

  1. border-box模式
  • width: 100px 包含内容、padding和border
  • 实际占用宽度就是设定的100px
  • 内容区自动收缩:内容宽度 = 100px - padding - border

为什么更直观

  • 你设想的100px就是最终显示的100px
  • 不需要做加减法计算实际占用空间
  • 特别适合响应式布局(百分比宽度时不会因padding而溢出) 这就是为什么现代CSS重置通常首选border-box

弹性布局与居中

css 复制代码
body {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
    overflow: hidden;
}
  • display: flex将body设置为弹性容器
  • align-items: center垂直居中(交叉轴方向)
  • justify-content: center水平居中(主轴方向)
  • height: 100vh使body高度等于视窗高度
  • overflow: hidden隐藏溢出内容,防止滚动条出现

注意:

  1. vh单位:1vh等于视窗高度的1%,100vh就是整个视窗高度。这是响应式设计中常用的相对单位。
  2. justify-content :现在是水平居中,但其实是主轴的方向居中,align-items就是另一个方向的居中(这两个方向相互垂直),通过flex-direction属性可以改变主轴的方向。(可以参考博客:告别浮动!Flexbox弹性布局终极指南引言)

容器样式

css 复制代码
.container {
    display: flex; /* 弹性布局 */
    width: 90vw; /* 宽度 90% 视窗宽度 */
}
  • 再次使用flex布局,使子元素排列在一行
  • width: 90vw容器宽度为视窗宽度的90%,留出边距

卡片基础样式

css 复制代码
.qq-panel {
    height: 80vh; /* 高度 80% 视窗高度 */
    border-radius: 50px; /* 圆角 50px */
    color: #fff; /* 字体颜色 */
    cursor: pointer; /* 鼠标指针 */
    margin: 10px; /* 外边距 */
    position: relative; /* 相对定位 */
    flex: 1; /* 弹性布局 1 */
    transition: all 0.7s ease-in; /* 过渡效果 */
}
  • height: 80vh卡片高度为视窗高度的80%
  • border-radius: 50px大圆角效果,现代感更强
  • flex: 1所有卡片平均分配剩余空间,这个是相对的,如果有一个盒子是flex:2,那么这个盒子就是其他盒子的两倍,后面会看到,点击的盒子(div)是其他的5倍

transition: all 0.7s ease-in 是CSS过渡效果的简写属性,分解来看:

  1. 作用范围
    • all表示监听元素所有可过渡属性的变化
    • 也可指定特定属性如opacity, transform
  2. 时间控制
    • 0.7s表示过渡持续700毫秒
    • 时间长短影响动画节奏感(0.3s-1s最常用)
  3. 缓动函数
    • ease-in表示动画"慢入快出"
    • 其他常见值:
      • ease-out(快入慢出)
      • ease-in-out(慢入慢出)
      • linear(匀速)
  4. 延迟时间 :
    • 其实后面还有一个值,如:transition: opacity 0.3s ease-in 0.4s;所示,这里的0.4s表示动画不会立即执行,而是等待 0.4 秒后才开始。

提示:过渡属性应写在元素的默认状态,而非:hover等伪类中

卡片标题样式

css 复制代码
.qq-panel__title {
    font-size: 24px; /* 字体大小 */
    position: absolute; /* 绝对定位 */
    bottom: 20px; /* 底部 20px */
    left: 20px; /* 左边 20px */
    opacity: 0; /* 不透明度 */
}
  • 使用绝对定位将标题固定在卡片左下角
  • 初始opacity: 0使标题不可见

激活状态卡片样式

css 复制代码
.qq-panel_active {
    flex: 5; /* 弹性布局 5 */
}

.qq-panel_active .qq-panel__title {
    opacity: 1; /* 不透明度 */
    transition: opacity 0.3s ease-in 0.4s; /* 过渡效果 */
}
  • flex: 5激活的卡片占据更多空间(是普通卡片的5倍)

  • 标题显示(opacity: 1)并有单独的过渡效果

  • transition: opacity 0.3s ease-in 0.4s表示:

    • 属性:opacity(只有这一个属性发生变化时,才会触发这个过渡函数,前面的all是不管什么属性发生变化都会触发这个过渡函数)
    • 时长:0.3秒
    • 缓动函数:ease-in
    • 延迟:0.4秒(让卡片展开动画先进行)

JavaScript交互逻辑

javascript 复制代码
//获取所有卡片元素
const panels = document.querySelectorAll('.qq-panel');

panels.forEach(panel => {
    // JS 是事件机制的语言
    panel.addEventListener('click', () => {
        // 移除所有的 active 类
        removeActiveClasses(); // 模块化
        panel.classList.toggle('qq-panel_active');
    });
});

function removeActiveClasses() {
    panels.forEach(panel => {
        panel.classList.remove('qq-panel_active');
    })
}
  1. 获取所有卡片元素

  2. 为每个卡片添加点击事件监听器

  3. 点击时:

    • 先移除所有卡片的激活状态
    • 然后切换当前卡片的激活状态
  4. removeActiveClasses函数封装了移除激活状态的逻辑

设计要点总结

  1. 响应式布局:使用vh/vw单位确保不同设备上比例一致

  2. 弹性布局:flexbox轻松实现水平和垂直居中

  3. 视觉层次:通过缩放和标题显示/隐藏创造焦点

  4. 动画细节

    • 主动画0.7秒确保效果明显但不拖沓
    • 标题延迟0.4秒显示,避免与卡片展开动画冲突
    • 缓动函数(ease-in)使动画更自然
  5. 用户体验

    • 光标变为指针形状(cursor: pointer)提示可点击
    • 圆角设计更友好
    • 平滑过渡减少视觉跳跃

这个项目展示了如何用简洁的代码实现优雅的交互效果,核心在于对CSS弹性布局和过渡动画的熟练运用。通过分析这个案例,我们可以学习到现代前端开发中许多实用的技巧和设计理念。

相关推荐
橙某人13 分钟前
🤖Agent进化论:从Copilot到主驾驶,MCP如何成为AI的"万能接口"?
前端·mcp
刺客-Andy26 分钟前
React 第五十一节 Router中useOutletContext的使用详解及注意事项
前端·javascript·react.js
NoneCoder30 分钟前
React进阶:状态管理选择题
前端·react.js·面试
巴巴_羊30 分钟前
react 生命周期
前端·react.js·前端框架
刺客-Andy31 分钟前
React 第五十二节 Router中 useResolvedPath使用详解和注意事项示例
前端·javascript·react.js
datascome33 分钟前
简数采集技巧之快速获取特殊链接网址URL方法
前端·经验分享·爬虫·程序人生·正则表达式
架构个驾驾36 分钟前
Vue2 与 Vuex 状态管理实战指南
前端·javascript·vue.js
贵州数擎科技有限公司38 分钟前
Unity 单例模式完全指南
前端
FogLetter38 分钟前
从语义化标签到JS变量:前端工程师的必修课
前端·javascript·代码规范