引言
时间像流水般匆匆而过, 一眨眼中秋节就要到了!! 既然如此那就让我用 CSS
画一对 相互依偎的情侣兔
吧!!! 借此祝福大家, 相信在月圆之夜, 有情人终将团圆, 共享美满幸福的时刻!! 在这个特殊的中秋节里, 让我们一同感受爱情的魅力 🐶🐶🐶🐶🐶
如图就是我们今天要绘制的 情侣兔
, 下面将会针对图上几个难点(耳朵、眼睛、嘴巴、眉毛、腮红…)进行一个拆解, 至于完整的绘制代码可以查看这几个👇🏻链接
-
codepen: codepen-mdawQxm
-
codesandbox: codesandbox-wen-zhang-demo-qing-lu-tu
-
掘金代码片段: pen/7278847094494855223
-
参考图片地址: Mid-Autumn-Festival-posters
一、兔子耳朵
如图, 是
耳朵
部分的一个绘制过程
- 最初是由嵌套的一组长方形组成
- 通过设置圆角, 变成椭圆
- 通过设置投影, 增加立体感
- 最后通过
transform
进行一个旋转
- 基本框架: 其实就是一个
div
配合伪元素::after
组成嵌套长方形, 并且通过flex
进行简单的布局, 并设置基本的宽高、背景色(包括外层的实色背景、内层的渐变背景)
<style>
.ear {
width: 160px;
display: flex;
justify-content: space-between;
.ear-left,
.ear-right {
width: 40px;
height: 150px;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
&::after {
content: "";
width: 50%;
height: 50%;
display: block;
background: linear-gradient(#e5a9ab, #fcf8f7);
}
}
}
</style>
<div class="ear">
<div class="ear-left"></div>
<div class="ear-right"></div>
</div>
- 设置圆角: 这里为每一组的内外两个长方形设置圆角, 这里需要补充一点 border-radius 实际上是可以设置八个值的, 具体的细节这里就不展开了, 而这边之所以这么写目的是为了让耳朵整体开起来更自然点
<style>
.ear {
...
.ear-left,
.ear-right {
...
+ border-radius: 45% 45% 50% 50% / 45% 45% 50% 50%;
&::after {
....
+ border-radius: 45% 45% 50% 50% / 45% 45% 50% 50%;
}
}
}
</style>
- 设置投影: 这里通过 box-shadow 为每个矩形设置不一样的投影
<style>
.ear {
....
.ear-left,
.ear-right {
...
+ box-shadow: inset 0 4px 4px 4px #ccc;
}
+ .ear-left {
+ &::after {
+ box-shadow: inset -1px 2px 0 1px #cf7674;
+ }
+ }
+
+ .ear-right {
+ &::after {
+ box-shadow: inset 1px 2px 0 1px #cf7674;
+ }
+ }
+ }
</style>
- 旋转: 最后最后通过 transform 为两个耳朵进行一个小幅度的旋转
<style>
.ear {
...
.ear-left,
.ear-right {
...
&::after {
...
+ transform-origin: center center;
}
}
.ear-left {
+ transform: rotate(-15deg);
...
}
.ear-right {
+ transform: rotate(15deg);
...
}
}
</style>
- 下面是本节, 也就是
两个耳朵
的一个完整的实现代码
<style>
body {
padding: 100px;
background-color: #c9daf8;
}
.ear {
width: 160px;
display: flex;
justify-content: space-between;
.ear-left,
.ear-right {
width: 40px;
height: 150px;
background-color: #fff;
display: flex;
align-items: center;
justify-content: center;
border-radius: 45% 45% 50% 50% / 45% 45% 50% 50%;
box-shadow: inset 0 4px 4px 4px #ccc;
&::after {
content: "";
width: 50%;
height: 50%;
display: block;
background: linear-gradient(#e5a9ab, #fcf8f7);
border-radius: 45% 45% 50% 50% / 45% 45% 50% 50%;
transform-origin: center center;
}
}
.ear-left {
transform: rotate(-15deg);
&::after {
box-shadow: inset -1px 2px 0 1px #cf7674;
}
}
.ear-right {
transform: rotate(15deg);
&::after {
box-shadow: inset 1px 2px 0 1px #cf7674;
}
}
}
</style>
<div class="ear">
<div class="ear-left"></div>
<div class="ear-right"></div>
</div>
补充说明: 从最终的图可以发现, 兔子耳朵实际上底部是缺了一小段的, 这里其实是通过一个白色遮罩盖住了(如下图所示), 当然为了过渡显得自然点, 对于遮罩可以简单给个渐变或者投影
二、公兔眼睛
如图, 是
公兔眼睛
的一个绘制过程
- 最初是由嵌套
3 个正方形
组成- 通过设置圆角, 变成椭圆
- 通过
transform
进行一个旋转- 通过定位, 设置眼白的位置
- 最后通过
box-shadow
给眼白设置一个阴影
- 基本结构: 通过一个
div
配合两个伪元素(::before
、::after
)完成3 个正方形
的实现, 并设置基本的宽高、背景色
<style>
.male {
width: 160px;
display: flex;
justify-content: space-between;
.eye-left,
.eye-right {
width: 20px;
height: 25px;
background-color: #ba300e;
&::before,
&::after {
content: "";
display: block;
background-color: #fff;
}
&::before {
width: 8px;
height: 8px;
}
&::after {
width: 3px;
height: 3px;
}
}
}
</style>
<div class="male">
<div class="eye-left"></div>
<div class="eye-right"></div>
</div>
- 设置圆角: 同耳朵那节, 通过 border-radius 为眼球设置不同的圆角, 实现鹅软石般的大眼睛
<style>
.male {
...
.eye-left,
.eye-right {
...
+ border-radius: 50% 50% 60% 60% / 50% 50% 60% 60%;
&::before,
&::after {
+ border-radius: 50%;
background-color: #fff;
}
...
}
}
</style>
- 旋转: 通过 transform 将眼睛进行小角度的旋转
<style>
.male {
...
.eye-left,
.eye-right {
....
}
+ .eye-left {
+ transform: rotate(-45deg);
+ }
+
+ .eye-right {
+ transform: rotate(45deg);
+ }
}
</style>
- 眼白定位: 使用 position 将眼白定位到正确的位置
<style>
.male {
...
.eye-left,
.eye-right {
...
+ position: relative;
...
&::before,
&::after {
...
+ position: absolute;
...
}
...
}
.eye-left {
...
+ &::before {
+ top: 6px;
+ left: 10px;
+ }
+
+ &::after {
+ top: 5px;
+ left: 3px;
+ }
}
.eye-right {
transform: rotate(45deg);
+ &::before {
+ top: 5px;
+ right: 10px;
+ }
+ &::after {
+ top: 2px;
+ right: 5px;
+ }
}
}
</style>
- 设置阴影: 这里通过 box-shadow 为眼白设置一个白色的阴影, 让整体看起来不显得生硬
<style>
.male {
...
.eye-left,
.eye-right {
...
&::before {
...
+ box-shadow: 0 0 4px #fff;
}
&::after {
...
+ box-shadow: 0 0 2px #fff;
}
}
...
}
</style>
- 下面是本节, 也就是
公兔的两个眼睛
的一个完整的实现代码
<style>
body {
padding: 100px;
background-color: #c9daf8;
}
.male {
width: 160px;
display: flex;
justify-content: space-between;
.eye-left,
.eye-right {
width: 20px;
height: 25px;
position: relative;
background-color: #ba300e;
border-radius: 50% 50% 60% 60% / 50% 50% 60% 60%;
&::before,
&::after {
content: "";
display: block;
border-radius: 50%;
background-color: #fff;
position: absolute;
}
&::before {
width: 8px;
height: 8px;
}
&::after {
width: 3px;
height: 3px;
}
}
.eye-left {
transform: rotate(-45deg);
&::before {
top: 6px;
left: 10px;
}
&::after {
top: 5px;
left: 3px;
}
}
.eye-right {
transform: rotate(45deg);
&::before {
top: 5px;
right: 10px;
}
&::after {
top: 2px;
right: 5px;
}
}
}
</style>
<div class="male">
<div class="eye-left"></div>
<div class="eye-right"></div>
</div>
三、兔子嘴巴
嘴巴部分, 简单来看其实就是一个带有 圆角
的 三角形
, 其实如果只是一个三角形那么这里其实完全可以通过 border 来实现, 但偏偏这里是带有圆角的, 那么通过 border 是没法直接实现的;
所以需要换个思路, 如下图所示可以通过三个圆角的菱形、拼凑而成!
那么问题就回到如果设置一个菱形了, 这里可以使用 transform
实现, 下面直接看完整代码…
<style>
body {
padding: 100px;
background-color: #c9daf8;
}
.mouth {
width: 10px;
height: 10px;
background-color: rgba(255, 0, 0, 0.5);
border-bottom-left-radius: 3px;
transform: rotate(327deg) skewX(20deg) scale(1, 0.866);
&::before,
&::after {
content: "";
width: 100%;
height: 100%;
display: block;
background-color: inherit;
border-bottom-left-radius: 4px;
}
&::before {
background-color: rgba(0, 255, 0, 0.5);
transform: rotate(135deg) skewY(-45deg) scale(0.707, 1.414) translate(-50%, 0);
}
&::after {
background-color: rgba(0, 0, 255, 0.5);
transform: rotate(-135deg) skewX(-45deg) scale(1.414, 0.707) translate(100%, 150%);
}
}
</style>
<div class="mouth"></div>
四、眉毛
如图, 是
眉毛
的一个绘制过程
- 由一个正方形绘制而成
- 首先设置圆角, 变成一个扇形
- 通过
box-shadow
在扇形弧度的边缘绘制边框(也就是眉毛部分)- 移除背景色: 最初为了调试方便所以设置了一个背景色, 所以需要移除
- 最后通过
transform
将眉毛旋转到正确位置
- 基础结构: 下面是基础代码, 一个
div
配合两个伪元素(::after
、::before
)创建两个正方形, 并设置了基础宽高、背景色
<style>
.eyebrow {
width: 40px;
display: flex;
justify-content: space-between;
&::after,
&::before {
content: "";
width: 14px;
height: 14px;
display: block;
background-color: #ff7875;
}
}
</style>
<div class="eyebrow"></div>
- 设置圆角: 通过 border-radius 为左上角设置一个圆角, 完成一个扇形的绘制
<style>
.eyebrow {
...
&::after,
&::before {
...
+ border-top-left-radius: 100%;
}
}
</style>
- 设置投影: 这里通过 box-shadow 来设置投影, 投影在
x
轴和y
轴的偏移都设置为-1px
这样的话就产生一个弧线
<style>
.eyebrow {
...
&::after,
&::before {
...
+ box-shadow: -1px -1px #290604;
}
}
</style>
- 移除背景色: 这里背景色是多余的, 最初之所以设置了背景色, 是为了调试方便才设置了一个背景色, 所以这里需要移除掉
<style>
.eyebrow {
...
&::after,
&::before {
...
- background-color: #ff7875;
...
}
}
</style>
- 旋转: 最后最后通过 transform 为将眉毛调整下角度
<style>
.eyebrow {
....
&::after,
&::before {
...
+ transform: rotate(45deg);
}
}
</style>
- 下面是本节, 也就是
眉毛
部分的一个完整的实现代码
<style>
body {
padding: 100px;
background-color: #c9daf8;
}
.eyebrow {
width: 40px;
display: flex;
justify-content: space-between;
&::after,
&::before {
content: "";
width: 14px;
height: 14px;
display: block;
border-top-left-radius: 100%;
box-shadow: -1px -1px #290604;
transform: rotate(45deg);
}
}
</style>
<div class="eyebrow"></div>
五、母兔大眼睛
母兔眼睛绘制起来相对会麻烦一点, 这里我们将进行拆解成三部分进行讲解: 眼睫毛、眼球、下睫毛
5.1 眼睫毛
如图, 是
眼睫毛
的一个绘制过程
- 由两个正方形绘制而成
- 首先设置圆角, 变成两个扇形
- 通过
border
设置右边框
, 和圆角
配合就形成一个睫毛- 移除背景色: 最初为了调试方便所以设置了一个背景色, 所以需要移除
- 最后通过
transform
将睫毛偏移、旋转到正确位置
- 基本结构: 由一个
div
中的两个伪元素(::before
、::after
)生成两个正方形, 并设置了基础宽高、背景色
<style>
.eyelid {
&::after,
&::before {
content: "";
width: 6px;
height: 6px;
display: block;
background-color: #ff7875;
}
}
</style>
<div class="eyelid"></div>
- 设置圆角: 通过 border-radius 为两个正方形的右上角设置一个圆角, 形成两个扇形
<style>
.eyelid {
&::after,
&::before {
...
+ border-top-right-radius: 100%;
}
}
</style>
- 设置边框: 通过 border 设置一个
右边框
, 这时与圆角
结合就会形成一个小睫毛
<style>
.eyelid {
&::after,
&::before {
...
+ border-right: 2px solid #290604;
}
}
</style>
- 移除背景色: 这里背景色是多余的, 最初之所以设置了背景色, 是为了调试方便才设置了一个背景色, 所以这里需要移除掉
<style>
.eyelid {
&::after,
&::before {
...
- background-color: #ff7875;
...
}
}
</style>
- 旋转偏移: 最后就是通过 transform 将两个睫毛通过偏移、旋转组合在一起
<style>
.eyelid {
&::after,
&::before {
...
}
+ &::before {
+ transform-origin: bottom right;
+ transform: translateY(100%) rotate(40deg);
+ }
}
</style>
- 下面是本节, 也就是
眼睫毛
部分的一个完整的实现代码
<style>
body {
padding: 100px;
background-color: #c9daf8;
}
.eyelid {
&::after,
&::before {
content: "";
width: 6px;
height: 6px;
display: block;
border-top-right-radius: 100%;
border-right: 2px solid #290604;
}
&::before {
transform-origin: bottom right;
transform: translateY(100%) rotate(40deg);
}
}
</style>
<div class="eyelid"></div>
5.2 眼球
如图, 是
眼球
的一个绘制过程
- 由三个正方形绘制而成
- 首先设置圆角, 变成三个圆
- 通过
border
为最外层圆形(眼球)设置边框- 通过
position
将眼白定位到正确的位置- 最后通过
box-shadow
给眼白设置一个阴影, 简单过渡下
- 基本结构: 通过一个
div
配合两个伪元素(::before
、::after
)绘制三个正方形, 并设置了基础宽高、背景色
<style>
.eye {
width: 20px;
height: 20px;
position: relative;
background-color: #fff;
&::before,
&::after {
content: "";
display: block;
position: absolute;
}
&::before {
width: 8px;
height: 8px;
background-color: #360703;
}
&::after {
width: 2px;
height: 2px;
background-color: #fff;
}
}
</style>
<div class="eye"></div>
- 设置圆角: 通过 border-radius 将正方形转为圆形
<style>
.eye {
...
+ border-radius: 50%;
&::before,
&::after {
content: "";
...
+ border-radius: 50%;
}
...
}
</style>
- 设置边框: 通过 border 为最外层圆形(眼球)设置边框
<style>
.eye {
...
+ border: 2px solid #290604;
...
}
</style>
- 定位组合: 使用 position 将眼白定位到正确的位置
<style>
.eye {
...
&::before {
...
+ right: 1px;
+ bottom: 1px;
background-color: #360703;
}
&::after {
...
+ right: 2px;
+ bottom: 3px;
background-color: #fff;
}
}
</style>
- 设置阴影: 通过 box-shadow 为眼白设置一个白色阴影, 目的只是为了让过滤自然点
<style>
.eye {
...
&::after {
...
+ box-shadow: 0 0 2px #fff;
background-color: #fff;
}
}
</style>
- 下面是本节, 也就是
眼球
部分的一个完整的实现代码
<style>
body {
padding: 100px;
background-color: #c9daf8;
}
.eye {
width: 20px;
height: 20px;
position: relative;
background-color: #fff;
border-radius: 50%;
border: 2px solid #290604;
&::before,
&::after {
content: "";
display: block;
position: absolute;
border-radius: 50%;
}
&::before {
width: 8px;
height: 8px;
right: 1px;
bottom: 1px;
background-color: #360703;
}
&::after {
width: 2px;
height: 2px;
right: 2px;
bottom: 3px;
box-shadow: 0 0 2px #fff;
background-color: #fff;
}
}
</style>
<div class="eye"></div>
5.3 下睫毛
这部分的实现方案, 和眉毛部分基本是一样的!! 这里就不一一展开了, 下面直接看代码
<style>
body {
padding: 100px;
background-color: #c9daf8;
}
.eyelid {
width: 10px;
height: 10px;
border-radius: 100% 0 0;
background-color: #f8ded9;
box-shadow: -1px -1px 0 0 #290604;
transform: rotate(23deg);
}
</style>
<div class="eyelid"></div>
5.4 合并
最后一步, 如图所示, 就是将上面完成的几个小部件, 通过定位也好, 偏移也好将它们组合合并起来, 这里就不展开了…
六、腮红
最后再顺便讲解下, 腮红
的实现!! 这里其实是通过 box-shadow 实现的, 相对比较很简单, 直接看代码
<style>
body {
padding: 100px;
background-color: #c9daf8;
}
.blusher {
width: 0;
height: 0;
display: block;
top: 48px;
position: absolute;
border-radius: 50%;
background-color: #e68d84;
box-shadow: 0 0 10px 8px #e68d84;
}
</style>
<div class="blusher"></div>
最后的结果大概就如图所示:
七、总结
到此, 情侣兔
绘制难点基本都已经讲到了, 剩下的工作其实就是将它们进行合并、组装起来, 具体的细节这里就不展开了!!!最后再贴下几个源码链接:
-
codepen: codepen-mdawQxm
-
codesandbox: codesandbox-wen-zhang-demo-qing-lu-tu
-
掘金代码片段: pen/7278847094494855223
-
参考图片地址: Mid-Autumn-Festival-posters