辞旧迎新,纯 CSS 实现手绘新年贺卡,城市星河与祝福一并奉上
old school 与回忆
我记得上学的时候,很喜欢互赠纸质贺卡。有一段时间,立体贺卡特别流行,深受大家的喜欢。
随后,伴随着互联网的发展,诞生了电子贺卡,不仅寄送方便,而且可以播放音乐和动画效果,且是免费的。因此电子贺卡逐渐成为人们相互问候的优先选择。
再后来,无论是电子贺卡,还是纸质贺卡,都逐渐淡出大众的视野。偶尔,出去旅游,会购买当地特色的明信片作为伴手礼。听说在有「世界尽头」之称的乌斯怀亚,有一间小邮局,如果有机会还蛮想去,买一张明信片,上面有“世界尽头邮政”字样,可以买来现场填写地址后邮寄到全球各地。
岁末将至,敬颂冬绥。想到好久不见的贺卡,在这个新旧交接的岁末,想用复古一些的方式,给朋友们送一份祝福。
因为大家天南海北的,电子贺卡比较方便,于是,我想到用 CSS 绘制一张新年贺卡,送给五湖四海的朋友。

新年贺卡
叮,有一封来自叶一一的手绘新年贺卡,请查收来~
3D 翻转
两种翻转
我一共设计了两种翻转,第一个是抽出卡片时的自动翻转,另一个是通过点击卡片的手动翻转。
因为两种翻转都是通过点击卡片触发的,所以用到同一个方法处理两种交互。我是通过设置了一个点击计数:count,区分不同的触发方式的。
// 触发计数,初始为0
var count = 0;
card.addEventListener('click', e => {
// 当count值大于等于1时,表示进行的手动翻转
if (count >= 1) {
card.classList.toggle('overturn');
} else {
/*
* 当count值小于1时,表示需要进行自动翻转
* 自动翻转前,需要将信封去掉,卡片向上滑动
* */
envelope.style.display = 'none';
cardWarp.classList.add('card-up');
setTimeout(function () {
card.classList.add('overturn');
}, 1000);
}
count++;
});
3D 翻转效果
首先需要允许子元素位于 3D 空间中。需要将元素的 transform-style 属性设置为 preserve-3d。这样,在元素进行翻转的时候,子元素会才会有 3D 转换的效果。
实际的翻转效果是通过为元素的两个属性组合实现的,一个是翻转切换的动画,另一个是背向用户时不可见。
- 翻转动画通过 transform 设置 3D 转换效果即可,元素沿 X 轴和 Z轴进行旋转;
- 背向用户时不可见,是通过设置 backface-visibility 的属性为 hidden。它的值为 visible 时,表示可见。
.card {
position: relative;
transform-style: preserve-3d;
height: 100%;
width: 100%;
transition: transform 2s ease-in;
}
.card.overturn {
transform: matrix3d(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1);
}
.card-back {
display: flex;
flex-direction: column;
align-items: center;
transform: matrix3d(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1);
}
.card-item {
backface-visibility: hidden;
}
城市星河
星河璀璨
一个标签,轻松实现繁星效果。
只需要一个 2px * 2px 的 DIV 即可,剩下的就交给 box-shadow。
box-shadow 不仅可以画心,还可以画星星。
.stars {
width: 2px;
height: 2px;
border-radius: 100%;
box-shadow: 10px 0px #cfcfc6, 40px 2px #cfcfc6, 70px 0px #cfcfc6, 110px 3px #cfcfc6, 140px 0px #cfcfc6, 190px 2px #cfcfc6, 240px 0px #cfcfc6, 270px 5px #cfcfc6, 320px 0px #cfcfc6, 5px 20px #cfcfc6, 50px 24px #cfcfc6, 100px 30px #cfcfc6, 120px 30px #cfcfc6, 150px 24px #cfcfc6, 180px 30px #cfcfc6, 240px 24px #cfcfc6, 270px 26px #cfcfc6, 300px 30px #cfcfc6, 10px 40px #cfcfc6, 40px 45px #cfcfc6, 70px 45px #cfcfc6, 110px 44px #cfcfc6, 140px 48px #cfcfc6, 2px 50px #cfcfc6, 30px 55px #cfcfc6, 60px 60px #cfcfc6, 90px 70px #cfcfc6, 130px 68px #cfcfc6, 2px 70px #cfcfc6, 20px 77px #cfcfc6, 40px 66px #cfcfc6, 60px 80px #cfcfc6, 100px 90px #cfcfc6, 150px 80px #cfcfc6, 180px 70px #cfcfc6, 200px 80px #cfcfc6, 230px 77px #cfcfc6;
position: absolute;
}
城市灯火
同样是一个标签,实现灯火通明的大厦效果。
灯火样式和楼层样式,均使用伪元素实现。
灯火效果,使用 box-shadow,基本繁星效果一摸一样。
楼层效果,也使用 box-shadow,不过楼层是竖线,所以需要 设置和父元素等长的高度。
.builds {
width: 70px;
height: 160px;
border-radius: 5px 5px 0 0;
background: #193f71;
position: absolute;
overflow: hidden;
}
.builds::after {
content: '';
position: absolute;
top: 0;
width: 2px;
height: 2px;
border-radius: 100%;
background: transparent;
box-shadow: 25px 10px #5e9cbd, 24px 60px #5e9cbd, 20px 70px #5e9cbd, 18px 90px #5e9cbd, 23px 120px #5e9cbd, 23px 140px #5e9cbd, 36px 28px #5e9cbd, 36px 70px #5e9cbd, 36px 160px #5e9cbd, 46px 10px #5e9cbd, 50px 60px #5e9cbd, 42px 90px #5e9cbd, 46px 120px #5e9cbd, 58px 20px #5e9cbd, 60px 80px #5e9cbd, 60px 120px #5e9cbd, 60px 160px #5e9cbd, 76px 10px #5e9cbd, 76px 60px #5e9cbd, 76px 80px #5e9cbd, 70px 130px #5e9cbd;
z-index: 99;
}
.builds::before {
content: '';
position: absolute;
top: 0;
width: 2px;
height: 100%;
border-radius: 100%;
background: transparent;
box-shadow: 12px 0px #295485, 24px 0px #295485, 36px 0px #295485, 48px 0px #295485, 60px 0px #295485, 72px 0px #295485;
z-index: 99;
}
人间皆安
这万千灯火中,总有一盏是为我们点亮的。仰起头就能看到,属于家的柔和的灯光。
这就是我设计这个建筑的初衷。每扇窗户后面,是一个关于家的温馨故事。
窗户
一个标签,实现窗户效果。
窗户是带边框的矩形,上面的隔档,使用伪元素即可。
.casement {
width: 70px;
height: 100px;
background: #ffe097;
position: absolute;
left: 30px;
border: 2px solid #453d52;
overflow: hidden;
}
.casement::before {
content: '';
position: absolute;
top: 0;
left: 50%;
width: 4px;
height: 100%;
margin-left: -2px;
background: #453d52;
z-index: 99;
}
窗帘
窗帘的实现还是很有趣的。
依旧是一个标签完成窗帘的效果。窗帘收起来的效果,主要在于图形结合圆角的设置。
窗帘上半部分较长,下半部分较短,符合日常对窗帘的认知。设置上下两个图形一个角度上的弧度,组合在一起形成被收起的效果。
.curtain {
position: absolute;
z-index: 10;
top: 0;
right: 0;
}
.curtain::before,
.curtain::after {
content: '';
position: absolute;
background: #bda16a;
}
.curtain::before {
width: 30px;
height: 70px;
top: 0;
right: -5px;
border-radius: 0 0 0 100%;
}
.curtain::after {
width: 20px;
height: 34px;
top: 67px;
right: -5px;
border-radius: 100% 0 0 0;
}
最终效果

彩蛋时刻
这个彩蛋是我抓住的稍纵即逝的灵感,有那么点「棋魂」里的神之一手的感觉。
先观察
我们来拆解一下这个 LOGO。无论是顺时针还是逆时针旋转45度,都可以将它拆解为三个部分:
一个正方形、一个折线、另一个折线。
后实现
正方形的实现还是很简单的。
而折线可以看做是缺少两个边的正方形,只需要完成一对相邻的边即可。
而作为除了正方形以外的唯二两个图形。两个折线使用伪类实现即可。
最终我会将图形进行逆时针旋转,所以相邻两个边选择了图形的右侧和下侧。
三个部分实现完成,还需要一个步骤,那就是图形旋转, 根据需要顺时针旋转45度。
这个时候就能得到最终的 LOGO,将 LOGO 摆放在贺卡中,最大最有设计特色的大厦即可。
总结
这次实现的新年贺卡的元素较多,但是大部分使用一个标签完成了实现,使得整体结构偏简洁。当然也在于我日常对图形实现经验在不断的练习中,得到了很好的积累。盖业精于勤也。
最后,送上叶一一的祝福
愿山河无恙,人间皆安,春风如故,桑梓依然。多喜乐,长安宁,岁无忧,久安康。
一月月相似,一年年不同
每个月都好像匆匆忙忙就过去了,唯有回望的时候,才发现这一年的不同。今年很多收获都离不开阅读。
读《命运》,重新审视这个词汇,靠着为数不多的经验,总结出一条人生经验:要好好的活着,因为人生一定会遇到好事的。
看《算命》,不再纠结活着的意义,因为感悟出:活着本身就是最大的意义。
读《季羡林散文》,解锁了人生的界石。今后的路怎么走?向着有亮光的地方前行。
翻阅了许许多多的沸点,于是我收获了诸多好友。
新的一年要开篇了,虽然我不晓得怎么去写年,但是我可以用写文章的方式去记录它。
我一直不晓得怎么去写「年」。它是,一个单位呢?一种风景呢?还是一本特别记事本?说它度量了岁月,但是「年年岁岁花相似,岁岁年年人不同」,它却处处有风景。说它记录了四季景色,但是「入春才七日,离家已二年」,它又成了离愁别绪中的岁月。
转载自:https://juejin.cn/post/7181395913867280442