🧩 项目背景:当CSS遇上魔法
想象你有一盒乐高积木,现在要搭建一个会变魔术的展示台,点击某个积木它就会突然膨胀,其他积木自动闪开——这就是我们今天要实现的Expanding Cards项目!
🧠 核心知识点大揭秘
🌈 弹性布局的魔法咒语(Flex布局)
✨ 居中大法:两招搞定
body {
display: flex; /* 开启弹性布局 */
align-items: center; /* 纵轴居中 */
justify-content: center; /* 主轴居中 */
height: 100vh; /* 占满屏幕高度 */
}
类比:就像在舞池中央放一个旋转木马,所有元素自动被吸附到中心!🎉
🧱 容器与子元素的默契配合
.container {
display: flex; /* 一行排开 */
width: 90vw; /* 占90%视口宽度 */
}
.qq-panel {
flex: 0.5; /* 初始平均分配 */
transition: all 700ms ease-in; /* 添加魔法特效 */
}
小贴士:
flex就像给每个卡片装上了弹簧,点击时弹簧突然伸长!💥
🧪 相对单位的魔法:100vh
height: 100vh; /* 占满屏幕高度 */
场景:无论你是用手机📱还是电脑🖥️,卡片都会完美贴合屏幕高度!
🎨 过渡效果:让元素优雅起舞
transition: all 700ms ease-in;
比喻:就像给卡片穿上滑轮鞋,动作变得丝滑流畅!⛸️
🧩 BEM命名规范:给元素戴名牌
<div class="qq-panel">
<h3 class="qq-panel__title">标题</h3>
</div>
好处:代码就像给每个角色发了身份证,再也不怕命名混乱啦!🆔
🤖 JS魔法:让卡片活起来
panel.addEventListener('click', () => {
console.log('biubiubiu'); // 控制台撒花
removeActiveClasses();
panel.classList.add("qq-panel_active");
});
彩蛋:点击卡片会触发"biubiubiu"的控制台烟花秀!🎇
🧾 完整代码源码(可直接复制运行)
文档小剧场:虽然有些文档链接可能像消失的魔法一样无法访问,但我们的代码已经完整打包,直接复制就能运行!🎉
📁 1. HTML结构文件(index.html)
<!DOCTYPE html>
<html lang="en">
<head>
<!-- 设置字符编码为UTF-8 -->
<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>
<!-- 引入JavaScript文件 -->
<script src="common.js"></script>
</body>
</html>
🎨 2. CSS魔法阵(common.css)
/* 全局样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* 页面主体样式 */
body {
display: flex; /* 弹性布局 pad 手机 布局 flex */
align-items: center; /* 垂直居中对齐 */
justify-content: center; /* 水平居中对齐 */
height: 100vh;/* vh 相对单位 viewport height 一屏高度100vh, 等比例划分*/
overflow: hidden;/* 超出隐藏 */
/* background-color: green; */
}
/* 容器样式 */
.container {
display: flex;/* 弹性布局 格式化上下文 */
width: 90vw; /* 90% viewport width 视口宽度 */
}
/* 面板基础样式 */
.qq-panel {
height: 80vh; /* 设置面板高度为视口高度的80% */
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; /* 距离底部20px */
left: 20px; /* 距离左侧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. JS魔法书(common.js)
// 获取所有面板元素
const panels = document.querySelectorAll('.qq-panel');
// 为每个面板添加点击事件监听器
panels.forEach(panel => {
// JS 是事件机制的语言
// 每一个元素上监听
panel.addEventListener('click', () => {
console.log('biubiubiu');
removeActiveClasses(); //模块化
panel.classList.add("qq-panel_active");
})
})
/**
* 移除所有面板的激活状态
* 这是一个模块化的函数,用于重置所有面板的状态
*/
function removeActiveClasses() {
panels.forEach(panel => {
panel.classList.remove('qq-panel_active');
})
}
🖼️ 页面展示模块(效果预览)
🎬 动态效果演示
- 初始状态:
五个卡片整齐排列,等待你的点击魔法!
- 点击某个卡片后:
被点击的卡片像气球一样膨胀,其他卡片自动退位让贤!
🧪 效果演示:点击卡片的魔法时刻
- 点击任意卡片,它会像吹气球一样膨胀🎈
- 其他卡片会优雅地缩回原位
- 标题文字会像从魔法盒里跳出来✨
- 控制台还会出现神秘的"biubiubiu"烟花秀🎇
🚀 学习建议:让知识生根发芽
- 动手实践:试着修改
flex值,看看卡片如何变化 - 代码调试:在控制台添加
console.log,观察点击事件的触发过程 - 扩展玩法:
- 给卡片添加阴影效果
- 尝试不同的过渡动画
- 添加音效增强交互体验
🎁 开发者小秘密
你知道吗?
100vh在某些设备上可能会有小bug,可以试试calc(100vh - 1px)来规避~ 😜
📚 知识点总结
| 技术点 | 说明 | 使用场景 |
|---|---|---|
| Flex布局 | 灵活的响应式布局方案 | 手机/PC适配 |
| BEM命名 | 结构清晰的命名规范 | 复杂项目维护 |
| 100vh单位 | 占满屏幕高度 | 全屏展示 |
| transition | 光滑的过渡效果 | 交互增强 |
| JS事件 | 控制动态变化 | 用户交互 |
🚀 最后
通过这个项目,我们不仅掌握了弹性布局的精髓,还学会了如何用CSS和JS创造惊艳的用户体验。记住:前端开发就像魔法,CSS是咒语,JS是魔杖!🧙♂️