前言
本文将详细讲解如何实现一个优雅的扩展卡片(Expanding Cards)组件,这是GitHub上流行的"50 Projects in 50 Days"系列中的经典案例。通过HTML、CSS和JavaScript的配合,我们将实现卡片点击后平滑展开的视觉效果,同时学习现代前端开发中的布局技术和交互设计思想。
项目结构与实现步骤
1. HTML结构设计
首先,让我们查看完整的HTML代码:
<!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="common.css" />
<title>Expanding Cards</title>
</head>
<body>
<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>
<script src="common.js"></script>
</body>
</html>
HTML结构采用了以下设计原则:
-
语义化结构:使用合适的HTML5标签构建页面框架
-
BEM命名规范:采用Block-Element-Modifier命名方式组织CSS类名
qq-panel:组件的块级元素qq-panel__title:标题作为面板的子元素qq-panel_active:表示激活状态的修饰符
-
初始激活状态:第一个卡片默认添加
qq-panel_active类,确保页面加载时就有展示效果 -
背景图片内联:直接在HTML中通过style属性设置背景图片,简化实现
-
外部资源链接:分离CSS和JavaScript,便于代码维护
2. CSS样式实现
CSS布局采用现代弹性盒模型和相对单位实现响应式设计:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
}
.container {
display: flex;
width: 90vw;
}
.qq-panel {
height: 80vh;
border-radius: 50px;
color: #fff;
cursor: pointer;
margin: 10px;
position: relative;
flex: 0.5;
transition: all 700ms ease-in;
}
.qq-panel__title {
font-size: 24px;
position: absolute;
bottom: 20px;
left: 20px;
opacity: 0;
}
.qq-panel_active {
flex: 5;
}
.qq-panel_active .qq-panel__title {
opacity: 1;
transition: opacity 0.3s ease-in 0.4s;
}
3. JavaScript交互逻辑
交互逻辑通过简洁的事件监听和DOM操作实现:
const panels = document.querySelectorAll('.qq-panel');
panels.forEach(panel => {
panel.addEventListener('click', () => {
removeActiveClasses();
panel.classList.add('qq-panel_active');
})
})
function removeActiveClasses() {
panels.forEach(panel => {
panel.classList.remove('qq-panel_active');
})
}
技术要点深入分析
1. display属性详解
display属性是CSS布局的基础,它定义了元素的显示类型与行为:
- block:块级元素,默认占据一行
- inline:行内元素,在文本流中显示
- inline-block:结合了行内和块级特性
- flex:弹性布局,一维布局系统
- grid:网格布局,二维布局系统
- none:元素不显示且不占空间
在本项目中,我们使用了display: flex创建弹性布局上下文:
body {
display: flex; /* 弹性布局,移动端时代的布局主流方式 */
align-items: center; /* 纵轴居中 */
justify-content: center; /* 主轴居中 */
height: 100vh;
}
.container {
display: flex; /* 子元素水平排列,不会换行 */
width: 90vw;
}
弹性布局的优势在于:
- 容器能自动调整子元素大小
- 简化垂直居中等常见布局难题
- 响应式设计更加简洁
- 减少媒体查询的使用
2. 相对单位系统
相对单位是响应式设计的核心,本项目使用了以下相对单位:
-
vh (viewport height):视口高度的百分比
body { height: 100vh; /* 占满整个视口高度 */ } .qq-panel { height: 80vh; /* 占视口高度的80% */ } -
vw (viewport width):视口宽度的百分比
.container { width: 90vw; /* 占视口宽度的90% */ }
相对单位的优势:
- 自适应不同屏幕大小
- 保持设计比例一致
- 减少媒体查询代码
- 简化响应式实现
3. Flex布局与动态比例
组件的核心交互效果通过flex属性值的变化实现:
.qq-panel {
flex: 0.5; /* 初始状态下的收缩比例 */
transition: all 700ms ease-in; /* 过渡效果 */
}
.qq-panel_active {
flex: 5; /* 激活状态下的扩展比例 */
}
通过改变flex值(从0.5到5)创造出卡片展开的视觉效果,配合transition属性实现平滑过渡。
4. 层次化动画效果
标题显示采用了延迟过渡效果,创造层次感:
.qq-panel__title {
opacity: 0; /* 初始状态隐藏 */
}
.qq-panel_active .qq-panel__title {
opacity: 1;
transition: opacity 0.3s ease-in 0.4s; /* 0.4秒延迟显示 */
}
这种延迟效果让用户先看到卡片展开,再看到标题文字显示,增强了交互的艺术性和期待感。
用户体验设计考量
项目在用户体验方面的精心设计:
-
视觉和谐:
- 圆角设计(
border-radius: 50px)柔化视觉边界 - 统一的图片风格营造连贯体验
- 圆角设计(
-
交互反馈:
- 鼠标悬停时的指针变化(
cursor: pointer)提示可点击 - 点击后的平滑过渡给予用户直观反馈
- 鼠标悬停时的指针变化(
-
动效节奏:
- 展开动画(700ms)和标题显示(300ms延迟400ms)形成富有韵律的体验链
- 避免所有元素同时变化,创造高级感
实现要点总结
- 语义化HTML结构与BEM命名规范提升代码可维护性
- 弹性布局实现元素间的动态比例关系
- 相对单位确保跨设备一致性体验
- CSS过渡效果设计达到视觉层次感
- JavaScript事件机制实现简洁的交互逻辑
- 模块化函数设计提高代码可读性和可维护性
实践启示
这个扩展卡片组件看似简单,却融合了多项前端核心技术与设计理念。从中我们可以学习到:
- 优秀的UI组件往往建立在简洁代码基础上
- 精心设计的过渡效果能显著提升用户体验
- 相对单位和弹性布局是响应式设计的基础
- 前端交互设计需要考虑动效的层次感和时间节奏
通过掌握这些技术和设计思想,我们能够在实际项目中创造出既美观又实用的前端组件,为用户带来"尖叫"级别的交互体验。