<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          移動(dòng)端1px問(wèn)題解決方案

          共 5474字,需瀏覽 11分鐘

           ·

          2020-11-08 23:13

          高清屏中1px線(xiàn)問(wèn)題

          在移動(dòng)端web開(kāi)發(fā)中,UI設(shè)計(jì)稿中設(shè)置邊框?yàn)?像素,前端在開(kāi)發(fā)過(guò)程中如果出現(xiàn)border:1px,測(cè)試會(huì)發(fā)現(xiàn)在retina屏機(jī)型中,1px會(huì)比較粗,即是較經(jīng)典的移動(dòng)端1px像素問(wèn)題。

          為什么高清屏下1px更寬

          高清屏(retina屏)是指高dpr的設(shè)備,其物理像素的密度更大。又分為有兩倍屏,三倍屏。

          dpr:物理像素/css像素

          普通屏1個(gè)css像素對(duì)應(yīng)1個(gè)物理像素2倍屏中一個(gè)css像素對(duì)應(yīng)4個(gè)物理像素;三倍屏中則是9個(gè)。

          7efabed5a6d4bae13491335f24ccecbf.webp

          按照這樣的置換規(guī)則后一張相同的圖片在不同的設(shè)備上才會(huì)顯示相同的大小。

          1px的線(xiàn)在高清屏下本應(yīng)不需要做特殊處理。兩倍屏下會(huì)自動(dòng)用兩排物理像素去展示‘1px’的細(xì)線(xiàn),普通屏用一排物理像素去展示‘1px’的細(xì)線(xiàn),他們應(yīng)該看起來(lái)是相同的。但是,就像數(shù)學(xué)中的概念:線(xiàn)是沒(méi)有寬度的,點(diǎn)是沒(méi)有大小的。像素同樣是沒(méi)有大小的。

          兩倍屏的物理像素密度是普通屏的兩倍,并不是每一個(gè)物理像素是普通屏的1/4大小,而是物理像素的間距是普通屏間距的1/2。

          用兩倍屏下用兩排像素去展示,自然會(huì)比普通屏中用一排像素去展示看起來(lái)更粗

          如何修正高清屏下的1px問(wèn)題

          要解決1px問(wèn)題,本質(zhì)就是讓高清屏用一個(gè)物理像素去展示一個(gè)css像素

          可以按照不同屏幕的dpr作出轉(zhuǎn)換,比如在2倍屏下將1px的細(xì)線(xiàn)寫(xiě)成border:0.5px。但這種方法只在ios上支持,安卓上會(huì)顯示成被當(dāng)成0px處理。

          更通用的方案中,有svg偽類(lèi)元素兩種。

          SVG方案

          這種方案本質(zhì)上border并沒(méi)有變細(xì),但是boder被一分為二,靠?jī)?nèi)側(cè)的是透明的

          87b8496e4a7654c1319d0f8924603cf8.webp

          關(guān)鍵的樣式代碼是css中的svg生成函數(shù)。

          SVG即矢量圖,用xml標(biāo)簽寫(xiě)在html文件中。

          通過(guò)postcss-write-svg這個(gè)postcss插件將css中svg函數(shù)生成的圖像處理成base64。這樣就可以在css文件直接調(diào)用svg函數(shù)。

          /* src/index.css */@svg?custom-name?{?  width:?4px;??  height:?4px;??   @rect?{       fill:?transparent;       width:?100%;       height:?100%;       stroke-width:?1;       stroke:?var(--color,?black);??    }}.svg-retina-border?{    border:?1px?solid;    border-image:?svg(custom-name?param(--color?green))?1?repeat;}.normal-border?{    border:?1px?solid?green;}

          處理過(guò)后的樣子59a23c1d225dd7d70a29e1492bb6ca96.webp

          剩余完整代碼

          import './index.css'const root = document.getElementById('root')const div2 = document.createElement('div')div2.innerHTML = 'SVG-retina-border'div2.className = 'svg-retina-border'root.append(div2)root.append(document.createElement('br'))const div3 = document.createElement('div')div3.innerHTML = 'normal-border'div3.className = 'normal-border'root.append(div3)

          Document
          // webpack.config.jsconst path = require('path')const HtmlPlugin = require('html-webpack-plugin')module.exports = { mode: 'development',    entry: {      entry1: './src/index.js'      },      output: {      path: path.resolve(__dirname, 'dist'),        filename: '[name].js'      },      module: {      rules: [{          test: /\.css$/,            use: ['style-loader', 'css-loader', 'postcss-loader']        }]      },      plugins: [     new HtmlPlugin({           template: './src/index.html'            })     ],      devServer: {     contentBase: path.resolve(__dirname, 'dist'),        host: '0.0.0.0',         port: 3005,        compress: true,        disableHostCheck: true      }}

          SVG

          分別直接用xml的svg標(biāo)簽和css實(shí)現(xiàn)了兩個(gè)100px,邊框?qū)挒?的矩形。

          高清屏下效果如下。

          cc4806f9b03317e9406827eb3c6619f8.webp1598073606858
            <-- 視口大小-->                <--矩形大小-->      width="100"      height="100"      fill="transparent"      <--svg中所有的單位都是px-->      stroke-width="1"      stroke="black"            />            

          stroke-widthborder一樣,都將矩形的邊設(shè)為了1px,但是用svg實(shí)現(xiàn)的矩形邊框看起來(lái)卻更細(xì)。關(guān)鍵的地方是使用svg標(biāo)記的視口大小和使用rect標(biāo)記的矩形大小相同的

          svg中沒(méi)有盒模型的概念,它的stroke畫(huà)線(xiàn)并不是對(duì)應(yīng)css中的border更像是不占空間的outline。因?yàn)椴徽伎臻g,它會(huì)以rect(矩形)的邊界為中心畫(huà)線(xiàn),一條線(xiàn)一半寬度在矩形內(nèi),一半在矩形外

          而因?yàn)橐暱趯挾日玫扔诰匦蔚拇笮。吹降木€(xiàn)寬就只有一半了

          ff078cd55eafbce7ac5814237159b3c4.webp(用svg畫(huà)一個(gè)100px大小+1px邊寬的方形)

          949dfecc141a78bd086f8b24b55b98ff.webp(用css畫(huà)一個(gè)100px大小+1px邊框的方形border-box)

          如果把矩形縮小一點(diǎn),不占滿(mǎn)視口,這時(shí)候看到的border是完整的,所以和沒(méi)處理過(guò)的1px一樣粗。

          53073db97007e227359c589e15b4565a.webp

          border-image

          border-image是三個(gè)屬性的縮寫(xiě)

          border-image-source: url('https://misc.aotu.io/leeenx/border-image/box.png');border-image-slice: 33% 20% 3 fill;border-image-repeat: stretch;
          • border-image-source:圖片鏈接或base64;
          • border-image-slice:圖片切割的四個(gè)位置。把圖片切成9塊,除中間一塊,其他八塊分別被當(dāng)成邊框使用。接受1-4個(gè)參數(shù)(使用類(lèi)似于padding/margin的尺寸設(shè)置)。可以是百分比(相對(duì)于圖片自身),也可以是數(shù)字(單位是px)。最后的fill決定中間那塊圖片會(huì)不會(huì)被當(dāng)成background使用。
          • border-image-repeat:stretch/round(平鋪)/repeat(重復(fù))上下左右四個(gè)正位的圖片怎樣被當(dāng)成border使用。
          • round(平鋪)會(huì)壓縮,repeat(重復(fù))會(huì)剪裁。

          border-image必須配合border使用。最終border寬度是border-widthborder-style也必須指定,border-color可以不用。

          偽類(lèi)元素方案

          c56695267365150836138917187f4999.webp

          完整代碼

          // index.html                                         
          retina border

          normal border
          // index.css.retina-border {   position: relative;}.retina-border::before { content: '';   position: absolute;    width: 100%;    height: 100%;     transform-origin: left top;    box-sizing: border-box;    pointer-events: none;     border-width: 1px;    border-style: solid;    border-color: #333;}@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 2dppx) {  .retina-border::before {       width: 200%;     height: 200%;     transform: scale(0.5);     }}@media (-webkit-min-device-pixel-ratio: 3), (min-resolution: 3dppx) {  .retina-border::before {   width: 300%;     height: 300%;       transform: scale(0.33);    }}.normal-border {    border: 1px solid #333;}

          具體實(shí)現(xiàn)

          以?xún)杀镀翞槔?/p>

          .retina-border {   position: relative;}.retina-border::before {     content: '';     position: absolute;    top: 0px;     right: 0px;     width: 200%;    height: 200%;    transform: scale(0.5);    transform-origin: left top;      box-sizing: border-box;    pointer-events: none;     border-width: 1px;      border-style: solid;    border-color: #333;}

          通過(guò)一個(gè)偽類(lèi)選擇器在retinaborder元素中加了一個(gè)子元素

          126e0f2dbf762491cb5c0def64be95bd.webp

          border-width: 1px將邊框的寬度設(shè)為1px。

          width:200%然后將偽類(lèi)元素的寬高都設(shè)置成父元素的2倍。(但是邊框還是1px)

          transform:scale(0.5)偽類(lèi)元素的x,y軸方向都縮放到0.5倍。

          通過(guò)兩次尺寸的設(shè)置,使這個(gè)偽類(lèi)子元素保持內(nèi)容的大小還是和父元素一樣,但是border:0.5px的效果。

          pointer-events: none當(dāng)有元素的層級(jí)重疊時(shí),鼠標(biāo)點(diǎn)擊是無(wú)法穿透的。即絕對(duì)定位的偽類(lèi)元素的層級(jí)更高,它底下的元素(即文字:retina border)無(wú)法被事件觸發(fā)。置為none時(shí),絕對(duì)定位的元素不觸發(fā)事件,底下的那層才能被選中。

          其他css樣式作用

          • 偽類(lèi)元素默認(rèn)的display:inline。而position:absolute會(huì)使元素display:block。只有塊級(jí)元素的尺寸(寬/高)設(shè)置才是有效的。

          • 其中偽類(lèi)選擇器中content是必填項(xiàng),不然無(wú)法生效

          • transform-origin的縮放的中心點(diǎn),默認(rèn)是元素中心,

          • transform-origin的縮放的中心點(diǎn),默認(rèn)是元素中心,和絕對(duì)定位的top,right一樣,相對(duì)的是padding+content部分整個(gè)空間的位置

          • 絕對(duì)定位的元素其top和right值是相對(duì)于padding+content的,默認(rèn)值是從content開(kāi)始,所以要規(guī)定都是0,否則當(dāng)父元素有padding時(shí),border就移位了

          919c98a37bc961ce01a48bb0879d6328.webp(如果刪去position:absolute)

          b85e9597571ccfae22f0d9c0beb90e49.webp(如果刪去position:absolute+display:block)

          當(dāng)使用百分比時(shí),其父元素的高度必須顯式指定,(20px/20view)不能是由子元素?fù)伍_(kāi)的,但是寬度是可以的。

          兩種方案比較

          兼容性

          svg方案經(jīng)過(guò)postcss處理,最終會(huì)影響瀏覽器兼容性的是border-image屬性

          bd6dc80a5f3dda46f04b2ff1b9c2b2a3.webp偽類(lèi)元素元素:方案最終影響兼容性的是transform屬性

          02e695dfb1daca56b9661f9bec6fea3b.webp1598076296220

          結(jié)論:svg方案的兼容性更好

          靈活性

          由于svg只能畫(huà)出特定的形狀,所以無(wú)法實(shí)現(xiàn)圓角邊框。而偽類(lèi)元素方案可以。

          學(xué)習(xí)成本

          svg方案所用到的border-image屬性、svg特性的理解成本較高,并且需要postcss-write-svg處理。偽類(lèi)元素方案相較簡(jiǎn)單。

          總結(jié)

          通常情況,偽類(lèi)元素方案更好,無(wú)論是從成本還是靈活性出發(fā)。如果是為了更高的兼容性選擇svg方案,border-image屬性一定要使用縮寫(xiě)。(不然兼容性會(huì)更差兼容性測(cè)試)




          瀏覽 59
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  97大香蕉在线视频 | 欧美黄色一级 | 午夜影院在线 | 老司机一区 | 青娱乐澳门久久 |