使用purifycss精簡css

隨着項目的不斷迭代,咱們的css會不斷變大,但一般頁面上須要用到的樣式並無那麼多,不少樣式是無用的,而若是靠人工去剔除,吃力又容易出錯。css

有痛點就應該去想辦法解決。那麼有沒有辦法經過自動化來把這些無用的樣式剔除呢?答案是確定的,否則就沒有這篇文章了。目前我能找到的有如下兩種方案:html

方案一:遍歷樣式表,經過dom選擇器判斷每一個樣式是否在頁面中存在

這種方案很精準,經過篩選有用的選擇器來去掉那些沒有用到的選擇器。換句話來,只保留被用到的樣式,去掉沒用到的樣式。webpack

但這個方案明顯存在缺陷,若是在js裏面對dom的操做(例如對dom添加一個class樣式等操做),這些如何判斷?很顯然,若是是js中引用到了css樣式的話,這種方案是解決不了的。web

方案1

方案二:找到那些必定不會被用到的選擇器,去掉這些便可

那麼怎麼肯定一個選擇器必定不會被用到?從選擇器的類型來看,至少包括下面幾種:瀏覽器

  • 標籤選擇器緩存

  • class選擇器dom

  • ID選擇器測試

  • 相鄰選擇器字體

  • 父子選擇器ui

  • 屬性選擇器

  • ...

具體有哪些,能夠參考下面的連接

這麼多類型的選擇器,若是簡單以字符解析js,想在js中肯定用到了某個選擇器,無疑是比較困難的事情。但咱們換個角度來思考,無論選擇器類型多複雜,它們都是由單詞組成的,好比:

h1 => ["h"]

.a .d => ["a", "c"]

.ab-c => ["ab", "c"]

#text => ["text"]

.ab-c #text => ["ab", "c", "text"]

所以一個合法的選擇器,咱們能夠看做是一組單詞的集合。

接着,再想一想咱們在html或者js裏面是若是引用這些選擇器的?無非就是:

<div class="ab-c">

<span id="text"></span>

</div>



$("text").addClass(".a");

那麼對於一個選擇器來講,在html或者js被引用的話,那麼html或者js代碼裏面必定會出現這個選擇器的全部單詞。若是沒有出現或者沒有所有出現的話,證實這個選擇器是沒有被用到的。

好比上面例子中:

選擇器h1的單詞集合["h"]在html或者js中並沒出現,所以選擇器h1是無用的。

選擇器.a .d的單詞集合["a", "d"]在js中只出現了單詞a,而沒有出現單詞d,所以選擇器.a .d也是無用的。

所以,怎麼肯定一個選擇器必定不會被用到這個問題,就轉化成,如何肯定一個選擇器的單詞集合是不是html或者js代碼中的單詞集合的子集這個問題。

那麼判斷一個選擇器的單詞集合是不是html或者js代碼中的單詞集合的子集,若是是就保留,若是不是就丟棄掉好了。

方案2

這種方案經過剔除必定不會用到的選擇器,換句話來講,它只能知道某個選擇器可能被用到,沒法肯定某個選擇器是必定會用的到。

若是有仔細注意上面的例子,就會發現若是咱們的html結構是這樣的,選擇器.ab-c依舊會被保留下來

<div class="ab">

<span class="c"></span>

</div>

也就是說這種方案也是仍是有缺陷的,不能精準地肯定某個選擇器必定會用到,會存在漏剔除的狀況(但毫不會出現誤剔除的狀況)。

在實際應用中,咱們發現這種方案仍是能剔除不少沒必要要的樣式(因此目前測試的案例很少):

所以,從原理和效果上來看,第二種方案來實現剔除css是極不錯的,在實際運用中,採用開源的purifycss (畢竟有現成的,就不必本身造輪子了)。

使用purifycss的一些細節和注意

  • 精簡外部css的時候,須要注意內部是否以相對路徑引用其餘的資源(圖片,字體等)

舉個例子,個人html結構和css引用是這樣的:

<link rel="stylesheet" href="//res.wx.qq.com/wechatgame/static/game/dist/css/style-notification.fb62b095.css">



<div class="bg"></div>

style-notification.fb62b095.css這個css是屬於外部的一個css,它的代碼裏用到一張背景:

.bg {

background-image: url("../../images/bg.jpg"); 

}

那這時候我精簡css的話,把這個css轉化成咱們本身的cdn(//wximg.gtimg.com/wxgame/webpack/ddz/mincss/style-notification_fb62b095.css), 那麼裏面的代碼天然也是:

.bg {

background-image: "../../images/bg.jpg";

}

而此時再訪問咱們的頁面的時候,就會發現背景加載不出來了,控制檯顯示圖片404了。緣由很簡單:

../../images/bg.jpg這個相對路徑對於//res.wx.qq.com/wechatgame/static/game/dist/css/style-notification.fb62b095.css來講,它的真實路徑是//res.wx.qq.com/wechatgame/static/game/dist/images/bg.jpg, 而對於//wximg.gtimg.com/wxgame/webpack/ddz/mincss/style-notification_fb62b095.css來講,它的真實路徑是//wximg.gtimg.com/wxgame/webpack/ddz/mincss/images/bg.jpg。而咱們在上傳cdn,並無上傳//wximg.gtimg.com/wxgame/webpack/ddz/mincss/images/bg.jpg,因此就出現圖片加載不出來的狀況。

解決:在精簡css的時候,須要把css裏面的相對路徑替換成絕對路徑

// 將css中的引用的相對路徑轉化爲絕對路徑

function relative2absolute(cssContent, base) {

return cssContent.replace(/url\([\"\']?([^\)]+)[\"\']?\)/g, function(input, _url) {

if( isRemotePath(_url)) {

return input;

}

return "url(" + url.resolve(base, _url) + ")";

});

}
  • 精簡css後,破壞了通用模塊css的緩存

這實際上是一個取捨問題。把不少通用css放在一個通用模塊裏面,頁面加載的時候,能夠利用瀏覽器緩存加快速度。而若是精簡css的話,意味着每一個頁面所用到的通用模塊都不同,天然就用不了緩存。

解決:不精簡通用模塊css,只精簡具體業務相關的css。個人實現是給link加個標誌min-css="true":

<link rel="stylesheet" href="//res.wx.qq.com/wechatgame/static/game/wgui/css/wgui.min.css">

<link rel="stylesheet" href="//res.wx.qq.com/wechatgame/static/game/dist/css/style-notification.fb62b095.css" min-css='true'>

這樣子,只構建精簡帶有標誌位的css,通用模塊的css仍能夠利用緩存,而具體業務相關的css能夠儘量剔除無用的樣式,減小體積。

相關文章
相關標籤/搜索