cover-img
avatar

托码特人

分享科技与人文

一个关注互联网的技术博客

移动端Web适配手记

写在开头

这篇文章所谈到的内容非常基础,如果你已经是一个前端老司机了,请直接掉头加足油门离去。

科普

REM

CSS3 新增的一个相对单位,来自 2013 年。全称:font size of root element。可根据网页根元素来设置网页中其他字体大小。

其中根元素指html标签,即:在html标签里设置font-size属性,以此来作为其他rem值的基准,从而取得自适配平衡。另外除了用来设置字体大小,rem 还可用来设置视图的:width,height,margin,padding…

EM

作用与 REM 类似,但早于 REM,算是他的前辈。全称:font size of element。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。其特点如下:

  • em 值并不是固定的;
  • em 会继承父级元素的字体大小;

使用 rem 为元素设定字体大小时,仍然是相对大小,但相对的是 HTML 根元素。而 em 是相对于父级元素;

实操

与 PX 的转换

px 像素(Pixel),相对长度单位。是相对于显示器分辨率而言。

目前对于大部分浏览器,如果不修改相关字体配置,都是默认显示font-size:16px,于是和 rem 的映射关系有:16px = 1rem

html {
  font-size: 16px;
}

如果想给一个 p 标签设置 12px 的字体大小,那么用 rem 表示就是

p {
    font-size: 0.75rem; // 12/16=0.75(rem)
}

单位转换的工具:pxtoem

移动端的适配

media queries

最早,我刚接触响应式那会儿,是通过css3 的 media queries来获取当前设备屏幕尺寸,然后对应写几套 css。但这玩意的副作用就是代码量很大,维护不方便(为了兼顾大屏幕或高清设备,会造成其他设备资源浪费,特别是加载图片。毕竟加载流量和时间也是要成本的)。代表作:Bootstrap

flex 或百分比(%)

号称弹性布局的就是。查得资料所言,大部分套路皆为:flex+百分比的布局方式。另外,不需要适配的地方仍然是 px 单位。

其中,百分比是相对于父元素,正常情况下是通过属性定义自身或其他元素

rem(本文主角)

这个特性目前主流浏览器都支持,可以放心用。适配步骤:

1. viewport 设置
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />

其中 width=device-width 用于设置 viewport 的宽度等于屏幕的宽度,initial-scale=1.0, maximum-scale=1.0 的作用同 width=device-width 一样

之所以还要同时设置这两者,是因为当它们单独使用时,表现不够完美,即单独使用时,浏览器会有兼容性问题。另外当两者值不同时,浏览器取最大者。

2. 动态设置元素的 font-size 值。一般有俩姿势
  • 利用 css 的media query来设置,好处是都是在样式表里,好管理;
  • 利用javascript 动态操作 dom 属性来计算基准值

样式设置

@media (min-device-width: 375px) and (max-device-width: 667px) and (-webkit-min-device-pixel-ratio: 2) {
  html {
    font-size: 37.5px;
  }
}

脚本设置

document.getElementsByTagName("html")[0].style.fontSize = window.innerWidth / 10 + "px";

这里除以 10,是为了控制数字不至于太大,便于后边计算,是随便定义的。即定义屏宽为:10rem,10rem * font-size = 设计宽度

3. 编写统一的计量单位值

在编写 CSS 元素时,width/height,margin,padding 等时,使用rem作为单位。换算方式如上文提到的那样。可以参考以下公式:

具体属性值 = 设计稿上的标注 / 设计稿的宽度

当然如果你是使用诸如 Less 这样的动态样式表语言的话,可以参考下边说的操作。这样就计算出设计稿上的元素和设计稿的比例了。

在 Less 中的应用

为了统一尺寸计算,可以造一个新的单位,比如:wem

module.exports = {
  /**
   * 基础尺寸换算。(eg in less: wem(1px))
   * @param less
   * @param pluginManager
   * @param functions
   */
  install(less, pluginManager, functions) {
    functions.add("wem", function (data, base) {
      const bem = base ? base.value : 36;
      return less.dimension(data.value / bem, "rem");
    });
  },
};

在公共的 less 文件中,可以引用以上插件:

@plugin "less-plugin";

// 外部的使用方式,直接用设计稿尺寸
@contentWidth: wem(360);
@padding: wem(10);

此时的 360 为设计稿的宽度,less 插件中的默认 36 是以设计稿 360px 为准的,如果你是 640px,换成 64 即可

延伸

DPR

设备像素比(device pixel radio),设备像素比(dpr) = 设备像素(分辨率)/设备独立像素(屏幕尺寸)。用人话说,就是常说的 2 倍图、3 倍图中的那个数字倍数

一般情况下,我们设置initial-scale=1.0就可以了,但是对于 dpr 大于 1 的,我们还需要精细化一波操作,可以用window.devicePixelRatio获取当前设备的 dpr,然后动态设置viewport

let drp = window.devicePixelRatio;
meta.setAttribute("content", "initial-scale=" + 1 / dpr + ", maximum-scale=" + 1 / dpr + ", minimum-scale=" + 1 / dpr + ", user-scalable=no");

如此,配合 rem,就可以完全按设计稿标注来了,也不用再除以 2、除以 3。好处是:

  • 解决了图片高清的问题;
  • 解决了 border 1px 的问题。比如设置了 viewport 的 scale 为 0.5,在 2 倍屏下,1px 的 border 就被缩放成 0.5px,更为细腻;

VW VH VM

视口单位(Viewport units),之前写 Vue 时偶然发现的。是相对于视窗的宽高度,值为 100。VM(VMin),即:取决于哪个更小

对于移动端而言,最重要的是如何多终端兼容。以上介绍的响应式也好、REM 也好都各有千秋,而 REM 使得 CSS 和 JS 耦合在了一起。VWVH的诞生解决了这一难题,目前来看,是最趋于完美的做法。具体做法参考以下资料:

参考资料

在线 DEMO

赞赏

声明: 本文内容由托码斯创作整理,由于知识水平和时效性问题,行文可能存在差错,欢迎留言交流。读者若需转载,请保留出处,谢谢!