移動端採用Flexible將PX轉換REM適配及開發中Retina屏1px邊框的兩種解決方案

移動端採用Flexible將PX轉換REM適配及開發中Retina屏1px邊框的兩種解決方案

說明:兩個方案均基於Webpack構建。javascript

方案一

搭建環境及相關配置

  • webpack 3,須要loader及說明
  • css-loader, style-loader 加載css文件
  • expose-loader 暴露全局例如jquery
  • url-loader 樣式文件內的圖片等資源
  • file-loader 字體等資源

使用庫和主要插件

要解決一些問題

自適應這裏採用了舊版的flexible,並經過px2rem來進行單位轉換,關於樣式中的px值是否轉換爲rem或者輸出多種對應不一樣dpr的px值,請查看插件說明進行對應的註釋,例如/*no*//*px*/。這裏有一點須要說明的是,與mobileweb不一樣的是,舊版的flexible具備最大寬度1080(540*dpr)的問題?也就是說當屏幕寬度大於1080的時候,兩邊會留出空白,而沒法佔滿屏幕?若有錯誤,望指正截取一段flexible代碼:css

function refreshRem() {
  var width = docEl.getBoundingClientRect().width;
  if (width / dpr > 540) {
    width = 540 * dpr;
  }
  var rem = width / 10;
  docEl.style.fontSize = rem + 'px';
  flexible.rem = win.rem = rem;
}

這裏有個小小的建議就是給body加上一段居中樣式:java

body {
  max-width: 750px; /* 設計稿最大寬度 */
  margin: 0 auto;
}

這樣當設備寬度大於設計稿的寬度時,則總體頁面居中,更加美觀。(再次強調mobileweb中用的最新的flexible會自動擴展到滿屏,不存在該問題。)jquery

附加:關於webpack配置寫法參考

module: {
  rules: [{
      test: /\.css$/,
      use: ['style-loader', 'css-loader']
    },
    {
      test: /\.scss$/,
      use: ExtractTextPlugin.extract({
        fallback: "style-loader",
        use: [{
          loader: "css-loader"
        }, {
          loader: "px2rem-loader",
          options: {
            remUnit: 75,
            threeVersion: true
          }
        }, {
          loader: 'postcss-loader'
        }, {
          loader: "sass-loader"
        }, ]
      })
    },
    {
      test: /\.(png|svg|jpg|gif)$/,
      use: [{
        loader: 'url-loader',
        options: {
          limit: 4096
        }
      }]
    },
    {
      test: /\.(woff|woff2|eot|ttf|otf)$/,
      use: [
        'file-loader'
      ]
    },
    {
      test: require.resolve('jquery'),
      use: [{
        loader: 'expose-loader',
        options: 'jQuery'
      }, {
        loader: 'expose-loader',
        options: '$'
      }]
    }
  ]
},

主要是px2rem-loader這裏的對px2rem的相關配置,我這裏設計稿750,所以設定75,其餘參數可自行參考文檔webpack

注1:git

這個demo依然有引入PostCSS,由於webpack下沒有一個很好autoprefixer的loader(其實有一個autoprefixer-loader,該loader也提示了autoprefixer官方推薦使用postcss-loader替代),所以依然加入了PostCSS混合SASS開發。github

注2:web

不太肯定若是單位寫成PX是否會存在兼容性問題,不過在高級瀏覽器和我測試的幾部手機觀察來看未發生異常。npm

假設經過將單位故意大寫爲PX而避免轉換的話,是否是相對尾部寫/*no*/來進行過濾更爲方便?segmentfault

發現這個特徵的是在學習postcss的時候用到postcss-pxtorem插件,碰巧測試出來的。

固然我的倒的確傾向於寫PX,若是不存在兼容性問題。

示例:
轉換前:

.pic-txts {
  text-align: left;
  border:1px solid #ddd; /*px*/
  border-radius: 5PX;
  width:690px;
  display: block;
}

轉換後:

.pic-txts {
  text-align: left;
  border-radius: 5PX;
  width: 9.2rem;
  display: block;
}

[data-dpr="1"] .pic-txts {
  border: 0.5px solid #ddd;
}

[data-dpr="2"] .pic-txts {
  border: 1px solid #ddd;
}

[data-dpr="3"] .pic-txts {
  border: 1.5px solid #ddd;
}

方案二(以前SF筆記上有,此處有更新):

搭建環境及相關配置

  • webpack 3,須要loader及說明
  • css-loader, style-loader 加載css文件
  • postcss-loader 對css進行轉換處理
  • expose-loader 暴露全局例如jquery
  • url-loader 樣式文件內的圖片等資源
  • file-loader 字體等資源

使用庫

PostCSS相關的插件

  • autoprefixer
  • postcss-advanced-variables
  • postcss-nested
  • postcss-partial-import
  • postcss-pxtorem
  • postcss-scss
  • postcss-sorting
  • cssnano
  • postcss-property-lookup
  • postcss-adaptive(該插件實際上與pxtorem功能類似,彷佛是px2rem的改進版,需配合lib-flexible該插件爲了解決1px邊框問題而生,實際上是配合類名對dpr2進行px/2的處理。若是需求不高能夠直接採用該插件,而放棄同時使用postcss-pxtorem和postcss-adaptive,我之因此同時使用主要是由於postcss-pxtorem的minPixelValue: 6比較方便,以及對於不想轉換的px處理的規則使用很是便捷!)

要解決一些問題

快速開發自適應的移動端專題站點或簡單頁面

解決字體和邊框不進行rem轉換(根據考究並未找到合理有效的證據證實font-size建議使用px,我的認爲若是rem計算合理不該該存在明顯的重大問題。天然就不須要用到px2rem的dpr擴輾轉換功能了)

該分支採用postcss-pxtorem避免了postcss-nested註釋問題,具體配置大體以下

require('postcss-pxtorem')({
  rootValue: 75,
  unitPrecision: 5,
  propList: ['*'],
  selectorBlackList: [],
  replace: true,
  mediaQuery: false,
  minPixelValue: 12
})

假設設計稿750寬,這裏設置簡單說明一下(沒說的是我還沒弄明白或者是不重要的?):

  • rootValue爲75,說是對根元素大小進行設置。可能相似px2rem中的remUnit參數吧
  • unitPrecision爲5,起初我真不知道這個官方說的The decimal numbers to allow the REM units to grow to.是啥意思,搞了半天才觀察出來,原來是轉換成rem後保留的小數點位數。。。
  • propList是一個存儲哪些將被轉換的屬性列表,這裏設置爲['*']所有,假設須要僅對邊框進行設置,能夠寫['*', '!border*']意思是排除帶有border的屬性,固然這裏會有一個問題,也許有時候不想對border其餘樣式處理例如border-radius因此也不是很好。
  • selectorBlackList則是一個對css選擇器進行過濾的數組,好比你設置爲['fs'],那例如fs-xl類名,裏面有關px的樣式將不被轉換,這裏也支持正則寫法。
  • minPixelValue是一個很是不錯的選項,我設置了12,意思是全部小於12px的樣式都不被轉換,那麼border之類的屬性天然會保留px值了。而剛纔提到的border-radius若是爲了創造圓形等特殊較大圓弧時則仍是會轉換成rem,來配合對應的width和height(固然,你也能夠用繼承width或者height的變量來設置radius)。

須要注意的是,如下狀況並不會保留爲px!

.test-radius {
  width:20px;
  height:20px;
  border-radius: calc(@width / 2);
  background-color:#ccc;
}

根據反覆測試,calc運算是來自cssnano插件,然而cssnano有必要放在最後執行,因此沒法知足計算後的10px在進行pxtorem轉換,不過這種狀況也是比較合理的。假設width和height轉換爲rem,而圓角是px,我的感受不可避免的會形成圓形錯誤的狀況(是否有可能改圓角px值實際上永遠大於轉換後的rem的50%?有待考究!),因此這種狀況暫時就不考慮了,讓其單位均保持一致便可。

寫到這裏我又陷入了沉思,由於有個問題不明白了。根據postcss.config.js配置cssnano是在最後面,pxtorem是在其前面,那麼如何作到對此段樣式轉換的順序。

這段代碼應該先是postcss-property-lookup對@width進行處理,而後進行calc(@width / 2)計算,最後對px檢測轉換,再進行cssnano壓縮。而實際上有點詭異。難道postcss.config.js中插件的執行順序並不是單純的從上而下!但願不久的未來這個疑問將被解決,或者我也懷疑postcss官方文檔實際有指出,只是我的英文能力較差被我忽略掉了?。

另外一方面,關於此段CSS在畫圓上有一些須要注意的,其實這裏若是寫圓用50%便可,我發現某些狀況下(多是圓形很小)若是按照除以2的寫法轉換成rem彷佛不圓,因此在現代開發來看移動端畫圓就50%了!因此上例僅作測試好了~

額外閱讀,關於border-radius的一些事項。

對了忘了說了,css樣式代碼中將px寫成Px或者PX他也不會轉換成rem的~

附加:前文提到了一個插件postcss-adaptive說明

在PostCSS的配置文件中,我加入了這個插件並放在了postcss-pxtorem的後面引入,這樣在第一次轉換後,postcss-adaptive的默認參數就不會影響到上一個插件的配置而形成的混亂狀況。實際上前面也提到過,這個插件的大部分功能和postcss-pxtorem類似,區別在於對於轉換規則的條件過濾,而postcss-pxtorem這點有極大的優點,使用這個插件主要是解決retina屏(iPhone4以上?)須要對1px邊框處理爲0.5px。具體測試能夠看一下DEMO中的pic-txts結構,如下是該結構部分說明:

這是一個pic-txts結構的wrap,展現小圓角邊框在兩個rem > px 轉換插件的做用下的影響由於在postcss-pxtorem配置中的minPixelValue設置爲6,當圓角爲5px時,他不進行轉換,而postcss-adaptive卻要對px屬性進行操做,這是咱們不但願的,合理的操做有兩種:

  1. 將圓角值按照設計稿(假設設計稿時10px)設定,並從新調整postcss-pxtorem配置中的minPixelValue爲兩倍安全值,例如12
  2. 將圓角5px值改爲postcss-pxtorem不處理的規則例如5PX,經過實驗,發現postcss-adaptive並不會處理該屬性

總結:

固然若是項目容易改造的話,仍是建議使用方案二,在適配上面已經作得很是完善了,方案二中1px的問題經過類名提升CSS優先級很是方便,也不須要更復雜的操做。PostCSS在這兩年來依舊是發展趨勢,在新的項目中能夠大膽嘗試。

方案三:

其實關於1px適配的問題,我想到了一個特別的方法,那就是在媒體查詢中,聲明一個變量例如:

$borderWidth: 1px;
@media (max-resolution: 2dppx) {
  $borderWidth: 0.5px;
}

我但願css變量能在符合該媒體查詢規則的狀況下覆蓋以前聲明的變量,然而這種操做是沒法實現的!!!

固然,我後來只有這樣寫:

.test {
  border:1px solid #ccc;
  @media (max-resolution: 2dppx) {
    border-width:0.5px;
  }
}

但是你知道這樣寫有多麼麻煩嗎,大型項目中大量的代碼須要批量處理的時候,這是不可能實現的,雖然我當時的確在項目裏手動替換了超過50個地方。。。而後過了幾天思考,又所有還原了採用了方案一(由於項目不方便轉換爲方案二)。

所以,方案三隻是留給你們思考一下,也就沒有什麼實際的使用價值了。

相關文章
相關標籤/搜索