練習(xí) CSS 有一個(gè)比較有趣的方式,就是發(fā)揮想象,繪制各式各樣的圖案,比如來(lái)繪制一只思否貓?
思否貓,SegmentFault 思否[1]的吉祥物,是一只獨(dú)一無(wú)二、特立獨(dú)行、熱愛(ài)自由的(>^ω^<)獨(dú)角貓,也是社區(qū)的首席摸魚(yú)官。

你也可以提前查看完整代碼:CSS sifou cat (codepen.io)[2] 或者 CSS sifou cat (runjs.work)[3]。
其實(shí)還是有點(diǎn)小復(fù)雜的,不要慌,根據(jù)結(jié)構(gòu),可以拆分成頭、眼睛、眉毛、耳朵、鼻子、嘴巴、角這幾個(gè)部分,一起來(lái)看看如何實(shí)現(xiàn)的吧,有超級(jí)多的 CSS 繪制小技巧~
一、頭
首先是最外層頭的形狀,是一個(gè)不太規(guī)則的橢圓,可以用border-radius實(shí)現(xiàn),直接手寫(xiě)可能會(huì)有點(diǎn)不太準(zhǔn)確,可以借助這個(gè)圓角生成工具進(jìn)行微調(diào)。
https://9elements.github.io/fancy-border-radius[4]

假設(shè) HTML是這樣的。
那么,臉的形狀可以這樣來(lái)實(shí)現(xiàn)。
cat{
width: 400px;
height: 320px;
border-radius: 50% 50% 50% 50% / 60% 60% 40% 40%;
border: 3px solid #222224;
background: #fef2dc;
}
效果如下:

然后臉上還有兩個(gè)圓形的花紋,通過(guò)兩個(gè)徑向漸變繪制。
對(duì)徑向漸變不太熟悉的可以參考張?chǎng)涡窭蠋煹倪@篇文章:10個(gè)demo示例學(xué)會(huì)CSS3 radial-gradient徑向漸變[5]。
cat{
/**/
background: radial-gradient(circle at 20px 14px, #fff 6px, transparent 7px),
radial-gradient(circle at 12px 26px, #fff 3px, transparent 4px)
#222224 no-repeat;
}
效果如下:

哈哈,是不是有點(diǎn)像小孩頭發(fā)?
二、眼睛
接著來(lái)繪制眼睛,可以單獨(dú)用一個(gè)標(biāo)簽,然后用兩個(gè)偽元素繪制。
<cat>
<!-- 眼睛 -->
<eye></eye>
</cat>
眼睛比較簡(jiǎn)單,一個(gè)圓形加一個(gè)邊框,邊框可以用border或者box-shadow生成,然后通過(guò)絕對(duì)定位定位就行了。
eye::before,
eye::after{
position: absolute;
content: '';
width: 50px;
height: 50px;
background: #222224;
box-shadow: 0 0 0 10px #967c51;
border-radius: 50%;
}
eye::before{
left: 60px;
top: 100px;
}
eye::after{
right: 110px;
top: 110px;
}
效果如下:

現(xiàn)在有點(diǎn)傻乎乎的,需要加點(diǎn)高光,和前面一樣,用徑向漸變繪制兩個(gè)白色的圓就行了。
eye::before,
eye::after{
/**/
background: radial-gradient(circle at 20px 14px, #fff 6px, transparent 7px),
radial-gradient(circle at 12px 26px, #fff 3px, transparent 4px)
#222224 no-repeat;
}
效果如下:

看,有了高光立刻就不一樣了,炯炯有神。
三、眉毛
然后給眼睛上加點(diǎn)眉毛,左右兩側(cè)的眉毛是三根白色的弧線,弧線可以用border-radius加上border來(lái)繪制,只保留一個(gè)方向上的border,原理是這樣的。

由于一個(gè)元素只能繪制一條這樣的弧線,加上偽元素也只能繪制三條,所以這里用兩個(gè)標(biāo)簽。
<cat>
<!-- 眼睛 -->
<eye></eye>
<!-- 眉毛 -->
<eyebrow-l></eyebrow-l>
<eyebrow-r></eyebrow-r>
</cat>
然后借助偽元素,適當(dāng)旋轉(zhuǎn)調(diào)整。
eyebrow-l,
eyebrow-r{
position: absolute;
width: 60px;
height: 10px;
border-radius: 100%;
border: 2px solid #fff;
border-width: 2px 0 0 0;
}
eyebrow-l{
left: 80px;
top: 60px;
transform: rotate(30deg);
}
eyebrow-r{
right: 130px;
top: 60px;
transform: rotate(-35deg);
}
eyebrow-l::before,
eyebrow-l::after,
eyebrow-r::before,
eyebrow-r::after{
content: '';
position: absolute;
width: 50px;
height: 10px;
right: 0;
border-radius: 100%;
border: 2px solid #fff;
border-width: 2px 0 0 0;
transform-origin: right center;
}
eyebrow-l::before{
top: -10px;
transform: rotate(20deg);
}
eyebrow-l::after{
top: 10px;
transform: rotate(-15deg);
}
eyebrow-r::before,
eyebrow-r::after{
left: 0;
right: auto;
transform-origin: left center;
}
eyebrow-r::before{
top: -10px;
transform: rotate(-20deg);
}
eyebrow-r::after{
top: 10px;
transform: rotate(15deg);
}
效果如下:

現(xiàn)在有點(diǎn)可愛(ài)了吧~
四、耳朵
現(xiàn)在加上耳朵,這個(gè)相對(duì)比較容易,首先通過(guò)border-radius生成工具調(diào)整為一個(gè)弧形三角的形狀,如下:

HTML 中需要添加一個(gè)標(biāo)簽。
<cat>
<!-- 眼睛 -->
<eye></eye>
<!-- 眉毛 -->
<eyebrow-l></eyebrow-l>
<eyebrow-r></eyebrow-r>
<!-- 耳朵 -->
<ear></ear>
</cat>
耳朵的輪廓可以用不同的border繪制,實(shí)現(xiàn)如下:
ear::before{
position: absolute;
content: '';
width: 120px;
height: 200px;
left: -20px;
top: -50px;
border-radius: 79% 21% 0% 100% / 100% 56% 44% 0% ;
background-color: #9e5439;
transform: rotate(-36deg);
border: 10px solid #222224;
border-width: 5px 30px 0 10px;
z-index: -1;
}
效果如下:

現(xiàn)在耳朵里只有一種顏色,沒(méi)有層次感,可以通過(guò)內(nèi)陰影生成。
ear::before{
/**/
box-shadow: inset -40px -10px 0 #b68679,
inset -110px -80px 0 #b06648;
}
這樣就得到了層次分明的耳朵。

右耳朵也是同樣的方法,可以用::after來(lái)生成,代碼就不重復(fù)了,效果如下:

有了耳朵,這樣是不是就有點(diǎn)像一只貓了?
五、鼻子
接下來(lái)是鼻子,鼻子可以看成是一個(gè)半橢圓和一個(gè)圓三角,HTML如下,只需一個(gè)標(biāo)簽就行了。
<cat>
<!-- 眼睛 -->
<eye></eye>
<!-- 眉毛 -->
<eyebrow-l></eyebrow-l>
<eyebrow-r></eyebrow-r>
<!-- 耳朵 -->
<ear></ear>
<!-- 鼻子 -->
<nose></nose>
</cat>
半橢圓可以通過(guò)border-radius實(shí)現(xiàn),注意鼻子上的高光,圓角三角可以用一個(gè)圓角矩形旋轉(zhuǎn)45deg然后配合橫向縮放得到,圓角三角繪制過(guò)程如下:

具體實(shí)現(xiàn)如下:
nose{
position: absolute;
left: 140px;
top: 140px;
transform: rotate(5deg);
filter: drop-shadow(0 2px #b68679);
width: 46px;
height: 22px;
border-radius: 50% 50% 50% 50% / 80% 80% 20% 20%;
background: radial-gradient( 8px 4px at 60% 50%, rgba(255, 255, 255, 0.5) 100%, transparent 0) #fcbaa1 no-repeat;
z-index: 1;
}
nose::after{
content: '';
position: absolute;
width: 24px;
height: 24px;
border-radius: 5px;
background: linear-gradient(135deg, transparent 50%, #fcbaa1 0);
transform: scale(0.8,1) rotate(45deg);
left: 10px;
bottom: -6px;
z-index: -1;
}
這樣就得到了小巧玲瓏的鼻子~

六、嘴巴
嘴巴其實(shí)就是幾條弧線,和前面畫(huà)眉毛的方式類(lèi)似,通過(guò)用border-radius加上border來(lái)繪制,由于彎曲程度比較大,可以保留兩個(gè)方向上的border,繪制過(guò)程如下:

所以只需要一個(gè)標(biāo)簽,然后用兩個(gè)偽元素畫(huà)出嘴巴的兩條弧線。
<cat>
<!-- 眼睛 -->
<eye></eye>
<!-- 眉毛 -->
<eyebrow-l></eyebrow-l>
<eyebrow-r></eyebrow-r>
<!-- 耳朵 -->
<ear></ear>
<!-- 鼻子 -->
<nose></nose>
<!-- 嘴巴 -->
<mouth></mouth>
</cat>
具體實(shí)現(xiàn)如下,注意一下旋轉(zhuǎn)中心軸:
mouth{
position: absolute;
left: 159px;
top: 170px;
width: 2px;
height: 30px;
border: 3px solid #222224;
border-width: 0 0 0 2px;
border-radius: 100%;
}
mouth::before{
content: '';
position: absolute;
left: 0;
bottom: 0;
width: 60px;
height: 20px;
border-radius: 0 0 0 20px;
border: 2px solid #222224;
border-width: 0 0 2px 2px;
transform: translate(-100%) rotate(-20deg);
transform-origin: right bottom;
}
mouth::after{
content: '';
position: absolute;
right: 3px;
bottom: 0;
width: 80px;
height: 30px;
border-radius: 0 0 30px 0;
border: 2px solid #222224;
border-width: 0 2px 2px 0;
transform: translate(100%) rotate(25deg);
transform-origin: left bottom;
}
嗯,一只可愛(ài)的小貓咪就出現(xiàn)了。

七、角
最后,加上思否貓獨(dú)特的標(biāo)識(shí),獨(dú)角。
這部分算是這里面最復(fù)雜的一塊了,整體外形是一個(gè)圓錐形,同樣可以借助border-radius生成工具調(diào)整出來(lái)。

然后左側(cè)的高光可以用內(nèi)陰影模擬,螺紋形狀可以用徑向漸變繪制,繪制過(guò)程如下:

角的下面還有三個(gè)彩色的小標(biāo)記(暫時(shí)還不知道叫什么??)(官方介紹叫代碼縮影>代碼光波??)。

由于形狀相同,只需繪制一個(gè),其他兩個(gè)可以直接用?box-shadow生成,向兩個(gè)方向投射。

同樣只需要一個(gè)標(biāo)簽:
<cat>
<!-- 眼睛 -->
<eye></eye>
<!-- 眉毛 -->
<eyebrow-l></eyebrow-l>
<eyebrow-r></eyebrow-r>
<!-- 耳朵 -->
<ear></ear>
<!-- 鼻子 -->
<nose></nose>
<!-- 嘴巴 -->
<mouth></mouth>
<!-- 角 -->
<horn></horn>
</cat>
具體實(shí)現(xiàn)如下:
horn{
position: absolute;
width: 40px;
height: 120px;
border-radius: 52% 48% 50% 50% / 93% 93% 7% 7% ;
background: #808087;
box-shadow: inset 10px -14px 0 -10px #808087, inset 24px -14px 0 -14px #b6b8be;
border: 3px solid #808087;
left: 165px;
top: -110px;
transform-origin: center bottom;
transform: rotate(-20deg);
}
horn::before{
content: '';
position: absolute;
inset: 0;
border-radius: 52% 48% 50% 50% / 93% 93% 7% 7% ;
background: repeating-radial-gradient( circle at 36px 0px,#b6b8be 30px 34px, transparent 35px 61px),
repeating-radial-gradient( circle at 36px 0px,#808087 34px 38px, transparent 39px 65px);
}
horn::after{
content: '';
position: absolute;
bottom: -25px;
transform: rotate(20deg);
width: 12px;
height: 4px;
border-radius: 4px;
background-color: #f6f090;
box-shadow: 18px 0 0 #d56564, -18px 0 0 #a2a9a6;
}
完成!

完整代碼可以查看:CSS sifou cat (codepen.io)[6] 或者 CSS sifou cat (runjs.work)[7]
八、總結(jié)一下
哦對(duì)了,本文繪制的效果并不是完全和原圖一致,很多地方做了改動(dòng),主要是原圖偏手繪風(fēng)格,很多線條都比較隨意,尤其是頭上的角,思索半天,簡(jiǎn)化成了本文的效果,下方是官方原圖:

不過(guò),從整體神情上還是有八九分相似的??下面總結(jié)一下繪制的幾個(gè)小技巧:
- 圓形、不太規(guī)則的橢圓都可以考慮用border-radius,可視化生成工具可以很方便地完成。
- 弧線可以用border-radius配合局部border生成。
- 圓形高光背景可以用radial-gradient繪制。
- 側(cè)邊高光還可以用內(nèi)陰影來(lái)實(shí)現(xiàn)。
- 圓角三角可以通過(guò)旋轉(zhuǎn)圓角矩形得到。
- 相同形狀可以用box-shadow生成多份。
- 各種繪制技巧靈活使用。
當(dāng)然實(shí)際工作中,我是不推薦繪制這么復(fù)雜的圖形的,主要是了解 CSS 繪制的相關(guān)技巧,碰到一些簡(jiǎn)單的圖標(biāo)、自適應(yīng)尺寸、顏色可變的圖形就綽綽有余了。