萬(wàn)能的CSS 漸變!單標(biāo)簽繪制一個(gè)足球場(chǎng)
世界杯正在進(jìn)行中,也不要忘記學(xué)習(xí) CSS(得想辦法蹭一波熱度)。比如,用 CSS 繪制一個(gè)足球場(chǎng)?
CSS 足球場(chǎng)
一眼望去,這里的形狀只有圓形和矩形,在不借助其他標(biāo)簽的情況下(包括偽元素),其實(shí)很容易聯(lián)想到漸變,一起看看如何繪制的吧,有非常多的漸變小技巧~
溫馨提示:文章中帶有“??”的描述屬于足球小知識(shí),不感興趣的可以跳過(guò),與 CSS 無(wú)關(guān)。
一、場(chǎng)地的尺寸設(shè)計(jì)
首先來(lái)看一下足球場(chǎng)的構(gòu)造,下面是在網(wǎng)上找到的一張?jiān)O(shè)計(jì)圖。
球場(chǎng)設(shè)計(jì)圖
主要有以下幾個(gè)部分:
- 整體是矩形,邊線和底線,長(zhǎng)度是 109~131碼(90~120m),寬度是 49-98碼(45~90m)。
- 中線,貫穿球場(chǎng)。
- 開(kāi)球點(diǎn),位于中線的中心。
- 中圈,以開(kāi)球點(diǎn)為圓形,半徑為 10碼(9.15m)圓。
- 罰球區(qū)(大禁區(qū)),長(zhǎng)度是44碼(40.3m),寬度是18碼(16.5m)。
- 球門區(qū)(小禁區(qū)),長(zhǎng)度是20碼(18.3m),寬度是6碼(5.5m)。
- 球門,長(zhǎng)度是8碼(7.32m)。
- 罰球點(diǎn)(點(diǎn)球點(diǎn)),距離球門12碼(11m)。
- 罰球?。ń麉^(qū)?。?,以罰球點(diǎn)為圓心,半徑為 10碼(9.15m)的圓弧。
- 角球區(qū),以4個(gè)角為圓心,半徑為 1m的 1/4 圓弧。
??現(xiàn)代足球運(yùn)動(dòng)起源于英國(guó),當(dāng)時(shí)英制的長(zhǎng)度單位是“碼”,1碼等于0.9144米,約0.915米。 那么,英制長(zhǎng)度10碼換算成公制長(zhǎng)度就是9.15米。 這就是9.15米的來(lái)源。
二、邊線和底線
以世界杯比賽場(chǎng)地為例,長(zhǎng)度115碼(105m),寬度74碼(68m)。
??2022世界杯決賽將在盧賽爾球場(chǎng)舉行,它由中國(guó)鐵建國(guó)際集團(tuán)承建。
假設(shè) HTML結(jié)構(gòu)如下,這里用到的標(biāo)簽僅僅只有一個(gè)。
為了尺寸計(jì)算方便,采用em相對(duì)單位進(jìn)行換算,數(shù)值就可以采用真實(shí)的“碼”,好處是都是整數(shù),簡(jiǎn)單繪制一下外圍邊線和底線,如下:
注意這里實(shí)現(xiàn)的小細(xì)節(jié):這里外層的線框是通過(guò)outline實(shí)現(xiàn)的,還預(yù)留了一個(gè)5em的透明邊框,這是因?yàn)楸尘暗奈恢煤统叽绨俜直扔?jì)算是根據(jù)內(nèi)容區(qū)域的,并不包含邊框。比如,background-postion:0 0表示的就是線框內(nèi)的左上點(diǎn),background-postion: 100% 100%表示的就是線框內(nèi)的右下點(diǎn),,background-size: 100%表示的就是線框內(nèi)最大尺寸,如下:
透明邊框的好處
還有一個(gè)好處,透明邊框仍然是可以繪制背景的,比如深淺不同的草皮就可以繪制在邊框之外,這個(gè)后面再說(shuō)。
準(zhǔn)備工作完成了,下面是具體的繪制過(guò)程。
三、中線、開(kāi)球點(diǎn)和中圈
在繪制之前,可以簡(jiǎn)單規(guī)劃一下,通過(guò) CSS 變量將各部分分離開(kāi)來(lái),這樣看起來(lái)會(huì)更加清晰,例如:
這個(gè)技巧在之前這篇文章中有相關(guān)介紹:??由 transform 被占用引發(fā)的思考????
首先是中線,使用線性漸變linear-gradient。
可能有些同學(xué)還不太清楚上面這一段 background的簡(jiǎn)寫,可以看下面這張圖(下面只列舉了常用的,實(shí)際上還有更多屬性)。
背景的簡(jiǎn)寫
效果如下:
中線
然后是開(kāi)球點(diǎn)和中圈。
??球在開(kāi)出前,其他隊(duì)員不得進(jìn)入中圈。
這是一個(gè)半徑為10碼的圓,可以通過(guò)一個(gè)徑向漸變r(jià)adial-gradient實(shí)現(xiàn)。
注意,這里使用了關(guān)鍵詞closest-side,表示最近的邊,可以根據(jù)背景尺寸直接控制圓的大小,默認(rèn)值是farthest-side,其他選項(xiàng)詳細(xì)如下:
關(guān)鍵字 | 描述 |
closest-side | 漸變中心距離容器最近的邊作為終止位置。 |
closest-corner | 漸變中心距離容器最近的角作為終止位置。 |
farthest-side | 漸變中心距離容器最遠(yuǎn)的邊作為終止位置。 |
? | 漸變中心距離容器最遠(yuǎn)的角作為終止位置。 |
當(dāng)然,對(duì)于完全對(duì)稱的容器,closest-* 和 farthest-*是完全相同的,各自的區(qū)別如下所示:
徑向漸變關(guān)鍵詞
繪制效果如下:
中圈
四、罰球區(qū)、球門區(qū)
罰球區(qū)通常也叫大禁區(qū),是一個(gè)44碼*18碼的矩形線框。
??守門員在罰球區(qū)內(nèi)可以用手觸球,出去就不行了,還有就是在這個(gè)區(qū)域犯規(guī),容易被判點(diǎn)球。
線性漸變不像徑向漸變那樣,并不能直接畫出這種矩形線框,我采用的方式是覆蓋的方式,也就是一塊綠色的覆蓋在一塊白色的背景之上,實(shí)現(xiàn)如下:
動(dòng)態(tài)演示如下:
大禁區(qū)實(shí)現(xiàn)演示
兩邊半場(chǎng)都有罰球區(qū)域,而且長(zhǎng)的也完全一樣,需要再重新繪制一份一模一樣的嗎?
??????當(dāng)然不需要!
凡事看到相同或相似的圖案都需要考慮能否避免重復(fù)的工作量?
仔細(xì)觀察,兩邊的罰球區(qū)域正好可以通過(guò)水平平鋪repeat-x實(shí)現(xiàn),只需要改變背景大小就行了,示意如下:
平鋪實(shí)現(xiàn)演示
你也可以查看動(dòng)態(tài)演示:
平鋪實(shí)現(xiàn)動(dòng)態(tài)演示
用代碼實(shí)現(xiàn)就是:
這樣就能在不增加漸變數(shù)量的情況下實(shí)現(xiàn)多份相同的背景,效果如下:
大禁區(qū)
然后是球門區(qū),通常叫小禁區(qū),是一個(gè)20碼*6碼的矩形線框。
??球門球時(shí),由守方隊(duì)員在球門區(qū)內(nèi)任意一點(diǎn)將球放定后踢出。
這個(gè)和罰球區(qū)繪制方法一致,就不多描述了。
效果如下:
小禁區(qū)
最后是球門。球門在底線后面,由于是俯視圖,只需要知道長(zhǎng)度8碼就行了,寬度可以隨便給一個(gè)。
??足球要完全越過(guò)門線才算進(jìn)球,僅超過(guò)1/2也不行。
這個(gè)和上面繪制方法一致,不過(guò)需要注意background-position的位置,是負(fù)數(shù)。
這里就體現(xiàn)出前面透明的好處了,可以將背景繪制在邊框上,效果如下:
球門
這樣就完成了所有矩形線框的繪制。
五、罰球點(diǎn)、罰球弧、角球弧
最后是幾條比較重要的圓弧。
首先是罰球點(diǎn),又稱點(diǎn)球點(diǎn),距離球門12碼。
??這個(gè)相信很多人都知道,12碼點(diǎn)球主罰的地方就是這里。
這是一個(gè)圓點(diǎn),直接通過(guò)一個(gè)徑向漸變r(jià)adial-gradient繪制,這個(gè)我們等會(huì)再來(lái)繪制,先畫下面的。
然后是罰球弧,它是以罰球點(diǎn)為圓心,半徑為10碼的圓弧,和中圈一樣。
??在罰點(diǎn)球時(shí),除守方守門員和主罰隊(duì)員外,雙方其他隊(duì)員都必須退出罰球區(qū)及罰球弧外,因?yàn)榈搅P球點(diǎn)的距離都是 10 碼。
和中圈大小是一樣的,只是位置不同,注意圓心距離左側(cè)的距離是12碼,由于左右都是一樣的,可以用前面提到的repeat-x方式實(shí)現(xiàn)(當(dāng)然這里不寫也行,因?yàn)槟J(rèn)就是平鋪的),示意如下:
平鋪實(shí)現(xiàn)演示
你也可以查看動(dòng)態(tài)演示:
平鋪實(shí)現(xiàn)動(dòng)態(tài)演示
用代碼實(shí)現(xiàn)就是:
效果如下:
最上層的罰球弧
現(xiàn)在這個(gè)圓弧覆蓋在最上面,由于罰球區(qū)是通過(guò)覆蓋的方式實(shí)現(xiàn)的,所以可以將罰球弧放在罰球區(qū)下面,通過(guò)改變background的先后順序就可以了,如下:
多背景的情況下,前面的背景層級(jí) > 后面的背景層級(jí)。
這樣就正常了。
罰球弧
然后用同樣的方式把罰球點(diǎn)補(bǔ)上。
效果如下:
?罰球點(diǎn)
最后是角球弧。位于球場(chǎng)四角,是半徑為1m的 1/4 圓弧。
??用來(lái)發(fā)角球的地方,守方隊(duì)員在己方半場(chǎng)將球自底線處踢出界外,攻方獲得的就是發(fā)角球的機(jī)會(huì)
如果按照一般的思路,肯定是繪制 4 個(gè) 1/4 圓弧就行了,不過(guò)這里還可以采用另一種方式。仔細(xì)想一下,這4個(gè)圓弧合在一起是不是剛好就是一個(gè)完整的圓?經(jīng)過(guò)位移、平鋪就可以了,思路演示如下
這個(gè)思路在之前這篇文章中有用到:??CSS 實(shí)現(xiàn)優(yōu)惠券的技巧??
1/4圓平鋪原理演示
用代碼實(shí)現(xiàn)就是:
這樣用一個(gè)漸變就同時(shí)繪制出了4個(gè)圓,效果如下:
4個(gè)完整角球弧
可以看到,4個(gè)圓弧已經(jīng)均勻分布在4個(gè)角落了,但是已經(jīng)超出了線外,這個(gè)也非常好解決,默認(rèn)情況下背景是可以繪制在border-box范圍內(nèi)的,只需要通過(guò)background-clip裁剪到content-box內(nèi)就行了,如下:
這樣就完美了。
使用background-clip裁剪后的角球弧
六、草坪
到目前位置,球場(chǎng)的所有部分基本已經(jīng)完成了,最后再鋪上深淺相間的草坪。
??不僅僅是為了好看,還能緩解觀眾和球員的視覺(jué)疲勞,同時(shí)也方便裁判和球員看清是否越位。
關(guān)于草坪的條紋間隔貌似不是很統(tǒng)一?這里就大概給一個(gè)數(shù)值,用線性漸變即可,如下:
由于前面罰球區(qū)等用到了覆蓋的方式,所以這里不能直接將草坪繪制在最底下,需要繪制在最上層,效果如下:
直接覆蓋的草坪
可以看到,僅僅通過(guò)半透明的覆蓋還是很不自然的,所以需要將顏色混合一下,需要用到background-blend-mode,比較復(fù)雜,這里就不展開(kāi)了,設(shè)置如下:
overlay,soft-light,hard-light屬于融合混合模式,比較適合這類情況。
效果如下:
混合模式
有點(diǎn)奇怪...原因是上面設(shè)置的是所有圖層的background-blend-mode,我們其實(shí)只需要設(shè)置最頂層的草坪,那怎么處理呢?我起初以為background縮寫是包含background-blend-mode的,這樣的話可以單獨(dú)給某一層設(shè)置了,可惜這個(gè)不支持(我猜測(cè)這個(gè)屬性出現(xiàn)的稍晚一些,沒(méi)有統(tǒng)一到背景里)。
沒(méi)辦法,只能逐層設(shè)置了,第1層設(shè)置 soft-light,剩下的全部都是normal,如下:
后面的normal可以多,但是不能少,原因在于,會(huì)根據(jù)背景數(shù)量自動(dòng)補(bǔ)充,如果數(shù)量不足,會(huì)重新開(kāi)頭循環(huán)(這個(gè)補(bǔ)充規(guī)則其實(shí)跟其他背景屬性,例如 background-size是一樣的)。
混合模式自動(dòng)填充規(guī)則
這樣就非常自然了,效果如下:
最終效果
下面是完整代碼(其實(shí)沒(méi)多少行):
你也可以訪問(wèn)以下任意鏈接:
- CSS football filed - 碼上掘金 (juejin.cn)[1]
- CSS football filed (codepen.io)[2]
- CSS football filed (runjs.work)[3]
七、總結(jié)一下
漸變是 CSS 中非常強(qiáng)大但比較繁瑣的功能了,幾乎是萬(wàn)能的,能夠設(shè)計(jì)出來(lái)的都可以通過(guò)漸變繪制出來(lái),只是實(shí)現(xiàn)的復(fù)雜度問(wèn)題,擅于發(fā)現(xiàn)圖形的規(guī)律也能有效地減少漸變的復(fù)雜度,下面簡(jiǎn)單總結(jié)一下。
- 背景的位置和尺寸的百分比計(jì)算是根據(jù)內(nèi)容區(qū)域的,并不包含邊框。
- 透明邊框仍然是可以繪制背景的。
- 通過(guò) CSS 變量將背景各部分分離開(kāi)來(lái),這樣看起來(lái)會(huì)更加清晰。
- 線性漸變不像徑向漸變那樣,并不能直接畫出這種矩形線框,可以用兩層漸變覆蓋的方式實(shí)現(xiàn)。
- 凡事看到相同或相似的圖案都可以考慮使用背景平鋪來(lái)減少工作量。
- 多背景的情況下,前面的背景層級(jí) > 后面的背景層級(jí)。
- 4 個(gè) 1/4圓可以通過(guò)一個(gè)完整的圓位移平鋪實(shí)現(xiàn)。
- 默認(rèn)情況下背景是可以繪制在邊框范圍內(nèi)的,可以通過(guò)background-clip改變繪制范圍。
- 背景混合模式并不在background簡(jiǎn)寫屬性中,需要單獨(dú)書寫,可以讓圖層混合更加自然。
- 背景混合模式會(huì)根據(jù)背景數(shù)量自動(dòng)補(bǔ)充,如果數(shù)量不足,會(huì)重新開(kāi)頭循環(huán)。
當(dāng)然實(shí)際工作中肯定是不推薦的,更多是學(xué)習(xí)掌握漸變相關(guān)知識(shí),這樣繪制一些活動(dòng)小圖標(biāo),或者在某些不方便改變 HTML 結(jié)構(gòu)時(shí)可以有更多的思路和方案,不是嗎?
參考資料
[1]CSS football filed - 碼上掘金 (juejin.cn): ??https://code.juejin.cn/pen/7172148336886022175。??
[2]CSS football filed (codepen.io): ??https://codepen.io/xboxyan/pen/BaVqogP。??
[3]CSS football filed (runjs.work): ??https://runjs.work/projects/8f18caa4fb1248dc。??