从理解开始 谈谈px rem 和 em 的区别与联系

时间:2023-12-14 14:29:38

概述

古语有云,没有规矩则不成方圆。秦灭六国之后为了促进国内生产力的发展,也是大力推进全国度量衡的统一。车同轨,书同文。与“尺寸”相关的问题(手动滑稽),从古至今一直为人们所关注。所以在我的处女文章中,也决定大体讲讲在前端领域里面的“尺寸”问题。

目前的国内的前端开发圈子中,最常使用到的关于“尺寸”的单位,应该是 px , rem , em 这三位。本文主要介绍这三种尺寸单位是怎么来的,能做什么,要怎么用。


px(逻辑像素)

在一般的计算机应用中,px表示像素点,即屏幕上每一个可发光的单元点,比如我们所说的1080p屏幕,那指的就是宽度达到1080px的屏幕,还有2k屏,4k屏,也是通过计算像素点的数量而得出的屏幕分类与称呼。从理论上来说,像素点是显示终端最小的可显示单位,小于1个像素的内容,是没有办法完美的显示在屏幕上。这也是为什么早期屏幕的画面容易出现锯齿的原因。

上面这一段所介绍的是硬件上的像素,一般我们称为“物理像素”。而在前端的长度单位里面的px的概念,与“物理像素”略有不同。浏览器在某些设备(如iphone系列)上,会将两个甚至更多的物理像素点合并为一个显示上的“点”去进行计算和渲染。这就涉及到另一个概念:“dpr”,这个在后面的文章会进一步深入介绍。而在浏览器上的一个“点”,我们称为“逻辑像素”,与“物理像素”概念相对应,也就是我们在css上所使用的 px 。

px单位的使用非常简单,比如我们需要一个宽度为300px,高度为100px的长方形div:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>px单位长方形</title>
<style>
#test1{width:300px;height:100px;background:#bfa;}
</style>
</head>
<body>
<div id="test1"></div>
</body>
</html>

使用px作为单位,对于pc端的开发来说具有较大的优势:

  1. PC端的项目设计图的宽度和高度比例基本固定,而且屏幕相对较宽,使用px单位对于普通项目不会造成太多不友好的显示效果。
  2. 对于设计师与前端开发者对接而言,使用px单位能够降低单位转换的成本,提高开发速度。
  3. px概念比较清晰,对于入门开发者而言使用门槛低,比较友好。

但如果是在移动端的开发上,px作为单位则显得有些力不从心了。

由于手机以及平板电脑等移动终端的普及,移动端的开发也已经占了前端开发的半壁*。而移动端由于其设备终端分辨率尺寸的多样化,以及横竖屏切换导致宽高比差异较大等原因。使用固定的px作为尺寸单位就很容易出现字体、形状的过大或过小,对于用户浏览和使用网站来说造成困扰。而为了解决这一问题,w3c标准也从最初的px单位开始,衍生出了如 em , rem , vh ,vh 等一系列单位。而在中国国内,使用最为广泛的就是 rem 单位。但要说 rem 单位之前,我们首先要来说一说 em 这个单位。

em(父元素字体大小)

em 与 rem 只差了一个字母,他们的概念也是相近。理解了 em 就能更好的理解 rem 这个单位。

相传从3000多年前古埃及的纸草书中,发现了人前臂的图形。用人的前臂作为长度单位叫“腕尺”;10世纪英国国王埃德加,把他的拇指关节之间的长度定为“1寸”。这里的“腕尺”和“寸”,实际上是一种相对的单位,如果两个埃及法老,一个身高一米五不到,一个身高两米,那他们的“腕尺”长度肯定是不一样的。但毫无疑问的是,他们的子民都会跟随他们的法老使用同样的“腕尺”作为他们的长度量度单位。所以只要新法老一上任,全国子民的“腕尺”也会跟着改变。而em单位,在原理上与这一制度相当接近。

em 的定义是元素所属的父元素的字体大小。如果某个元素的字体大小(font-size)为20px,那么它里面的元素的 1em 换算过来也是20px。

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>em单位</title>
<style>
.content{ background: #bfa; }
</style>
</head>
<body>
<div id="test1" style="font-size: 50px">
<!-- test1的字体大小是50px,所以里面的content 实际宽度是150px;实际高度是50px-->
<div class="content" style="width: 3em;height: 1em;"></div>
</div>
<br/><br/>
<div id="test2" style="font-size: 20px">
<!-- test2的字体大小是20px,所以里面的content 实际宽度是60px;实际高度是20px-->
<div class="content" style="width: 3em;height: 1em;"></div>
</div>
</body>
</html>

em的单位一般的使用场景为段前段后的空行,或是在按字号倍数设置行高(如word中常用的1.5倍/2倍行高等),另外,对于模块化的设计而言,采用em单位应该也是一个不错的方案(模块内的元素统一度量单位,编辑时只需修改模块字体大小一个参数)。

rem(根节点字体大小)

理解了 em 单位之后,rem 这个就比较好理解了。rem 里面的这个“r”代表的就是 root ,也就是根。rem所指的也是整个html文档的根节点(html)的字体大小。如果说 em 是一方诸侯,那 rem 那就是号令四海八荒的天子了。只要元素是在html文档中显示,无论其是否脱离文档流,是否有绝对定位、固定定位等影响,元素中的1rem都是html标签上所定义的font-size。

也正是rem的这一种唯一性,使其在移动端的开发中备受青睐。还在使用px的日子里,每适配一个屏幕,各个元素的尺寸大小全部要算一遍,心好累。自从使用了rem,屏幕大小有变化,那只要根节点(html)的字体大小一变,就如同皇上下的圣旨,八荒六合无不拜服,各个元素麻溜地就把自己的尺寸给跟着调整过来了,顺心!

在这里我分享一套rem适配方案,并补充一些自我的注释:

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<!-- viewport设置视口参数,宽度为设备宽度,缩放比例固定为1-->
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=0, minimal-ui">
<title>rem解决方案</title>
<script>
(function(win) {
var doc = win.document;
var html = doc.documentElement;
// 基于640px方案的设计稿
////////////////////////////////////////////////////
// 通用的做法是将设计稿中的100px换算为1rem
// 因此,当我们已知设计稿的宽度baseWidth,还有屏幕的实际宽度clientWidth时,1rem对于屏幕的实际宽度为:
// html-font-size = clientWidth / (baseWidth/100) px
///////////////////////////////////////////////////
var baseWidth = 640,
grids = baseWidth / 100,
resizeEvt = 'orientationchange' in win ? 'orientationchange' : 'resize',
recalc = function() {
// 默认尺寸为320px
var clientWidth = html.clientWidth || 320;
// 如果屏幕尺寸大于640,则按640宽度进行计算
if (clientWidth > 640) {
clientWidth = 640
} html.style.fontSize = clientWidth / grids + 'px';
document.querySelector('.content').style.display = 'block';
};
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', function() {
setTimeout(recalc)
}, false);
})(window);
</script>
<style>
@media screen and (min-width: 641px) {
/*当屏幕大小大于640px时,显示区域宽度为640px并水平居中*/
.content {
width: 640px;
margin: auto;
}
}
.content{background: #baf;}
.rem_box{
width: 3.2rem;
background: #fba;
font-size: 0.2rem;
margin: auto;
}
</style>
</head>
<body>
<div class="content">
<div class="rem_box">
无论屏幕如何缩放,橙色区域的宽度永远是紫色区域宽度的一半,里面的字体大小也会随屏幕大小变化而同步变化(除非小于12px)
</div>
</div>
</body>
</html>

rem的使用比较广泛而且成熟,包括像手机淘宝等网站项目,也是使用了rem作为其解决方案。目前现代浏览器对于rem的支持也是相当不错,下面是canIuse上提供的rem的兼容性查询结果。

从理解开始 谈谈px rem 和 em 的区别与联系


本文到这里也就接近尾声了,px rem 和 em 这三个概念在前端的知识中理解起来不算困难,同样也不需要死记硬背。只要肯多写,多试,多练,相信不用多久,你也能熟练掌握这三种利器,并且运用到实际的开发过程中。