了解真實的『REM,必看

大前端高工 2021-09-18 22:34:18 阅读数:612

了解 rem 必看

1rem = 1 * htmlFontSize


> `htmlFontSize` 為 `html` 元素的字體大小。
首先來看方案1中,在屏寬為`640px`情况下的設置:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

@media screen and (min-width: 640px) {html{font-size:100px;}}


可以很明顯的錶現出這一點 `1rem = 1 * 100px` ,同我們最初的設定。那麼我們要得到其它屏幕大小的 `htmlFontSize` 值要怎麼辦。很簡單如方案3,因為我們的采用等比縮放的方式適配,所以計算目標屏幕寬度和設計稿的寬度的比即可:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

window.innerWidth / designWidth * rem2px + ‘px’


由於瀏覽器默認字體大小為 `16px`,所以當我們使用百分比作為根節點 `html` 的字體大小時,即`html`元素的`font-size`值設置為一個百分比值,`rem` 的計算方式就會改為:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

defaultFontSize = 16px

1rem = 1 * htmlFontSize * defaultFontSize


如方案2中,在屏寬為`640px`情况下的設置:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

@media screen and (min-width: 640px) {html{font-size:625%;}}


應用上面的公式:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

1rem = 1 * 625% * 16px

其中:625% * 16 = 6.25 * 16 = 100

所以:1rem = 1 * 100px


同樣的可以得到所有屏幕大小下,`html` 的 `font-size` 值的計算公式,即為方案4:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

window.innerWidth / designWidth * rem2px / 16 * 100 + ‘%’


通過方案3和方案4的公式,就可以很方便的生成方案1和方案2中的css。
這裏只給出了方案3和方案4對應驗證頁面(方案1和方案2是它們的變形): [scheme3.html](
), [scheme4.html](
)
> 如下面兩張圖,是在屏寬為360px下的效果,通過計算目標為:`1rem = 56.25px`。方案3設置值為:`56.25px`,方案4設置值為:`351.5625%`
| 方案3 | 方案4 |
| --- | --- |
| ![了解真實的『REM,必看_前端](https://img-blog.csdn.net/20161214140440722?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3Nkbl95dWRvbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) | ![了解真實的『REM,必看_前端_02](https://img-blog.csdn.net/20161214140509066?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3Nkbl95dWRvbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) |
到目前為止貌似很完美的解决了問題,實際情况當然是出現了意外。在有些 Android 手機上,瀏覽器或 webview 的默認字體是隨著系統設置的字體改變的。這樣就會導致默認字體大於或小於 `16px`。
修改默認字體大小後,我們再看方案3和方案4。
同樣在屏寬為360px下,我們調大系統字體大小,如下面的效果
> 設置前 `html` 元素的字體大小的`計算值`為 `18px` ,設置後的`計算值`為 `65px` ,由於屏幕寬度沒有改變,我們的目標值,即我們在 `html` 元素上設置的 `font-size` 值也沒有變化任然為 `56.25px`,而最終`計算值`出現了偏差。
| 方案3 | 方案4 |
| --- | --- |
| ![了解真實的『REM,必看_程序員_03](https://img-blog.csdn.net/20161214140623630?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3Nkbl95dWRvbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) | ![了解真實的『REM,必看_前端_04](https://img-blog.csdn.net/20161214140733742?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3Nkbl95dWRvbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) |
分析偏差前,先來看在`360px`屏寬下,方案3和方案4的計算過程:
方案3:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.

document.documentElement.style.fontSize = 56.25px

htmlFontSize = 56.25px

1rem = 1 * htmlFontSize = 56.25px

實際為:

1rem = 64.6875px


方案4:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

document.documentElement.style.fontSize = 351.5625%

htmlFontSize = 351.5625%

defaultFontSize = 18px

1rem = 1 * htmlFontSize * defaultFontSize = 351.5625% * 18px = 63.28125px

351.5625% * 18 = 63.28125

實際為:

1rem = 64.6875px


貌似方案4的計算結果很接近實際效果,而方案3偏差很大。再來比較方案3和方案4的計算公式:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

// 方案3

document.documentElement.style.fontSize =

window.innerWidth / designWidth * rem2px + ‘px’;

// 方案4

document.documentElement.style.fontSize =

window.innerWidth / designWidth * rem2px / 16 * 100 + ‘%’;


方案4較於方案3其實多除了一個16,可以推測瀏覽器在計算 `rem` 的具體值時,如果 `html` 設置的 `font-size` 為 `px` 值時會先除以 `16` ,然後再乘以 `htmlFontSize`。

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

1rem = 1 * (56.25px / 16) * 18

1 * (56.25 / 16) * 18 = 63.28125


方案4存在問題,是因為系統的默認字體改為了 `18px` ,但是我們在計算百分比是時候,還是以 `16px` 為基准值進行計算,所以出現偏差(計算值和實際值之間還有一點偏差這個在後面會提到)。
而在方案3中,我們其實是不考慮瀏覽器默認字體大小的,但在實際使用的過程中,瀏覽器還是除了 `16` ,而此時默認字體大小為 `18px`。得出如下在 `html` 的 `fontSize` 設置為 `px` 的情况下 `rem` 的計算公式為:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

1rem = 1 * (htmlFontSize / 16) * defaultFontSize


在系統設置的字體大小發生改變時,`defaultFontSize` 會跟著改變,而 `16` 不會變化。所以方案3雖然錶面上不考慮默認字體大小的變化,只關注屏幕與設計稿之間的寬度比,但在實際計算中還是使用到了默認字體大小,而且還有一個不變的 `16` 在作祟,導致方案3失敗。
> 所謂的「`root element`」其實不是想象的那樣,一個是`16`,一個是`18`,到底取的是那個 `root element` 的字體大小。
ok,`rem` 的計算的時候,`px` 的方式會有一個`16`不隨系統字體大小改變,所以我們采用百分比的方案,繞開這個問題。
采用百分比的`方案4`因為在計算時寫死了默認字體大小 `16px`。所以它的偏差在於沒能動態的獲取默認字體大小。更新如下:
方案4.1

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.

var designWidth = 640, rem2px = 100;

var h = document.getElementsByTagName(‘html’)[0];

var htmlFontSize = parseFloat(window.getComputedStyle(h, null)

 .getPropertyValue('font-size'));

document.documentElement.style.fontSize =

window.innerWidth / designWidth * rem2px / htmlFontSize * 100 + ‘%’;


效果如下圖:
> `16px` 的圖中,設置後的 `html` 的 `font-size` 與 `1rem` 的實際值有偏差,同時 `6.4rem` 的計算值也有偏差。通過查看代碼發現`html`的`font-size`使用的是: `getPropertyValue('font-size')` 而 `1rem` 使用的是 `getPropertyValue('width')`,偏差出在計算 `font-size` 的時候瀏覽器進行了四舍五入。`rem` 定義中的另一個元素「`font size`」也不能按字面意思使用,宣告失守。
>
> `18px` 中的偏差,以及上文中方案4在 `18px` 實際值和計算值出現的偏差都是同樣的問題。所以基准值還需要修改。
| 16px | 18px |
| --- | --- |
| ![了解真實的『REM,必看_程序員_05](https://img-blog.csdn.net/20161214140808352?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3Nkbl95dWRvbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) | ![了解真實的『REM,必看_前端_06](https://img-blog.csdn.net/20161214140828709?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3Nkbl95dWRvbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast) |
在更新一版,方案4.2:

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

var designWidth = 640, rem2px = 100;

var d = window.document.createElement(‘div’);

d.style.width = ‘1rem’;

d.style.display = “none”;

var head = window.document.getElementsByTagName(‘head’)[0];

head.appendChild(d);

總結

為了幫助大家更好溫習重點知識、更高效的准備面試,特別整理了《前端工程師面試手册》電子稿文件。

內容包括html,css,JavaScript,ES6,計算機網絡,瀏覽器,工程化,模塊化,Node.js,框架,數據結構,性能優化,項目等等。

包含了騰訊、字節跳動、小米、阿裏、滴滴、美團、58、拼多多、360、新浪、搜狐等一線互聯網公司面試被問到的題目,涵蓋了初中級前端技術點。

了解真實的『REM,必看_前端_07

了解真實的『REM,必看_程序員_08

前端面試題匯總

了解真實的『REM,必看_Web_09

 CodeChina開源項目:【大廠前端面試題解析+核心總結學習筆記+真實項目實戰+最新講解視頻】

JavaScript

了解真實的『REM,必看_前端_10

性能

了解真實的『REM,必看_前端_11

linux

了解真實的『REM,必看_Web_12

版权声明:本文为[大前端高工]所创,转载请带上原文链接,感谢。 https://gsmany.com/2021/09/20210918223418190d.html