每次要用到圖標的時候都會到 icono 去copypaste,但每次用到的時候尺寸都各不一樣,總是要調整參數,巨煩。當然你可以會想到用zoom、scale來做縮放,但是這樣的縮放會使得線寬也變粗了,不甚滿意。
終於下定心思來改造一個可縮放的圖標庫。github先上:https://github.com/qieguo2016/iconoo,目前提供下載link標簽引入和npm+webpack的引入方式,詳見項目的readme。(喂,來個star!)。上圖:

關於改造,一開始的想法就是使用百分比尺寸來改造,然后馬上發現不可行了,繪制圖標最依賴的兩種手段:border、box-shadow都不可以用百分比,所以這個想法,pass!然后很自然就想到了在單位上做文章,rem?No、No、No,一個庫依賴全局變量那簡直是個笑話。剩下的自然就是em了,在icon級設置font-size,然后icon本身以及后代都以這個font-size為參照,Perfect!
CSS繪圖的原理
使用CSS繪制線條,用到的不外乎兩個屬性:border & box-shadow。而形狀則可以用border-radius、transform控制,位置會用到絕對定位、transform、margin等。CSS的繪圖,做過幾個就知道大概是怎么回事了,歸根到底,還是幾何。
比如最簡單的加號:
1 .plus { 2 box-sizing : border-box; 3 display : inline-block; 4 position : relative; 5 font-size : 20px; 6 } 7 8 .plus:before, plus:after { 9 content : ''; 10 pointer-events : none; 11 position : absolute; 12 left : 50%; 13 top : 50%; 14 transform : translate(-50%, -50%); 15 box-shadow : inset 0 0 0 1em; 16 } 17 18 .plus:before { 19 width : 1em; 20 height : 2px; 21 } 22 23 .plus:after { 24 height : 1em; 25 width : 2px; 26 }
實現非常簡單,通過設置兩個偽類的寬高形成橫豎兩個小矩形,接着用陰影填充滿,這樣一個加號必需的圖形就出來了。然后就是調整位置了,將這兩個矩形居中,加號就出來了。具體是通過絕對定位+反向偏移的方式,巧妙利用了這兩個屬性百分比參照的不同實現居中。尺寸方面,所有尺寸除了線寬(2px)外都使用em這個相對單位,所以調整font-size的值就可以調整圖標的大小了。如果要調整線寬,那就需要改變這個2px了,引入less、sass將線寬定義成變量就可以很方便地改變線寬了。
CSS的各種玩法
原理雖然簡單,但是很多圖標還是相當有意思的,通過分析這些圖標也能加深對css的認識。例如:

這個圖形網上說的應該還是比較多的了,第一眼看到懵逼了。。。分析一下,最外層的邊框明顯可以用border來做,然后用個before來做圓點也非常簡單,關鍵是兩座大山要如何繪制呢?box-shadow貌似可以做多層邊框呢,然后加個旋轉是不是就出來了呢?繪制流程如下:

上CSS代碼吧:
1 .icon-test { 2 display: inline-block; 3 position: relative; 4 box-sizing: border-box; 5 width: 90px; 6 height: 80px; 7 border: 5px solid; 8 border-radius: 10px; 9 color: #2ba5bb; 10 overflow: hidden; 11 } 12 13 .icon-test:before,.icon-test:after { 14 content: ''; 15 pointer-events: none; 16 position: absolute; 17 } 18 19 .icon-test:before { 20 width: 10px; 21 height: 10px; 22 top: 18px; 23 right: 20px; 24 box-shadow: inset 0 0 0 1em; 25 border-radius: 50%; 26 } 27 28 .icon-test:after { 29 width: 60px; 30 height: 50px; 31 left: 0; 32 bottom: -27px; 33 box-shadow: inset 0 0 0 50px,30px -20px 0 0; 34 transform: rotate(45deg); 35 }
再來一個:

看起來跟上一個有點像,然而,按照上一個的繪制方式卻怎么也畫不出來~~~還是分解幾步來畫,邊框很容易解決,一個box-shadow就完事。這兩座大山其實形狀都一樣,都是一個三角形下接一個矩形,三角形顯然可以用border來畫,而矩形用box-shadow就可以了!這里還用了透明border來做左側和下側的留白,比直接用尺寸對齊要好很多。

1 .icon-test { 2 display: inline-block; 3 position: relative; 4 box-sizing: border-box; 5 color: #2ba5bb; 6 width: 60px; 7 height: 40px; 8 border-top-width: 0; 9 border-right-width: 0; 10 border: 4px solid; 11 border-color: transparent; 12 box-shadow: -4px 5px; 13 overflow: hidden; 14 } 15 16 .icon-test:before,.icon-test:after { 17 content: ''; 18 pointer-events: none; 19 position: absolute; 20 } 21 22 .icon-test:before { 23 left: 0; 24 bottom: 8px; 25 border: 14px solid transparent; 26 border-bottom-color: currentColor; 27 box-shadow: 0 16px; 28 } 29 30 .icon-test:after { 31 left: 28px; 32 bottom: 9px; 33 border-width: 0 9px 21px; 34 border-style: solid; 35 border-color: transparent transparent currentColor; 36 box-shadow: 0 17px; 37 }
怎么樣?覺得這些都是小玩意?好吧,都讓開,我要開始裝逼了!
蒙娜麗莎?什么鬼?我會告訴你這也是一個單標簽純CSS畫出來的嗎?
幾千條box-shadow構成的蒙娜麗莎,看的我內分泌都失調了。。。
(author:Jay Salvat, 來源:http://codepen.io/jaysalvat/pen/HaqBf )
如此變態的繪圖,都沒有怎么用到CSS中最強大的變形,如果加入變形,那可以畫出來的形狀就更多了。。。更多CSS玩意兒,請到codepen上去探寶吧!
PS: 蒙娜麗莎這種圖形,可以讀取原圖信息轉換成單位面積的box-shadow,前端用canvas就可以做的,其實這貨的技術含量比一個圖片圖標還要少呢。話雖如此,復雜圖形使用CSS來繪制的話,性價比還是太低,建議還是使用圖片,這樣會更具表現力一些,操作起來也更加簡單!專業的繪圖還是交給專業的UI去做吧!
大大小小的坑
其實,遇到的這些都不能叫做坑,是自己對CSS的理解度不夠而已。原以為,將原來icono使用的單位換算成em就算完事了,然而,一改font-size就變形了,頓時懵逼!究其原因,其實也很簡單,並不是所有地方與font-size都是正比的,很多地方混入了線寬的影響,所以要剔除線寬的影響。
去除線寬影響的方法不外乎兩種:
1)去掉線寬,例如使用box-shadow等不影響尺寸的屬性
2)將線寬納入計算內,比如translate反向偏移掉線寬,這樣整體縮放就不會受到線寬的影響了。
另外一個比較煩的就是居中,其實居中基本上就只用到了下面兩種方式,還是蠻簡單的。只是,這個反復的copypaste,煩哪!
1. 絕對定位+margin:auto。
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
實現原理:利用css定位規則,設置左右、上下方向定位為0,margin為auto,讓css根據定位計算margin值,用hack的方式實現居中。居中塊的尺寸需要可控,因為css計算margin時也需要參考尺寸值,由於四周為0,所以自動計算得到的盒子尺寸(含margin)是與父容器一樣的。無論是設置居中塊的width、height或者是max-height、max-width,都是讓尺寸不會擴大到與父級一樣。
局限:在參考系父級(position!=static)大小比本身要小的時候,水平方向的居中就會失效。(垂直方向依然居中)
2. 絕對定位 + transform反向偏移。
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); margin: auto;
實現原理:先絕對定位相對父級偏移50%,然后使用transform來反向偏移。由於transform的計算基准是元素本身,所以這里可以用50%來做反向偏移。
局限:這個方案需要固定居中塊的尺寸值(不能設置max-width等范圍限制),瀏覽器需要以此為基准來計算定位!
綜合來說,方案2的居中方式明顯會比方案1要好,但是在繪制圖標的時候會用到transform來做一些偏移,為了不覆蓋偏移效果所以要用到方案的方式來做居中。除了這兩種居中方式,還有inline-block對齊after/before子元素的方式,還有table和flexbox的方式來實現居中,但是畫圖標本身層級有限而且也用到了before/after,所以不適用圖標繪制。
最后一點
目前純CSS的圖標還是挺多應用場景的,這種圖標的方案免去了做雪碧圖和維護雪碧圖的麻煩,而且減少了圖片資源的請求,從性能上來說會有那么0.01s的提高吧。不用堆雪碧圖還方便調整顏色,性能還有0.01s的優化,這套CSS圖標你還不趕緊用起來?!
PS:各位看官覺得不錯的話,還請順手給個github星星哈。多攥幾顆星星,說不定就升職加薪贏取白富美了呢~~~
PPS:再附上幾個神級的CSS效果吧(by Fabrizio Bianchi 來源: http://codepen.io/fbrz/pen/iqtlk):
