从一个超酷的展开卡片效果,聊聊前端开发的艺术

171 阅读5分钟

前言

大家好啊!今天我要和大家分享一个非常酷炫的前端小项目 —— 展开卡片效果。这个项目来自 GitHub 上超火的"50 Projects in 50 Days"系列。看起来简单,但里面却暗藏玄机,包含了很多前端开发的精髓。让我们一起来扒一扒这个项目背后的故事!

初见效果:这不就是几张卡片吗?

乍一看,这就是五张排列在一起的图片卡片。但是!当你点击任意一张卡片时,魔法就开始了 —— 被点击的卡片会优雅地展开,同时显示出隐藏的标题,而其他卡片则会自动收缩。这种流畅的动画效果,就像变魔术一样,让人忍不住想多点几下! B1E595BDE5B620190305_converted.gif

解剖项目:原来你是这样的骨架!

1. HTML:BEM命名法的艺术

<div class="container">
    <div class="qq-panel qq-panel--active">
        <h3 class="qq-panel__title">Explore The World</h3>
    </div>
</div>

看到这个HTML结构,有经验的开发者会立刻认出:这是BEM命名法!如果你还不知道BEM,那就让我用一个生动的比喻来解释:

想象你在组织一个家庭聚会(Block),家里有爸爸、妈妈、孩子(Element),他们可能在看电视、做饭或者睡觉(Modifier)。在BEM中:

  • Block(块):就像"qq-panel",是一个独立的组件
  • Element(元素):像"qq-panel__title",是组件中的子元素
  • Modifier(修饰符):比如"qq-panel--active",表示组件的特定状态

2. CSS:Flex布局的艺术

body {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
    overflow: hidden;
}

这段CSS代码简直就是居中布局的艺术!它用Flex布局轻松实现了完美居中,就像是把一幅画挂在墙正中央一样精确。让我们来解读一下这些神奇的属性:

  • display: flex:开启了flex布局模式,就像打开了一个新世界的大门
  • align-items: center:垂直居中,就像电梯停在正中间的楼层
  • justify-content: center:水平居中,就像把沙发放在客厅正中央
  • height: 100vh:使用视口高度,确保在任何设备上都能占满整个屏幕(因为我们可能在不同设备打开,这个就保证沾满你的设备的屏幕)

align-items: centerjustify-content: center 是基于display: flex生效的,一但没有弹性布局这个属性,这两个属性不会生效,在子元素生效,让子元素居中

3. 弹性布局的艺术

.container {
    display: flex;
    width: 90vw;
}

.qq-panel {
    flex: 0.5;
    transition: all 700ms ease-in;
}

.qq-panel--active {
    flex: 5;
}

这里用到了Flex布局的一个绝妙特性:flex属性!它就像是在分蛋糕,默认情况下每个面板占据0.5份,当被激活时突然变成了5份!这种动态变化配合transition过渡效果,简直就是视觉享受。

display: flex;当有子元素有很多的情况下, 父元素和子元素们之间的布局方案 子元素们不会换行 也就是像上图一样在一行显示

4. 动画效果的艺术

.qq-panel__title {
    opacity: 0;
}

.qq-panel--active .qq-panel__title {
    opacity: 1;
    transition: opacity 0.3s ease-in 0.4s;
}

这段代码展示了前端动画的精髓。标题默认是隐藏的(opacity: 0),只有在面板被激活时才渐渐显示出来。特别注意那个0.4s的延迟,这就像是让标题演员等待正确的出场时机,让整个动画效果更加自然流畅。

5. JavaScript:交互的艺术

const panels = document.querySelectorAll('.qq-panel')
panels.forEach(panel => {
    panel.addEventListener('click', () => {
        removeActiveClasses()
        panel.classList.add('qq-panel--active')
    })
})

这段JavaScript代码看似简单,但处理用户交互的方式非常优雅。点击后,我们就把这个类加到点击元素上面,它就像一个训练有素的舞台监督:当观众(用户)点击某个演员(面板)时,首先让所有演员回到基础位置,然后让被选中的演员站到聚光灯下。

完整代码

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>

css部分

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    /* 弹性布局 pad 手机 尺寸不同 布局 flex */
    display: flex;
    /* 垂直方向居中 */
    align-items: center;
    /* 水平方向居中 */
    justify-content: center;
    /* 相对单位  view height 一屏高度100vh,等比例划分,一屏全部沾满*/
    height: 100vh;
    /* 超出隐藏 */
    overflow: hidden;
}

.container {
    /* 弹性布局 格式化上下文 */
    display: flex;
    /* 90% view width 视口宽度 */
    width: 90vw;
}

.qq-panel {
    height: 80vh;
    border-radius: 50px;
    color: #fff;
    cursor: pointer;
    margin: 10px;
    position: relative;
    flex: 0.5;
    /* 过度效果 元素样式改变后 all代表某一个样式改变 700ms表示时间 ease-in 表示一个变换的速度 */
    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;
    /* 从不可见到可见花了0.3秒 在0.4秒钟慢慢出现 */
    /* transition: all 700ms ease-in;我们上面展开时间用了0.7秒 */
    transition: opacity 0.3s ease-in 0.4s;
}

js部分

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')
    })
}

响应式设计的艺术

这个项目在响应式设计上也很用心。使用vw(视口宽度)和vh(视口高度)这样的相对单位,确保在不同尺寸的设备上都能完美展示。这就像是一件能自动调整尺寸的魔法衣服,无论是谁穿都合身!

用户体验的艺术

整个项目处处体现了对用户体验的追求:

  • 平滑的过渡动画让交互感觉自然
  • 恰到好处的延迟让动画节奏感十足
  • 简洁的界面设计不会让用户感到困惑

总结:前端开发就是艺术

这个看似简单的展开卡片效果,其实融合了现代前端开发的多个重要概念:

  • BEM命名规范的结构组织
  • Flex布局的灵活运用
  • CSS过渡动画的精确控制
  • JavaScript交互的优雅处理
  • 响应式设计的周到考虑