天天看點

解決 webpack 打包後 z-index 重新計算的問題

背景

與 PC 端共同開發一個頁面,頁面由 PC 端提供,内部 iframe 則由我們前端提供。開發時候遇到了一個問題,webpack 打包後 css 的 z-index 值與原始值不符,導緻 iframe 裡面的 toast 被外面 z-index 較小的 dialog 覆寫。更改 toast 的 z-index,發現沒起作用,頁面上的 z-index 依然是之前的值,而不是 css 中賦予的值。給 z-index 加上 !important 後依然無效,查資料發現是 OptimizeCssAssetsPlugin 調用 cssProcessor cssnano 對 z-index 進行了重新計算導緻的。

這本來是 webpack 插件的一個善舉(讓 z-index 數值更加合理),但是具體情況來看,這裡顯然不需要這個 “善舉”。

解決方案

解決方案按照網上的資料,可以在 OptimizeCssAssetsPlugin 插件中關掉 cssnano 對 z-index 的重新計算(cssnano 稱為 rebase)。

new OptimizeCSSPlugin({
    cssProcessor: require('cssnano'),
    cssProcessorOptions: {
        discardComments: {removeAll: true},
        // 避免 cssnano 重新計算 z-index
        safe: true
    },
    canPrint: false
})           

複制

cssnano 将 z-index rebase 歸類為 unsafe,隻有在單個網頁的 css 全部寫入一個 css 檔案,并且不通過 JavaScript 進行改動時是 safe。

參考: http://cssnano.co/optimisations/zindex/

cssnano 預設進行 z-index rebase。

unsafe (potential bug) 優化項預設不開啟應該比較友好。

另外一個方案

以上是網上提供的方案,而且親測有效,但是由于項目太大,因為其中一個小功能改了整個項目的 css 處理政策,難免有些擔心會影響到其它頁面。思考再三,決定不改 webpack 配置。

觀察之前項目中使用的架構,在生成 dialog 或者 toast 的時候,即使在 webpack 插件對 css 進行處理之後,其 z-index 依然是很大的。

比如 element-ui 下 的 popup-manager.js 中首先設定 zIndex 為 2000,然後在 openModal 的時候動态添加 css 到 DOM 中,并且改變 zIndex 的值,而在浏覽器中觀察彈框的 z-index,果然是沒有經過 cssnano rebase 的。

于是仿照 element-ui 的做法,把 z-index 相關的 css 用 js 動态插入到 DOM 中,就完美地解決了這個問題,并且沒有對其它項目産生影響。

// 改變 toast 的 z-index
(function addToastStyle () {
    let nod = document.createElement('style')
    let str = `.mint-toast{z-index:2009;}`
    nod.type = 'text/css'
    nod.appendChild(document.createTextNode(str))
    document.getElementsByTagName('head')[0].appendChild(nod)
})()           

複制

總結

webpack 在對代碼進行打包之前,會掃描所有的子產品,建立子產品之間的依賴樹,而插件的運作時機也是相對于此時的靜态代碼,是以用 js 動态插入 css,webpack 顯然不會知道要插入的 css 是什麼樣的,是以動态插入的 css 内容就不會經過插件的處理,也就避免了 OptimizeCssAssetsPlugin 的 “善舉”。