再谈移动端适配和点5像素的由来

前言

这篇文章的内容如题目一样,主要分为两个部分,

  1. 谈谈业内主流的移动端适配解决方案
  2. 点5像素的由来和实现方法

建议在读这篇文章的时候先读下这篇文章《高清屏概念解析与检测设备像素比的方法_20161005》,因为这些文章涉及的很多概念在这篇文章中都会提到。

1.再谈移动端适配

1.1百分比解决方案的缺点

在我们的项目中大量的使用百分比来解决页面在宽度上的自适应,其实在高度上并没有很好的自适应。所以在我们的前端页面会出现一些比较奇怪的问题。比如下面这样:

3883791857-57f6132cc630e_articlex

还有一个比较明显的问题就是:在任何机型上我们的按钮的高度是不会变化自适应的,所以小屏手机我们的按钮看起来很臃肿。

1.2一些常用单位的概念解析

在谈我为什么在我们的项目中引入rem单位的时候,先来详细的了解几个常用的单位概念。

  1. px像素(Pixel)。相对长度单位。像素px是相对于显示器屏幕分辨率而言的(也就是说是跟物理设备有关的)。拿高清屏和普通屏来做对比就是普通屏幕的1个像素点就是1个物理像素点,而高清屏的1个像素点4个物理像素点
  2. em相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。em单位的特点:1. em的值并不是固定的;2. em会继承父级元素的字体大小。
  3. rem相对长度单位。rem是CSS3新增的一个相对单位,这个单位引起了广泛关注。这个单位与em有什么区别呢?区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。这个单位可谓集相对大小和绝对大小的优点于一身,通过它既可以做到只修改根元素就成比例地调整所有字体大小,又可以避免字体大小逐层复合的连锁反应。

任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1rem=16px。那么12px=0.75rem,10px=0.625rem。为了简化font-size的换算,需要在css中的html选择器中声明font-size=62.5%,这就使rem值变为 16px*62.5%=10px, 这样12px=1.2rem, 10px=1rem, 也就是说只需要将原来的px数值除以10,然后换上rem作为单位就行了。

注意:当我们在根节点<html>上设置了font-size基准值以后,在文档中有使用rem单位的属性值都是相对于根节点font-size的一个相对值。比如说一些元素的属性如width height margin等。也正是这个原因,现在很多网站的移动端网站都在使用rem单位作为适配工具。

在使用rem的时候比较麻烦的就是pxrem换算的问题。上面的除10的方案是比较简单的。但是根据设置基准值的不同换算方法也不一样。如果我们使用scss来写我们的样式表的话,解决方法就比较简单了,代码如下:

1.3为什么引入 rem 单位

由上面的内容已经知道百分比单位在多屏幕适配上的缺点和rem单位的优点。那么rem单位能为我们的开发带来什么呢?来看一个常见的多列布局,淘宝移动端的商品列表页,如下图:

650354880-57f6132cb97af_articlex

设计稿(不管是iphone6的二倍稿还是iphone5的二倍稿)中给展示商品的坑位的宽高比是固定的。为了能够使这个列表在不同的屏幕上达到最佳的显示效果,需要保持宽度和高度比一致。如果使用百分比肯定是满足不了这个需求的,因为高度上我们没有办法控制。

iphone6和iphone5的屏幕宽度和高度比不一样,当我们使用百分比做多列布局的时候就会出现下面的这种情况:

1214795131-57f6132ca68dd_articlex

所以为了满足商品坑位在不同屏幕上的宽高比一致,淘宝使用的是rem的解决方案,也是目前最好的解决方案。

1.3为什么将计算根元素的font-size值的js放在head标签中

设置根节点font-size值的方法,第一种是使用css的Media queries,示例代码如下:

上面的这种方式在我之前做过的项目中使用了一段时间。上面的设置方法有一个很明显的问题font-size是在一个屏幕宽度的区间上有一个基准值。像安卓手机种类的繁多,屏幕大小就更多的情况下,上面的方法很鸡肋。

第二种解决方案,就是使用JavaScript根据当前屏幕的宽度动态计算font-size值,这种方法可以保证屏幕宽度连续变化的时候,font-size基准值也是连续变化的

计算方法可以参考这篇文章《根据iPhone6设计稿动态计算rem值》

那么最后一个问题也来了:为什么将计算rem单位的js放在head标签里面?

一句话总结:在浏览器中文档流是从上往下加载渲染的。为了保证发生不必要的重绘或者是重排肯定是越早给根节点设置font-size值越好。

1.4什么情况下使用rem来布局和注意的问题

  1. 整体的布局还是使用百分比
  2. 使用rem的最佳场景是,遇到例如多列带有图片的列表,常常需要图片固定宽高比例
  3. 研究了一些网站,比如淘宝,对字体字体一般情况建议使用px
  4. 出现1px像素线的地方,仍旧使用border-width:1px;而不是border-width:.1rem;

2.点5像素的由来

在前言中推荐阅读的那篇文章中已经知道在 高清屏(Retina) 中控制显示的最小的物理单元包括4个基本的像素点,而普通屏幕1个点像素就是1个物理像素单元。所以在高清屏(Retina)出来之前,就算我们在css中写 0.5px,对于显示屏幕也是不识别的。但是在高清屏(Retina)中我们可以通过间接的方法实现0.5px的效果。

下面的这张图可能能让我们迅速回忆上篇文章的内容

497398027-57f6132d0f66e_articlex

来看一段简单的示例代码加深理解:

css代码如下:

chrome中的显示效果如下图:

937782784-57f6132c7854a_articlex

我把这张图截取下来放到 PS 中放大可以很明显的看到一些问题。就是高清屏实际上是用了两排的物理像素点来显示1px的像素线。且不做特殊处理的话1px0.5px的在Chrome浏览器中显示效果是相同的。也就是说Chrome浏览器不识别0.5px

2951347750-57f6132cbcd44_articlex

但是相同的代码我在 safari浏览器中的效果却是下面的效果:

2861588739-57f6132d250af_articlex

下面的效果是我在PS中做了放大后的效果。

43572163-57f6132d1a77a_articlex

所以,我们可以得出一个结论:对于0.5px不同浏览器对它的识别是存在差异的。

以下这张图是一位网友对一些常用设备是否识别0.5px做的统计:

3965970914-57f6132d2be1a_articlex

其实从视觉的感受上来说0.5px像素的显示效果确实是比1px的显示效果要好很多。大多数情况下也更符合设计稿上的1px线的效果。那么我们有没有办法可以让1px在不同的浏览器和设备中显示真正的1像素的效果呢?

答案是肯定定的。

2.1传统的实现方法,也就是我们的项目中正在使用的方法:

伪元素 + css3的缩放巧妙地实现;

基本步骤就是:

  1. 设置目标元素定位参照
  2. 给目标元素添加一个伪元素before或者after,并设置绝对定位
  3. 给伪元素添上1px的边框
  4. 设置伪元素的宽高为目标元素的2倍
  5. 缩小0.5倍(变回目标元素的大小)
  6. 使用border-box把border包进来

先来看一个1像素0.5像素的显示效果,下面的截图是在chrome中:

3185700036-57f6132d2842a_articlex

实现的代码如下:

可以很明显的看到缩放前和缩放后的效果。在ps中把上面的截图放大很多倍以后我们可以看到显示细节。缩放以后确实是使用的最小的物理像素单元来显示边框。如下图:

1857039905-57f6132d61dd8_articlex

注意:按照css3 transformscale的定义,理论上边框可以任意细(1/n px)。但是上图中已经是物理设备能够使用的最小的物理单元了,那么我们继续缩放会有什么现象呢?

使用一下代码

chrome中显示效果如下,可以很明显的看到颜色变浅了,但是是否变得更细了我们肉眼无法分辨:

647297012-57f6132d6a13a_articlex

在PS中放大以后的效果:

585228758-57f6132d77019_articlex

很明显可以看到线并没有变细,但是线的颜色确实是变浅了。这样的结果也符合我们的预期,就是已经到了物理设备能够显示一块颜色的最小的物理单元了。

2.2js动态设置viewport的方案

一些大厂(所谓的淘宝)的解决方案就是使用js动态获取屏幕的设备像素比,然后动态设置viewport。当然也是我认为目前最好的解决方案。

我们知道,一般我们获取到的视觉稿大部分是iphone6的,所以我们看到的尺寸一般是双倍大小的,在使用rem之前,我们一般会自觉的将标注/2,其实这也并无道理,但是当我们配合rem使用时,完全可以按照视觉稿上的尺寸来设置。

  1. 设计给的稿子双倍的原因是iphone6这种屏幕属于高清屏,也即是设备像素比(device pixel ratio)dpr比较大,所以显示的像素较为清晰。
  2. 一般手机的dpr是1,iphone4,iphone5这种高清屏是2,iphone6s plus这种高清屏是3,可以通过js的window.devicePixelRatio获取到当前设备的dpr,所以iphone6给的视觉稿大小是(*2)750×1334了。
  3. 拿到了dpr之后,我们就可以在viewport meta头里,取消让浏览器自动缩放页面,而自己去设置viewport的content例如(这里之所以要设置viewport是因为我们要实现border1px的效果,在scale的影响下,高清屏中就会显示成0.5px的效果)

总结:

由以上两个部分的内容可以知道,不管是在做多终端适配还是实现点5像素的线,都是存在css和js两种解决方案的。两种方案相比来说,我都认为使用JavaScript的解决方案都胜一筹。唯一的缺点就是会在html的head标签中引入一段js代码 。

记得刚入行的时候,业内有一个叫“雅虎军规”的东西,是好多前端做页面优化参考的标准。其中有一条就是要将js文件放在body标签的底部。到现在很多年了,时代在变化,我们的网络带宽也在提升,“雅虎军规”中的一些内容,可能有些已经不适合我们现在应用开发的场景。而且我觉的做技术不应该拘泥于已有的一些规定,而应该按照我们的场景选择适合我们的技术和解决方案。

纵然有瑕疵,有些也是可以通过技术手段来解决的。比如在head标签中引入计算font-size和检测设备独立像素比的js的时候,会担心js的执行阻塞页面的渲染。而我们完全可以通过review的方式确定js代码的执行不会出现阻塞,而影响文档流的加载。

还是那句话:没有十全十美的技术方案,只有适合不合适当前业务场景的技术方案。

参考文章

[css3的字体大小单位[rem]到低好在哪里](https://www.zhihu.com/questio…
移动端高清、多屏适配方案
使用Flexible实现手淘H5页面的终端适配
lib-flexible源代码

966493170-578aeb5ec3ed0_articlex

打赏支持我写出更多好文章,谢谢!

打赏作者

打赏支持我写出更多好文章,谢谢!

任选一种支付方式

1 7 收藏 7 评论

关于作者:zhiqiang21

做认为对的事情,如果可能是错的,那就做认为自己承受得起的事情! 个人主页 · 我的文章 · 11 ·      

相关文章

可能感兴趣的话题



直接登录
最新评论
  • 紫梦~ IT 02/10

    border边框这个真的是太有用了,之前总找不到解决的办法

  • 前风 测试 02/22

    请问《根据iPhone6设计稿动态计算rem值》的这个方法里的注释是放错地方了吗?如果放在脚本外,不是会直接显示在页面上了么?另外,该方法没有把根元素的字体大小调整成10,这样方便后续像素设置吗?例如,如果是10的话,后面写Rem值时只用考虑除以10后得到的值,37px可以直接写成3.7rem了!

    • zhiqiang21 前端工程师 02/22

      “如果放在脚本外,不是会直接显示在页面上了么”这句话没有搞明白你想表达的是什么呀。麻烦再详细下呗!

       

      “如果是10的话,后面写Rem值时只用考虑除以10后得到的值,37px可以直接写成3.7rem”这里说的你可以去再去学习下rem单位的定义。只有在根节点设置font-size:62.5%的时候你从px到rem换算的时候才是整除10 然后2倍稿再除2

       

       

       

      • 前风 测试 02/23

        就是<script>开头前面的那段注释,放在<script>标签外有什么含义吗?好像也没用,会被直接显示在页面上

  • 前风 测试 04/15

    请问,750X1334的设计稿,按照这种做法:

    1.html的宽度不是设置成100%吗?

    2.设计稿上的高度怎么转换成rem?是  设计稿高度/750/10   吗?

    谢谢

跳到底部
返回顶部