如何合理使用px | em | rem | % 等單位

在 CSS 中有許多距離單位,比如 px | em | rem | %,還有 CSS3 中的 vh | vw 等單位。
那麼我們在項目中應該如何使用呢?我們在 pc 端不需要考慮的這麼複雜,所以這裏我們主要講講這些單位在移動端中的使用。

基礎單位 px

px 是我們最早接觸到的單位了,不過我們在移動端自適應的要求下,使用的頻率不是很高;我總結了以下使用的情況:
比較小的圖案
比如需要我們畫一個 r 爲 5px 的圓,如果我們使用 rem 作爲單位,我們很快會發現在一些機型上的圖案不圓,會呈現橢圓形。這是由於 rem 轉 px 會存在精度丟失問題。
所以這個時候我們就需要使用 px 配合 dpr 來實現:

// less 
/*@size 建議取雙數*/
.circle(@size, @backgroundColor) {  
    width: @size;
    height: @size;
    background-color: @backgroundColor;
    [data-dpr="1"] & {
        width: @size * 0.5;
        height: @size * 0.5;
    }
    [data-dpr="3"] & {
        width: @size * 1.5;
        height: @size * 1.5;
    }
}

1px 細線問題

這個問題下面我會單獨做一小節講,在這裏就不累述。
字體大小(基本都是用 rem 作爲單位)
一般情況字體的大小我也會使用 rem 作爲單位,因爲精度丟失我認爲在可以接受的範圍之內。

相對單位 rem

rem 是 CSS3 新增的一個相對單位(root em),即相對 HTML 根元素的字體大小的值。
rem 應該是自適應使用的最廣泛的單位了。

相對單位 em

em 也是一個相對單位,卻是相對於當前對象內文本的字體大小。

line-height

一般建議在 line-height 使用 em。因爲在需要調整字體大小的時候,只需修改 font-size 的值,而 line-height 已經設置成了相對行高了。

首行縮進兩個字符

在存在首行縮進的需求,我也會使用這個單位。

text-indent: 2em

視口單位 vw | vh

vw: 1vw = 視口寬度的 1%
vh: 1vh = 視口高度的 1%

我們知道以 rem 單位設計的彈性佈局,是需要在頭部加載一段腳本來進行監聽分辨率的變化來動態改變根元素字體大小,使得 CSS 與 JS 耦合了在一起。
那麼有沒有方案解決這個耦合的問題呢?

答案就是視口單位 vw | vh。

以下就是前人給出的使用方案:

$vm_fontsize: 75;
@function rem($px) {
     @return ($px / $vm_fontsize ) * 1rem;
}
$vm_design: 750;
html {
    font-size: ($vm_fontsize / ($vm_design / 2)) * 100vw; 
    @media screen and (max-width: 320px) {
        font-size: 64px;
    }
    @media screen and (min-width: 540px) {
        font-size: 108px;
    }
}
// body 也增加最大最小寬度限制,避免默認100%寬度的 block 元素跟隨 body 而過大過小
body {
    max-width: 540px;
    min-width: 320px;
}

1px 方案

做過移動端需求的前端肯定是避免不了處理 1px 細線問題,這個問題的原因就是 UI 對頁面美觀度的要求越來越高(不要和我說這是 retina 屏的問題)。

據查閱資料所知好像沒有什麼兼容性特別好的方案,這裏我只是提供三種相對較好的方案。

使用僞類 + transform
.border_bottom { 
    overflow: hidden; 
    position: relative; 
    border: none!important; 
}
.border_bottom:after { 
    content: ".";
    position: absolute; 
    left: 0; 
    bottom: 0; 
    width: 100%; 
    height: 1px; 
    background-color: #d4d6d7; 
    -webkit-transform-origin: 0 0;  
    transform-origin: 0 0; 
    -webkit-transform: scaleY(0.5);
    transform: scaleY(0.5);
}

當然這個方案在一些版本較低的機型也是會出現粗細不均、細線消失斷裂的兼容性問題。不過現在在已經 2019 年了,版本較低的機型也淘汰的差不多了。

使用 box-shadow 模擬
.border_bottom {
  box-shadow: inset 0px -1px 1px -1px #d4d6d7;
}

這個方案基本可以滿足所有場景,不過有個缺點也就是顏色會變淺。

第三種方案

這種方案對 dpr 做了不同的處理,可謂更加精細。

.min-device-pixel-ratio(@scale2, @scale3) {
  @media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
    transform: @scale2;
  }
  @media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
    transform: @scale3;
  }
}

.border-1px(@color: #DDD, @radius: 2PX, @style: solid) {
  &::before {
    content: "";
    pointer-events: none;
    display: block;
    position: absolute;
    left: 0;
    top: 0;
    transform-origin: 0 0;
    border: 1PX @style @color;
    border-radius: @radius;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    @media screen and (min-device-pixel-ratio: 2), (-webkit-min-device-pixel-ratio: 2) {
      width: 200%;
      height: 200%;
      border-radius: @radius * 2;
      transform: scale(.5);
    }
    @media screen and (min-device-pixel-ratio: 3), (-webkit-min-device-pixel-ratio: 3) {
      width: 300%;
      height: 300%;
      border-radius: @radius * 3;
      transform: scale(.33);
    }
  }
}

.border-top-1px(@color: #DDD, @style: solid) {
  &::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    border-top: 1Px @style @color;
    transform-origin: 0 0;
    .min-device-pixel-ratio(scaleY(.5), scaleY(.33));
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章