再谈移动端适配

本文首发于 https://blog.lenconda.top/posts/2018/04/11/mobile_adjust_again/,转载请注明出处。

引言

移动端适配一向是很令人头大的问题,因为随着移动设备型号数量的爆发式增长,手机屏幕尺寸越来越多样化,网页内容自适应屏幕尺寸进行显示的需求也就越来越强烈。原本可能通过百分比/媒体查询等简单手段就可以常见的适配问题,但是对于页面有复杂结构或者视觉上有特殊要求的,就需要通过其他手段来解决了。

像素基础

像素

像素是一个老生常谈的问题了。不论是做前端开发还是做UI设计,都离不开这个话题。其实真要深究起来,像素是一个十分复杂的概念。追溯到上世纪6、70年代,计算机的输出设备还是点阵式打印机,如何使打印机打印出文字和图形?科学家们研究出了很多点组成的阵列,通过控制每一个点的黑白,最终组成文字和图形。现代计算机的显示器也借鉴了这个设计,发明了像素。
像素分为两种:

物理像素

又称设备像素(Device Pixel, DP),这是组成显示设备的最小单位。可以理解为显示器上的一个一个的点,这些点组成一个个阵列。因为这些点间隔太短,排布太密集,所以肉眼观察不到颗粒感,物理像素通过RGB显色系统,分别控制RGB三基色通道的明与暗,形成了各种颜色。这就是所谓的视觉欺骗效果。任何显示设备的物理像素的数量都是不变的,出厂前就已经设定好。
物理像素的单位是pt,计算公式为:

1pt = 1 / 72 inch

设备独立像素

设备独立像素(Density-independent Pixel, DIP)又称密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素。所以它是一种抽象出的逻辑像素。前端开发中用到的CSS像素(px像素及px衍生单位像素)就是一种典型的设备独立像素。这种像素有决定因素——PPI或DPI。

image

PPI

PPI名为每英寸像素。它是一个表示打印图像或显示器单位面积上像素数量的指数。一般用来计量电脑显示器,电视机和手持电子设备屏幕的精细程度。通常情况下,每英寸像素值越高,屏幕能显示的图像也越精细。
我们通常可以在手机的参数列表中发现名为“屏幕尺寸”的参数,比如说5.5inch。那么这个究竟是什么概念呢?这其实是手机对角线的长度,采用英寸为单位。
PPI的计算可以采用如下公式:
[图片上传失败...(image-25ca44-1550330376113)]

其中:

dp为屏幕对角线的分辨率
wp为屏幕横向分辨率
hp为屏幕纵向分辨率
di为屏幕对角线的长度(单位为英寸)

DP-DIP关联

我们已经了解到,前端工程师口中常提到的“px、em”等单位,实际上是计算机软件系统虚拟抽象出的一种概念,但因为它们是逻辑意义上的,人们可以轻松理解,所以这种像素在前端开发和平面设计中被广泛应用。那么,物理像素又是怎么和设备独立像素联系起来的呢?于是我们引出了设备像素比(Device Pixel Ratio, DPR)的概念。DPR与DP和DIP存在如下转换关系:

设备像素比(DPR) = 物理像素(DP) / 设备独立像素(DIP)

基于以上的转换关系,通过DPR,设备独立像素便可以转换成显示设备能够读懂的物理像素,并根据编码控制物理像素点的明暗变化,从而显示图像。

视口基础(搬运)

视口的概念相当复杂,想要完全搞清楚也是不太容易的,我对这个也没有做深入的研究,所以请参阅:CSS像素、物理像素、逻辑像素、设备像素比、PPI、Viewport

移动端适配的历史

无适配

这是较早期的移动端网页的形态——几乎没有哪个网站会针对移动设备进行,除非有特殊需求或者用户跨平台范围特别广的。在我的印象中,我读初中的时候(2013年左右),连百度都没有移动端适配,还要手动缩放。为了验证这个说法,特意去https://archive.org上选取了2013年7月31日百度新闻的截图:

image

ViewPort缩放

以最小的iPhone 4/5的宽度(320px)为基准,还原视觉稿。

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

然后对不同屏幕分辨率的手机进行简单粗暴的等比例缩放设置。例如:iPhone 8(375px)initial-scale = 375 / 320 = 1.18

这种方式虽然能达到目的,但initial-scale越来越大,页面内容也就被拉伸也越厉害,导致页面内容会变得模糊。这个方法已经被摒弃了。

媒体查询

采用对视口宽度进行媒体查询的方法设置断点,当视口宽度变化时,对相应的样式进行修改,从而达到样式随视口宽变化的效果。这种方式的好处是比较简单,而且图片的尺寸也可以非常容易地控制。不足之处则在于代码量很大,不易于维护,而且宽屏和窄屏的效果并不是非常好。

响应式布局

在近几年兴起的响应式布局热潮中,涌现出无数优秀的解决方案,比如Twitter开发和维护的Bootstrap,为移动端和原生应用量身定制的Ionic,响应式的SemanticUI等,为移动端适配带来无尽便利。拿Bootstrap来说,其栅格系统能同时兼顾5种不同尺寸的屏幕,不失美观,为后起之秀提供了一种全新的思路。

移动端分流

这种方式近几年被国内的大厂所采用。移动端分流实质上是Web服务器通过判断Request Header中的User-Agent字段判断用户是否使用移动设备访问站点,如果匹配到移动端的User-Agent,那么将会跳转至移动站点。比如说百度的PC首页是https://www.baidu.com,而使用移动端访问则会自动跳转至移动站点https://wap.baidu.com。这种方式实现了移动端的精细化适配(因为不需要考虑PC端),但是缺点在于User-Agent完全由用户控制,用户可以利用User-Agent进行欺骗,从而引发不可预期的结果。

REM适配

关于rem这个CSS像素单位,MDN的描述如下:

REM(root em)和em以同样的方式工作,但它总是等于默认基础字体大小的尺寸;继承的字体大小将不起作用,所以这听起来像一个比em更好的选择,虽然在旧版本的IE上不被支持).

rem是一个相对单位,对象为html选择器中font-size的值,一般来说,rem与基础字体大小(px)有如下对应关系(取其值为12px):

1rem = 12px

不论父元素的font-size的值是多少,1rem的值永远等于基础字体大小,除非它本身改变,否则rem的参照值不会改变。

基于淘宝Flexible的REM适配及其原理

在一次阿里AMFE无线前端团队双十一技术分享的时候,从手机淘宝团队中流传出了一种更加灵活的布局方案——Flexible布局,其具体原理可以概括成如下几点:

  • 将视觉稿分成100份,每份被称为一个单位a
  • 1rem被认为10a

Flexible会将实际视口宽度除以10,并将这个值设置为根元素htmlfont-size值。

由此可以推出:对于采用标准iPhone 6的750×1334视觉稿来说

1a = 7.5px
1rem = 75px

基于这个计算结果,我们就能将1:1标注稿的px数值除以75转换成rem数值,再套用到CSS中。

淘宝的Flexible实现了真正的弹性布局,而且达到了只适配一种机型,其他任何机型都能适配的效果。我们接下来讨论的另一种REM适配也是基于这种方案的。

关于淘宝Flexible的具体使用方法和更深层次的原理,请移步使用Flexible实现手淘H5页面的终端适配

基于VW的REM适配及其原理

前面说到,Flexible实现了弹性布局,但是这种方式需要使用专门的Javascript对DOM进行修改。实际上由于浏览器的不同,Flexible有几率出现未知的问题。因此,我想基于Flexible改造出一种更完美的解决方案。从CSS的相对单位入手,我发现了VW比较适合。下面引用一段对vw、vh、vm的描述:

  • vw是视口宽度的单位,视口宽度是100vw
  • vh是视口高度的单位,视口高度是100vh
  • vm取vw和vh较小的一个除以100作为单位

我们可以惊奇地发现,vw也是将视口宽度分割为100个columns。

浏览器兼容性

既然如此,事情就变得简单起来了。不过先别急,在使用一个CSS特性之前,我们最好去检查一下它的兼容性。以下是我从Can I Use中找到的关于这几个单位的基本兼容情况:

image

除Opera Mini全版本和IE低版本不支持之外,其他的浏览器基本上都已经支持vw了。

实现

兼容性不至于特别差,因此我们可以进行下一步的实现。

根据Flexible的实现原理,我们类比出直接使用CSS对根元素样式进行修改:

html {
  font-size: 10vw !important;
}

这样一来,htmlfont-size的值就变成视口宽度的10%,达到了和Flexible相同的效果。但是,我发现如果使用宽屏移动设备(例如iPad、Nexus平板等平板设备)时,Web组件将会变的很大很大,并不是很美观。于是,我发现Flexible在视口宽度大于等于540px时,基础字体大小将会保持54px。于是,在CSS中添加一个媒体查询:

@media (min-width: 540px) {
  html {
    font-size: 54px !important; /*no*/ /*这个no注释主要是为了防止px2rem将px转换成rem*/
  }
}

在查询到的视口宽度大于540px时,htmlfont-size将被固定为54px。接下来的步骤,就和淘宝Flexible的操作一模一样了。

另外,根据bug测试的结果来看,当flexible.css结合normalize.css使用时,buttontextareainput等元素的字体大小可能超大,这是因为在normalize.css的第258行将font-size的值设成了100%从而导致问题的发生。

针对这个bug,我建议在flexible.css末尾加上这段代码:

button,
input,
optgroup,
select,
textarea {
  *font-size: 100%;
}

注意:如果要结合normalize.css使用,normalize.css必须在flexible.css之前引入

至此,这个方案已经被完整实现了,暂且称它为flexible.css。完整代码如下:

flexible.css

html {
  font-size: 10vw !important;
}
@media (min-width: 540px) {
  html {
    font-size: 54px !important; /*no*/
  }
}
button,
input,
optgroup,
select,
textarea {
  font-size: initial;
  *font-size: 100%;
}

使用时,最好在较前的代码中引入。

VW适配

这种适配方法和REM适配类似,值是将CSS中的所有px单位转换成vw单位,从而达到移动端适配的目的。这个适配方法我还没有作过详细的研究,在这篇文章中就不详细描述了。参考文章:如何在Vue项目中使用vw实现移动端适配

参考

[1]. 使用Flexible实现手淘H5页面的终端适配
[2]. 移动端前端适配方案对比
[3]. 移动端适配方案(上)
[4]. 简单粗暴的移动端适配方案 - REM
[5]. 移动端Web页面适配方案
[6]. 动态rem解决移动前端适配
[7]. Can I USE
[8]. CSS的值和单位 - 学习 Web 开发 | MDN
[9]. CSS像素、物理像素、逻辑像素、设备像素比、PPI、Viewport

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,423评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,147评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,019评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,443评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,535评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,798评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,941评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,704评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,152评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,494评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,629评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,295评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,901评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,978评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,333评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,499评论 2 348

推荐阅读更多精彩内容

  • 移动端适配方案:1)viewport(scale=1/dpr)2)rem3)flex4)vm/vh一、什么是移动端...
    puxiaotaoc阅读 43,065评论 3 56
  • 刚开始做移动端web开发的同学应该都碰到过页面适配问题,为什么我在开发手机上调试好的页面在其他手机会有这样或那样的...
    留七七阅读 19,320评论 5 80
  • 一、meta标签的效果 移动端页面一般会在head头部添加如下meta标签。 该meta标签是否添加对页面渲染的影...
    nimw阅读 3,528评论 0 5
  • 现在回过头来看,感觉自己以前写复杂了,其实道理很简单; 就是利用vw,rem随屏幕,或者跟字体正比变化的特性; 1...
    会会会会阅读 42,984评论 16 40
  • 不知不觉做前端已经两年了,从PC端,移动端,微信小程序一路走来到今天刚刚开放注册的快应用(手机厂商对抗小程序的新技...
    是ADI呀阅读 3,095评论 0 10