跳到主要内容

原理-像素与单位

在前端开发中, 尺寸单位是最常见的概念之一.

基本概念

像素

像素不是自然界的物理长度, 是一种抽象概念.

在 CSS 中指一种抽象的单位, 在不同的设备或者环境下, css 中的 1px 所代表的设备物理像素是不同的.

在桌面浏览器设计的网页中, 基本上是 1px 对应一个物理像素的, 但是由于移动设备的像素密度的升高, 开始有了不同的表现. 比如从 iphone4 开始, Retina 屏幕分辨率提高了一倍, 但是屏幕尺寸没有变化, 意味着一个 css 像素大小等于两个物理像素. 其他移动设备类似.

物理像素

指显示器的最小物理显示单位, 物理像素指的是显示器上最小的点, 物理像素的大小取决于屏幕, 是一个固定属性.

设备独立像素

指我们开发过程中使用的 px

image

设备像素比(device pixel radio)

设备像素比=物理像素/设备独立像素, 单位是 dpr(device pixel readio)

Retina 屏幕

在 pc 端, 默认情况下, css 中的 1px 等于 1 物理像素, 但在移动端是不一样的, 比如 iphone6 的物理像素为 750*1334, dpr 为 2, 设备独立像素是 375*667

所以在移动开发中,2 倍图比 1 倍图清晰, 就是这个原因.

px

默认情况下, pc 是相对于屏幕分辨率而言的, 但是也有例外.

浏览器缩放

缩放是缩放 CSS 像素, 用户的缩放是针对浏览器进行的, 缩放了 css 的像素, 并不是缩放分辨率. 移动端可以一定程度上控制用户的缩放行为, 也可以禁止用户缩放:

<meta name="viewport" content="width=device-width,initial-scale=1.0" />

content 属性值:

  1. width: 可视区域的宽度, 值可为数字或者关键词device-width
  2. height: 可视区域的高度, 值可为数字或者关键词device-height
  3. intial-scale: 页面首次被显示是可视区域的缩放级别, 取值 1.0 则页面按实际尺寸显示, 无任何缩放
  4. maximum-scale=1.0, minimum-sacle=1.0;可视区域的缩放级别
  5. maximum-scale 用户可将页面方法的程序, 1.0 将禁止用户放大到实际尺寸之上
  6. user-saclable: 是否可对页面进行缩放, no 禁止缩放.

但在 pc 端就麻烦了 windows:

  • ctrl + +/-
  • ctrl + 滚轮
  • 浏览器菜单栏

mac:

  • cammond + +/-
  • 浏览器菜单栏

由于浏览器菜单栏属于系统软件权限,没有办法控制,我们可以通过 js 控制 ctrl/cammond + +/- 或 Windows 下 ctrl + 滚轮 缩放页面的情况

em

em 在实际开发中使用较少, 指相对长度单位, 相当于当前对象内文本的字体尺寸. 如当前对行内文本的字体尺寸未被人为设置, 则相对于浏览器的默认字体尺寸

  • em 的值是不固定的
  • em 会继承父元素的字体大小
  • 任意浏览器的默认字体高都是 16px, 所有未经调整的浏览器都符合1em=16px. body 选择器中声明font-size=62.5%等价于1em=10px.
<body>
<style>
html {
font-size: 50px;
}

.my-div {
width: 100%;
height: 500px;
margin-top: 50px;
background-color: gray;
font-size: 40px;
}

.my-div .parent-font {
font-size: 30px;
}

.my-div .parent-font .child-font {
font-size: 0.5em;
}
</style>
<div class="my-div">
<p class="parent-font">
我是父级文字
<span class="child-font">我是子级文字</span>
</p>
</div>
</body>

第一级,html 的 font-size: 50px;

第二级,my-div 的 font-size: 40px;

第三级,parent-font 的 font-size:30px;

第四级,child-font 的 font-size: 0.5em;

所以说 em 的字体大小不是固定的,em 的大小取决于父级的字体大小

rem

rem 是 cee3 的一个相对单位(root em, 根 em)

使用 rem 为元素设定字体大小是, 任然是相对大小, 但是是相对于 HTML 根元素的.

只要 html 的 font-size 不变, 1rem 所代表的 font-szie 大小就不会变, rem 只取决于 html 的 font-size 大小

rem 的优点

移动设备的宽度是不同的, dpr 也各种各样, 适配起来会很麻烦.

如果 font-size 可以根据不同设备的宽度做动态计算, 问题就会得到解决.

我们假设 UI 设计稿的宽度是 750px(750px 是常规宽度,当然也可以是 640px 或是其他宽度,但是整个项目,宽度必须统一),唯一不变就是就屏幕宽度,我们的 html 的 font-size(rem)只取决于设备宽度

document.documentElement.style.fontSize = 100 * (document.documentElement.clientWidth / 750) + 'px';

html 的 font-size:document.documentElement.style.fontSize

设备的宽度:document.documentElement.clientWidth

750: UI 设计稿的宽度.

x100 是为了方便计算, 但不是必须的.

封装成函数:

const fontFun = function() {
let docEl = document.documentElement;
let resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';
const recalc = function() {
let clientWidth = docEl.clientWidth;
if (!clientWidth) return;
docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';
};
if (!document.addEventListener) return;
window.addEventListener(resizeEvt, recalc, false);
window.addEventListener('pageshow', recalc, false);
document.addEventListener('DOMContentLoaded', recalc, false);
};
export { fontFun };

写成 IIFE:

(function(doc, win) {
var docEl = doc.documentElement,
resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
recalc = function() {
var clientWidth = docEl.clientWidth;
if (!clientWidth) return;
docEl.style.fontSize = 100 * (clientWidth / 750) + 'px';
};
if (!doc.addEventListener) return;
win.addEventListener(resizeEvt, recalc, false);
win.addEventListener('pageshow', recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
})(document, window);

rpx

rpx 是微信小程序提供的一种 css 尺寸单位, 可以根据屏幕宽度进行自适应, 规定屏幕宽为 750rpx. 如在 iPhone6 上,屏幕宽度为 375px,共有 750 个物理像素,则 750rpx = 375px = 750 物理像素,1rpx = 0.5px = 1 物理像素。

image

移动端的自适应布局

依据屏幕宽度和设计图宽度动态声明htmlfont-size属性, 以rem为长度单位声明所有节点的几何属性, 这样就能做大部分移动设备的页面兼容, 兼容出入较大的地方通过媒体查询进行特殊处理

通常1rem设为1rem = 100px, 即在设计图上100px长度在CSS代码上使用1rem表示

function AutoResponse(width = 750) {
const target = document.documentElement;
if (target.clientWidth >= 600) {
target.style.fontSize = "80px";
} else {
target.style.fontSize = target.clientWidth / width * 100 + "px";
}
}
AutoResponse();
window.addEventListener("resize", () => AutoResponse());

当然还可以使用屏幕宽度设计图宽度的比例使用calc()动态声明.

html {
font-size: calc(100vw / 7.5);
}

如果以iPad Pro分辨率1024px为移动端和桌面端的端点, 还可以结合媒体查询做断点处理. 1024px一下使用rem布局, 否则不使用rem布局

@media screen and (max-width: 1024px) {
html {
font-size: calc(100vw / 7.5);
}
}



## 参考链接

- [CSS 尺寸单位介绍](https://juejin.im/post/5c892273e51d4523c06c62ee)