设计师通常会选择iPhone6作为基准设计尺寸,可没

作者: 前端  发布:2019-11-20

使用Flexible实现手淘H5页面的终端适配

2015/11/21 · CSS · 7 评论 · Flexible

原文出处: 大漠(@w3cplus )   

曾几何时为了兼容IE低版本浏览器而头痛,以为到Mobile时代可以跟这些麻烦说拜拜。可没想到到了移动时代,为了处理各终端的适配而乱了手脚。对于混迹各社区的偶,时常发现大家拿手机淘宝的H5页面做讨论——手淘的H5页面是如何实现多终端的适配

那么趁此Amfe阿里无线前端团队双11技术连载之际,用一个实战案例来告诉大家,手淘的H5页面是如何实现多终端适配的,希望这篇文章对大家在Mobile的世界中能过得更轻松。

使用Flexible实现手淘H5页面的终端适配rem自适应布局-移动端自适应必备

一,flexible.js 的使用方式:

前言

曾几何时,互联网到了移动时代,前端也不用为了兼容IE低版本浏览器而头痛。有了gulp,mv*等利器之后,前端开发似乎变得简单起来了。

可是最后为了处理各终端的适配而乱了手脚。

虽然H5的页面与PC的Web页面相比简单了不少,但是我们要想尽办法让页面能适配众多不同的终端设备。
看看下图你就会知道,这是多么痛苦的一件事情:

9159.com 1

Device metrics

目标

拿一个双11的Mobile页面来做案例,比如你实现一个类似下图的一个H5页面:

9159.com 2

目标很清晰,就是做一个这样的H5页面。

或者直接加载阿里CDN的文件:

github地址:
官方文档地址:
本文中有部分内容引至上面这个文档。

希望这篇文章可以对大家实现多终端适配的提供一些帮忙!

痛点

虽然H5的页面与PC的Web页面相比简单了不少,但让我们头痛的事情是要想尽办法让页面能适配众多不同的终端设备。看看下图你就会知道,这是多么痛苦的一件事情:

9159.com 3

点击这里查看更多终端设备的参数。

再来看看手淘H5要适配的终端设备数据:

9159.com 4

看到这些数据,是否死的心都有了,或者说为此捏了一把汗出来。

另外强烈建议对JS做内联处理,在所有资源加载之前执行这个JS。执行这个JS后,会在元素上增加一个data-dpr属性,以及一个font-size样式。JS会根据不同的设备添加不同的data-dpr值,比如说2或者3,同时会给html加上对应的font-size的值,比如说75px。

(一),引用方式

设计需要配合什么

在h5产品开发的时候,设计师通常会选择iPhone6作为基准设计尺寸,交付给前端的设计尺寸是按750px * 1334px为准(高度会随着内容多少而改变)。
前端开发人员通过一套适配规则自动适配到其他的尺寸。

手淘团队适配协作模式

早期移动端开发,对于终端设备适配问题只属于Android系列,只不过很多设计师常常忽略Android适配问题,只出一套iOS平台设计稿。但随着iPhone6,iPhone6+的出现,从此终端适配问题不再是Android系列了,也从这个时候让移动端适配全面进入到“杂屏”时代。

9159.com 5

上图来自于paintcodeapp.com

为了应对这多么的终端设备,设计师和前端开发之间又应该采用什么协作模式?或许大家对此也非常感兴趣。

而整个手淘设计师和前端开发的适配协作基本思路是:

  • 选择一种尺寸作为设计和开发基准
  • 定义一套适配规则,自动适配剩下的两种尺寸(其实不仅这两种,你懂的)
  • 特殊适配效果给出设计效果

还是上一张图吧,因为一图胜过千言万语:

9159.com 6

在此也不做更多的阐述。在手淘的设计师和前端开发协作过程中:手淘设计师常选择iPhone6作为基准设计尺寸,交付给前端的设计尺寸是按750px * 1334px为准(高度会随着内容多少而改变)。前端开发人员通过一套适配规则自动适配到其他的尺寸。

根据上面所说的,设计师给我们的设计图是一个750px * 1600px的页面:

9159.com 7

如此一来,页面中的元素,都可以通过rem单位来设置。他们会根据html元素的font-size值做相应的计算,从而实现屏幕的适配效果。

1,引用cdn地址

前端开发完成终端适配方案

拿到设计师给的设计图之后,剩下的事情是前端开发人员的事了。

前端的解决方案通常是用自适应(Flex,百分比)+ rem.

更高端一点的办法就是通过Iconfont或者svg来处理Icon,用bootstrap的栅格处理列表和布局。

这些都会有个通病就是无法动态处理宽度改变,以及低版本的安卓机没法控制缩放比例。

所以我们可以针对这些问题整理出一套完整的终端适配方案

前端开发完成终端适配方案

拿到设计师给的设计图之后,剩下的事情是前端开发人员的事了。而手淘经过多年的摸索和实战,总结了一套移动端适配的方案——flexible方案

这种方案具体在实际开发中如何使用,暂时先卖个关子,在继续详细的开发实施之前,我们要先了解一些基本概念。

除此之外,在引入lib-flexible需要执行的JS之前,可以手动设置meta来控制dpr值,如:

当前最新的版本是0.3.2。

基本概念

在进行介绍方案之前,首先得了解下面这些基本概念(术语):

视窗 viewport

简单的理解,viewport是严格等于浏览器的窗口。在桌面浏览器中,viewport就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。

移动端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport:虚拟的viewportvisualviewport和布局的viewportlayoutviewport。

而事实上viewport是一个很复杂的知识点,上面的简单描述可能无法帮助你更好的理解viewport,而你又想对此做更深的了解,可以阅读PPK写的相关教程。

物理像素(physical pixel)

物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度。正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。

设备独立像素(density-independent pixel)

设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。

CSS像素

CSS像素是一个抽像的单位,主要使用在浏览器上,用来精确度量Web页面上的内容。一般情况之下,CSS像素称为与设备无关的像素(device-independent pixel),简称DIPs。

屏幕密度

屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(PPI)。

设备像素比(device pixel ratio)

设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:

  设备像素比 = 物理像素 / 设备独立像素

在JavaScript中,可以通过window.devicePixelRatio获取到当前设备的dpr。
而在CSS中,可以通过-webkit-device-pixel-ratio,-webkit-min-device-pixel-ratio和 -webkit-max-device-pixel-ratio进行媒体查询,对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)。

9159.com 8

视网膜屏幕

Meta标签

<meta>标签有很多种,而这里要着重说的是viewport的meta标签,其主要用来告诉浏览器如何规范的渲染Web页面,而你则需要告诉它视窗有多大。在开发移动端页面,我们需要设置<meta>标签如下:

    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

CSS单位rem

简单的理解,rem就是相对于根元素<html>的font-size来做计算。而我们的方案中使用rem单位,是能轻易的根据<html>的font-size计算出元素的盒模型大小。而这个特色对我们来说是特别的有益处。

flexible解决方案

其实H5适配的方案有很多种,网上有关于这方面的教程也非常的多。不管哪种方法,都有其自己的优势和劣势。
flexible解决方案 这个库在手机淘宝已经使用了近一年,而且已达到了较为稳定的状态
除此之外,你不需要考虑如何对元素进行折算,可以根据对应的视觉稿,直接切入。

事实上他做了这几样事情:

  • 动态改写<meta>标签
  • <html>元素添加data-dpr属性,并且动态改写data-dpr的值
  • <html>元素添加font-size属性,并且动态改写font-size的值

flexible使用方法

只需要在Web页面的<head></head>中添加对应的flexible_css.js,flexible.js文件:

    <script src="build/flexible_css.debug.js"></script>
    <script src="build/flexible.debug.js"></script>

执行这个JS后,会在<code><html></code>元素上增加一个data-dpr属性,以及一个font-size样式。JS会根据不同的设备添加不同的data-dpr值,比如说2或者3,同时会给html加上对应的font-size的值,比如说75px。

除此之外,可以手动设置meta来控制dpr值,如:

    <meta name="flexible" content="initial-dpr=2" />

目前Flexible会将视觉稿分成100份,而每一份被称为一个单位a。同时1rem单位被认定为10a。
针对我们这份视觉稿可以计算出:

    1a   = 7.5px
    1rem = 75px     

那么我们这个示例的稿子就分成了10a,也就是整个宽度为10rem,<html>对应的font-size为75px

iphone 6的是实际宽度是375 * 667 ;

当前设备的dpr = 2 ;

所以设计图的宽度是 750 * 1134

在750Px设计图切出来的Icon比如说是85 * 85;

那我们给这个icon设置样式就是 width: 85/75;height:85/75

<b>CSSREM</b>

<p>CSSREM是一个CSS的px值转rem值的Sublime Text3自动完成插件。</p>
插件的效果:

9159.com 9

CSSREM

本人长期维护的前端公众号欢迎大家关注

9159.com 10

前端那些事

一些基本概念

在进行具体实战之前,首先得了解下面这些基本概念(术语):

其中initial-dpr会把dpr强制设置为给定的值。如果手动设置了dpr之后,不管设备是多少的dpr,都会强制认为其dpr是你设置的值。在此不建议手动强制设置dpr,因为在Flexible中,只对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr为1。

2,下载flexible.js 等文件到项目指定目录下,然后在head中引入。建议对于js做内联处理,在所有资源加载之前执行这个js。

视窗 viewport

简单的理解,viewport是严格等于浏览器的窗口。在桌面浏览器中,viewport就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。

移动端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport:虚拟的viewportvisualviewport和布局的viewportlayoutviewport。

George Cummins在Stack Overflow上对这两个基本概念做了详细的解释。

而事实上viewport是一个很复杂的知识点,上面的简单描述可能无法帮助你更好的理解viewport,而你又想对此做更深的了解,可以阅读PPK写的相关教程。

if (!dpr && !scale) {

下面是淘宝的写法:

物理像素(physical pixel)

物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。每个像素可以根据操作系统设置自己的颜色和亮度。正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。

9159.com 11

var isAndroid = win.navigator.appVersion.match(/android/gi);

lib.flexible

设备独立像素(density-independent pixel)

设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。

var isIPhone = win.navigator.appVersion.match(/iphone/gi);

(二),flexible.js原理

CSS像素

CSS像素是一个抽像的单位,主要使用在浏览器上,用来精确度量Web页面上的内容。一般情况之下,CSS像素称为与设备无关的像素(device-independent pixel),简称DIPs。

var devicePixelRatio = win.devicePixelRatio;

在页面中引入flexible.js后,flexible会在标签上增加一个data-dpr属性和font-size样式(如下图)。

屏幕密度

屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(PPI)。

if (isIPhone) {

flexible.png
flexible.png
js首先会获取设备型号,然后根据不同设备添加不同的data-dpr值,比如说1、2或者3,从源码中我们可以看到。

设备像素比(device pixel ratio)

设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:

设备像素比 = 物理像素 / 设备独立像素

1
设备像素比 = 物理像素 / 设备独立像素

在JavaScript中,可以通过window.devicePixelRatio获取到当前设备的dpr。而在CSS中,可以通过-webkit-device-pixel-ratio-webkit-min-device-pixel-ratio和 -webkit-max-device-pixel-ratio进行媒体查询,对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)。

dip或dp,(device independent pixels,设备独立像素)与屏幕密度有关。dip可以用来辅助区分视网膜设备还是非视网膜设备。

缩合上述的几个概念,用一张图来解释:

9159.com 12

众所周知,iPhone6的设备宽度和高度为375pt * 667pt,可以理解为设备的独立像素;而其dpr为2,根据上面公式,我们可以很轻松得知其物理像素为750pt * 1334pt

如下图所示,某元素的CSS样式:

CSS

width: 2px; height: 2px;

1
2
width: 2px;
height: 2px;

在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是49159.com,个物理像素。

有关于更多的介绍可以点击这里详细了解。

看到这里,你能感觉到,在移动端时代屏幕适配除了Layout之外,还要考虑到图片的适配,因为其直接影响到页面显示质量,对于如何实现图片适配,再此不做过多详细阐述。这里盗用了@南宮瑞揚根据mir.aculo.us翻译的一张信息图:

9159.com 13

// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案

if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
另外,页面中的元素用rem单位来设置,rem就是相对于根元素的font-size来计算的,flexible.js能根据的font-size计算出元素的盒模型大小。这样就意味着我们只需要在根元素确定一个px字号,因此来算出各元素的宽高,从而实现屏幕的适配效果。

meta标签

<meta>标签有很多种,而这里要着重说的是viewport的meta标签,其主要用来告诉浏览器如何规范的渲染Web页面,而你则需要告诉它视窗有多大。在开发移动端页面,我们需要设置meta标签如下:

XHTML

<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

1
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

代码以显示网页的屏幕宽度定义了视窗宽度。网页的比例和最大比例被设置为100%。

留个悬念,因为后面的解决方案中需要重度依赖meta标签。

if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {

(三),把视觉稿中的px转换成rem

CSS单位rem

在W3C规范中是这样描述rem的:

font size of the root element.

简单的理解,rem就是相对于根元素<html>font-size来做计算。而我们的方案中使用rem单位,是能轻易的根据<html>font-size计算出元素的盒模型大小。而这个特色对我们来说是特别的有益处。

dpr = 3;

工作中我们常见的视觉稿大小大至可为640、750、1125三种。不过flexible.js并没有限制只能用这三种,所以你还可以根据自身情况来调整,具体如何转换,我们以视觉稿为640px的宽来举例子,把640px分为100份,每一份称为一个单位a,那么每个a就是6.4px,而1rem单位被认定为10a,此时,1rem=1(a)X10X6.4(px)即64px。

前端实现方案

了解了前面一些相关概念之后,接下来我们来看实际解决方案。在整个手淘团队,我们有一个名叫lib-flexible的库,而这个库就是用来解决H5页面终端适配的。

} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){

640px/100=6.4px 1个单位a为6.4px
1rem = 10a 1rem单位被认定为10a
1rem = 1(a)106.4(px) = 64px
因此,对于视觉稿上的元素的尺寸换算,只需要原始px值除以rem基准px值(此例子中为64px)即可。例如240px * 120px的元素,最后转换为3.75rem * 1.875rem。

lib-flexible是什么?

lib-flexible是一个制作H5适配的开源库,可以点击这里下载相关文件,获取需要的JavaScript和CSS文件。

当然你可以直接使用阿里CDN:

JavaScript

<script src=";

1
<script src="http://g.tbcdn.cn/mtb/lib-flexible/{{version}}/??flexible_css.js,flexible.js"></script>

将代码中的{{version}}换成对应的版本号0.3.4

dpr = 2;

在开发过程中那我们如何快速的把px转换成rem呢?

使用方法

lib-flexible库的使用方法非常的简单,只需要在Web页面的<head></head>中添加对应的flexible_css.js,flexible.js文件:

第一种方法是将文件下载到你的项目中,然后通过相对路径添加:

XHTML

<script src="build/flexible_css.debug.js"></script> <script src="build/flexible.debug.js"></script>

1
2
<script src="build/flexible_css.debug.js"></script>
<script src="build/flexible.debug.js"></script>

或者直接加载阿里CDN的文件:

XHTML

<script src=";

1
<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>

另外强烈建议对JS做内敛处理,在所有资源加载之前执行这个JS。执行这个JS后,会在<html>元素上增加一个data-dpr属性,以及一个font-size样式。JS会根据不同的设备添加不同的data-dpr值,比如说2或者3,同时会给html加上对应的font-size的值,比如说75px

如此一来,页面中的元素,都可以通过rem单位来设置。他们会根据html元素的font-size值做相应的计算,从而实现屏幕的适配效果。

除此之外,在引入lib-flexible需要执行的JS之前,可以手动设置meta来控制dpr值,如:

XHTML

<meta name="flexible" content="initial-dpr=2" />

1
<meta name="flexible" content="initial-dpr=2" />

其中initial-dpr会把dpr强制设置为给定的值。如果手动设置了dpr之后,不管设备是多少的dpr,都会强制认为其dpr是你设置的值。在此不建议手动强制设置dpr,因为在Flexible中,只对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr1

JavaScript

if (!dpr && !scale) { var isAndroid = win.navigator.appVersion.match(/android/gi); var isIPhone = win.navigator.appVersion.match(/iphone/gi); var devicePixelRatio = win.devicePixelRatio; if (isIPhone) { // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案 if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) { dpr = 3; } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){ dpr = 2; } else { dpr = 1; } } else { // 其他设备下,仍旧使用1倍的方案 dpr = 1; } scale = 1 / dpr; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
if (!dpr && !scale) {
    var isAndroid = win.navigator.appVersion.match(/android/gi);
    var isIPhone = win.navigator.appVersion.match(/iphone/gi);
    var devicePixelRatio = win.devicePixelRatio;
    if (isIPhone) {
        // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
        if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {                
            dpr = 3;
        } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)){
            dpr = 2;
        } else {
            dpr = 1;
        }
    } else {
        // 其他设备下,仍旧使用1倍的方案
        dpr = 1;
    }
    scale = 1 / dpr;
}

} else {

1,如果你用的是Sublime Text3,你可以直接在这个编辑器上安装CSSREM插件。

flexible的实质

flexible实际上就是能过JS来动态改写meta标签,代码类似这样:

JavaScript

var metaEl = doc.createElement('meta'); var scale = isRetina ? 0.5:1; metaEl.setAttribute('name', 'viewport'); metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no'); if (docEl.firstElementChild) { document.documentElement.firstElementChild.appendChild(metaEl); } else { var wrap = doc.createElement('div'); wrap.appendChild(metaEl); documen.write(wrap.innerHTML); }

1
2
3
4
5
6
7
8
9
10
11
var metaEl = doc.createElement('meta');
var scale = isRetina ? 0.5:1;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
    document.documentElement.firstElementChild.appendChild(metaEl);
} else {
    var wrap = doc.createElement('div');
    wrap.appendChild(metaEl);
    documen.write(wrap.innerHTML);
}

事实上他做了这几样事情:

  • 动态改写<meta>标签
  • <html>元素添加data-dpr属性,并且动态改写data-dpr的值
  • <html>元素添加font-size属性,并且动态改写font-size的值

dpr = 1;

github地址:

案例实战

了解Flexible相关的知识之后,咱们回到文章开头。我们的目标是制作一个适配各终端的H5页面。别的不多说,动手才能丰衣足食。

}

2,如果你用的是其他编辑器或者IDE,就可以用CSS的处理器来处理,比如说Sass、LESS以及PostCSS这样的处理器。我们简单来看两个示例。

创建HTML模板

XHTML

<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta content="yes" name="apple-mobile-web-app-capable"> <meta content="yes" name="apple-touch-fullscreen"> <meta content="telephone=no,email=no" name="format-detection"> <script src="; <link rel="apple-touch-icon" href="favicon.png"> <link rel="Shortcut Icon" href="favicon.png" type="image/x-icon"> <title>再来一波</title> </head> <body> <!-- 页面结构写在这里 --> </body> </html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta content="yes" name="apple-mobile-web-app-capable">
        <meta content="yes" name="apple-touch-fullscreen">
        <meta content="telephone=no,email=no" name="format-detection">
        <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
        <link rel="apple-touch-icon" href="favicon.png">
        <link rel="Shortcut Icon" href="favicon.png" type="image/x-icon">
        <title>再来一波</title>
    </head>
    <body>
        <!-- 页面结构写在这里 -->
    </body>
</html>

正如前面所介绍的一样,首先加载了Flexible所需的配置:

XHTML

<script src=";

1
<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>

这个时候可以根据设计的图需求,在HTML文档的<body></body>中添加对应的HTML结构,比如:

XHTML

<div class="item-section" data-repeat="sections"> <div class="item-section_header"> <h2><img src="{brannerImag}" alt=""></h2> </div> <ul> <li data-repeat="items" class="flag" role="link" href="{itemLink}"> <a class="figure flag-item" href="{itemLink}"> <img src="{imgSrc}" alt=""> </a> <div class="figcaption flag-item"> <div class="flag-title"><a href="{itemLink}" title="">{poductName}</a></div> <div class="flag-price"><span>双11价</span><strong>¥{price}</strong><small>({preferential})</small></div> <div class="flag-type">{activityType}</div> <a class="flag-btn" href="{shopLink}">{activeName}</a> </div> </li> </ul> </div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="item-section" data-repeat="sections">
    <div class="item-section_header">
        <h2><img src="{brannerImag}" alt=""></h2>
    </div>
    <ul>
        <li data-repeat="items" class="flag" role="link" href="{itemLink}">
            <a class="figure flag-item" href="{itemLink}">
                <img src="{imgSrc}" alt="">
            </a>
            <div class="figcaption flag-item">
                <div class="flag-title"><a href="{itemLink}" title="">{poductName}</a></div>
                <div class="flag-price"><span>双11价</span><strong>¥{price}</strong><small>({preferential})</small></div>
                <div class="flag-type">{activityType}</div>
                <a class="flag-btn" href="{shopLink}">{activeName}</a>
            </div>
        </li>
    </ul>
</div>

这仅是一个示例文档,大家可以根据自己风格写模板

为了能更好的测试页面,给其配置一点假数据:

JavaScript

//define data var pageData = { sections:[{ "brannerImag":"", items:[{ "itemLink": "##", "imgSrc": "", "poductName":"Carter's1年式灰色长袖连体衣包脚爬服全棉鲸鱼男婴儿童装115G093", "price": "299.06", "preferential": "满400减100", "activityType": "1小时内热卖5885件", "shopLink":"##", "activeName": "马上抢!" } .... }] }] }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//define data
var pageData = {
    sections:[{
        "brannerImag":"http://xxx.cdn.com/B1PNLZKXXXXXaTXXXXXXXXXXXX-750-481.jpg",
        items:[{
            "itemLink": "##",
            "imgSrc": "https://placeimg.com/350/350/people/grayscale",
            "poductName":"Carter's1年式灰色长袖连体衣包脚爬服全棉鲸鱼男婴儿童装115G093",
            "price": "299.06",
            "preferential": "满400减100",
            "activityType": "1小时内热卖5885件",
            "shopLink":"##",
            "activeName": "马上抢!"
        }
            ....
        }]
    }]
}

接下来的工作就是美化工作了。在写具体样式之前,有几个点需要先了解一下。

} else {

@function px2em($px, $base-font-size: 75px) {
@if (unitless($px)) {
@warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
@return px2em($px + 0px); // That may fail.
} @else if (unit($px) == em) {
@return $px;
}
@return ($px / $base-font-size) * 1em;
}
除了使用Sass函数外,还可以使用Sass的混合宏:

把视觉稿中的px转换成rem

读到这里,大家应该都知道,我们接下来要做的事情,就是如何把视觉稿中的px转换成rem。在此花点时间解释一下。

首先,目前日常工作当中,视觉设计师给到前端开发人员手中的视觉稿尺寸一般是基于640px750px以及1125px宽度为准。甚至为什么?大家应该懂的(考虑Retina屏)。

正如文章开头显示的示例设计稿,他就是一张以750px为基础设计的。那么问题来了,我们如何将设计稿中的各元素的px转换成rem

9159.com 14

我厂的视觉设计师想得还是很周到的,会帮你把相关的信息在视觉稿上标注出来

目前Flexible会将视觉稿分成100份(主要为了以后能更好的兼容vhvw),而每一份被称为一个单位a。同时1rem单位被认定为10a。针对我们这份视觉稿可以计算出:

1a = 7.5px 1rem = 75px

1
2
1a   = 7.5px
1rem = 75px

那么我们这个示例的稿子就分成了10a,也就是整个宽度为10rem<html>对应的font-size75px

9159.com 15

这样一来,对于视觉稿上的元素尺寸换算,只需要原始的px值除以rem基准值即可。例如此例视觉稿中的图片,其尺寸是176px * 176px,转换成为2.346667rem * 2.346667rem

// 其他设备下,仍旧使用1倍的方案

@mixin px2rem($property,$px-values,$baseline-px:75px,$support-for-ie:false){
//Conver the baseline into rems
$baseline-rem: $baseline-px / 1rem * 1;
//打印出第一行的像素值
@if $support-for-ie {
#{$property}: $px-values;
}
//if there is only one (numeric) value, return the property/value line for it.
@if type-of($px-values) == "number"{
#{$property}: $px-values / $baseline-rem;
}
@else {
//Create an empty list that we can dump values into
$rem-values:();
@each $value in $px-values{
// If the value is zero or not a number, return it
@if $value == 0 or type-of($value) != "number"{
$rem-values: append($rem-values, $value / $baseline-rem);
}
}
// Return the property and its list of converted values
#{$property}: $rem-values;
}
}
(四),字体不使用rem的方法

如何快速计算

在实际生产当中,如果每一次计算px转换rem,或许会觉得非常麻烦,或许直接影响大家平时的开发效率。为了能让大家更快进行转换,我们团队内的同学各施所长,为px转换rem写了各式各样的小工具。

dpr = 1;

工作中做完一个触屏版的页面后,我们会拿iPhone5s、iPhone6、iPhone6s等手机进行测试,他们都是Retina屏,我们当然希望在这些手机型号上看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本(例如iPhone7、iPhone7Plus)。另外,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px和24px,都是偶数,所以我们不希望出现13px和15px这样的奇葩尺寸。
如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。

CSSREM

CSSREM是一个CSS的px值转rem值的Sublime Text3自动完成插件。这个插件是由@正霖编写。先来看看插件的效果:

9159.com 16

有关于CSSREM如何安装、配置教程可以点击这里查阅。

}

div {
width: 1rem;
height: 0.4rem;
font-size: 12px; // 默认写上dpr为1的fontSize
}
[data-dpr="2"] div {
font-size: 24px;
}
[data-dpr="3"] div {
font-size: 36px;
}
为了能更好的利于开发,在实际开发中,我们可以定制一个font-dpr()这样的Sass混合宏:

CSS处理器

除了使用编辑器的插件之外,还可以使用CSS的处理器来帮助大家处理。比如说Sass、LESS以及PostCSS这样的处理器。我们简单来看两个示例。

scale = 1 / dpr;

@mixin font-dpr($font-size){
font-size: $font-size;

Sass

使用Sass的同学,可以使用Sass的函数、混合宏这些功能来实现:

Sass

@function px2em($px, $base-font-size: 16px) { <a href='; (unitless($px)) { @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you"; @return px2em($px + 0px); // That may fail. } @else if (unit($px) == em) { @return $px; } @return ($px / $base-font-size) * 1em; }

1
2
3
4
5
6
7
8
9
@function px2em($px, $base-font-size: 16px) {
    <a href='http://www.jobbole.com/members/jinyi7016'>@if</a> (unitless($px)) {
        @warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
        @return px2em($px + 0px); // That may fail.
    } @else if (unit($px) == em) {
        @return $px;
    }
    @return ($px / $base-font-size) * 1em;
}

除了使用Sass函数外,还可以使用Sass的混合宏:

Sass

@mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){ //Conver the baseline into rems $baseline-rem: $baseline-px / 1rem * 1; //Print the first line in pixel values <a href='; $support-for-ie { #{$property}: $px-values; } //if there is only one (numeric) value, return the property/value line for it. <a href='; type-of($px-values) == "number"{ #{$property}: $px-values / $baseline-rem; } @else { //Create an empty list that we can dump values into $rem-values:(); @each $value in $px-values{ // If the value is zero or not a number, return it <a href='; $value == 0 or type-of($value) != "number"{ $rem-values: append($rem-values, $value / $baseline-rem); } } // Return the property and its list of converted values #{$property}: $rem-values; } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){
    //Conver the baseline into rems
    $baseline-rem: $baseline-px / 1rem * 1;
    //Print the first line in pixel values
    <a href='http://www.jobbole.com/members/jinyi7016'>@if</a> $support-for-ie {
        #{$property}: $px-values;
    }
    //if there is only one (numeric) value, return the property/value line for it.
    <a href='http://www.jobbole.com/members/jinyi7016'>@if</a> type-of($px-values) == "number"{
        #{$property}: $px-values / $baseline-rem;
    }
    @else {
        //Create an empty list that we can dump values into
        $rem-values:();
        @each $value in $px-values{
            // If the value is zero or not a number, return it
            <a href='http://www.jobbole.com/members/jinyi7016'>@if</a> $value == 0 or type-of($value) != "number"{
                $rem-values: append($rem-values, $value / $baseline-rem);
            }
        }
        // Return the property and its list of converted values
        #{$property}: $rem-values;
    }
}

有关于更多的介绍,可以点击这里进行了解。

}

[data-dpr="2"] & {
    font-size: $font-size * 2;
}

[data-dpr="3"] & {
    font-size: $font-size * 3;
}
PostCSS(px2rem)

除了Sass这样的CSS处理器这外,我们团队的@颂奇同学还开发了一款npm的工具px2rem。安装好px2rem之后,可以在项目中直接使用。也可以使用PostCSS。使用PostCSS插件postcss-px2rem:

JavaScript

var gulp = require('gulp'); var postcss = require('gulp-postcss'); var px2rem = require('postcss-px2rem'); gulp.task('default', function() { var processors = [px2rem({remUnit: 75})]; return gulp.src('./src/*.css') .pipe(postcss(processors)) .pipe(gulp.dest('./dest')); });

1
2
3
4
5
6
7
8
9
10
var gulp = require('gulp');
var postcss = require('gulp-postcss');
var px2rem = require('postcss-px2rem');
 
gulp.task('default', function() {
    var processors = [px2rem({remUnit: 75})];
    return gulp.src('./src/*.css')
        .pipe(postcss(processors))
        .pipe(gulp.dest('./dest'));
});

除了在Gulp中配置外,还可以使用其他的配置方式,详细的介绍可以点击这里进行了解。

配置完成之后,在实际使用时,你只要像下面这样使用:

CSS

.selector { width: 150px; height: 64px; /*px*/ font-size: 28px; /*px*/ border: 1px solid #ddd; /*no*/ }

1
2
3
4
5
6
.selector {
    width: 150px;
    height: 64px; /*px*/
    font-size: 28px; /*px*/
    border: 1px solid #ddd; /*no*/
}

px2rem处理之后将会变成:

CSS

.selector { width: 2rem; border: 1px solid #ddd; } [data-dpr="1"] .selector { height: 32px; font-size: 14px; } [data-dpr="2"] .selector { height: 64px; font-size: 28px; } [data-dpr="3"] .selector { height: 96px; font-size: 42px; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.selector {
    width: 2rem;
    border: 1px solid #ddd;
}
[data-dpr="1"] .selector {
    height: 32px;
    font-size: 14px;
}
[data-dpr="2"] .selector {
    height: 64px;
    font-size: 28px;
}
[data-dpr="3"] .selector {
    height: 96px;
    font-size: 42px;
}

在整个开发中有了这些工具之后,完全不用担心px值转rem值影响开发效率。

flexible的实质

}
有了这样的混合宏之后,在开发中可以直接这样使用:

字号不使用rem

前面大家都见证了如何使用rem来完成H5适配。那么文本又将如何处理适配。是不是也通过rem来做自动适配。

显然,我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px24px,所以我们不希望出现13px15px这样的奇葩尺寸

如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。

CSS

.selector { width: 2rem; border: 1px solid #ddd; } [data-dpr="1"] .selector { height: 32px; font-size: 14px; } [data-dpr="2"] .selector { height: 64px; font-size: 28px; } [data-dpr="3"] .selector { height: 96px; font-size: 42px; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.selector {
    width: 2rem;
    border: 1px solid #ddd;
}
[data-dpr="1"] .selector {
    height: 32px;
    font-size: 14px;
}
[data-dpr="2"] .selector {
    height: 64px;
    font-size: 28px;
}
[data-dpr="3"] .selector {
    height: 96px;
    font-size: 42px;
}

为了能更好的利于开发,在实际开发中,我们可以定制一个font-dpr()这样的Sass混合宏:

Sass

@mixin font-dpr($font-size){ font-size: $font-size; [data-dpr="2"] & { font-size: $font-size * 2; } [data-dpr="3"] & { font-size: $font-size * 3; } }

1
2
3
4
5
6
7
8
9
10
11
@mixin font-dpr($font-size){
    font-size: $font-size;
 
    [data-dpr="2"] & {
        font-size: $font-size * 2;
    }
 
    [data-dpr="3"] & {
        font-size: $font-size * 3;
    }
}

有了这样的混合宏之后,在开发中可以直接这样使用:

Sass

<a href='; font-dpr(16px);

1
<a href='http://www.jobbole.com/members/sanjiaomaohero'>@include</a> font-dpr(16px);

当然这只是针对于描述性的文本,比如说段落文本。但有的时候文本的字号也需要分场景的,比如在项目中有一个slogan,业务方希望这个slogan能根据不同的终端适配。针对这样的场景,完全可以使用rem给slogan做计量单位。

flexible实际上就是能过JS来动态改写meta标签,代码类似这样:

@include font-dpr(16px);
当然这只是针对于描述性的文本,比如说段落文本。但有的时候文本的字号也需要分场景的,比如在项目中有一个slogan,业务方希望这个slogan能根据不同的终端适配。针对这样的场景,完全可以使用rem给slogan做计量单位。

CSS

本来想把这个页面的用到的CSS(或SCSS)贴出来,但考虑篇幅过长,而且这么简单的页面,我想大家也能轻而易举搞定。所以就省略了。权当是给大家留的一个作业吧,感兴趣的可以试试Flexible能否帮你快速完成H5页面终端适配。

var metaEl = doc.createElement('meta');

(五),viewport的meta标签。

效果

最后来看看真机上显示的效果吧。我截了两种设备下的效果:

var scale = isRetina ? 0.5:1;

该标签主要用来告诉浏览器如何规范的渲染Web页面,而你则需要告诉它视窗有多大。在开发移动端页面,我们需要设置meta标签如下:

iPhone4

9159.com 17

metaEl.setAttribute('name', 'viewport');

代码以显示网页的屏幕宽度定义了视窗宽度。网页的比例和最大比例被设置为100%。

iPhone6+

9159.com 18

metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

而我们在使用flexible.js时候就只需要像下面这样写

总结

其实H5适配的方案有很多种,网上有关于这方面的教程也非常的多。不管哪种方法,都有其自己的优势和劣势。而本文主要介绍的是如何使用Flexible这样的一库来完成H5页面的终端适配。为什么推荐使用Flexible库来做H5页面的终端设备适配呢?主要因为这个库在手淘已经使用了近一年,而且已达到了较为稳定的状态。除此之外,你不需要考虑如何对元素进行折算,可以根据对应的视觉稿,直接切入。

当然,如果您有更好的H5页面终端适配方案,欢迎在下面的评论中与我们一起分享。如果您在使用这个库时,碰到任何问题,都可以在Github给我们提Issue。我们团队会努力解决相关需Issues。

4 赞 18 收藏 7 评论

9159.com 19

if (docEl.firstElementChild) {

标签,或者干脆省略下面的标签:

document.documentElement.firstElementChild.appendChild(metaEl);

或者我们也可以像flexible的github例子中那样写:

} else {

原理:flexible.js会先去获取页面上[name="viewport"]或[name="flexible"]的meta标签,如果有就直接根据获取到的值来判断,如果没有,会自己创建一个meta标签,我们看一下源码就知道了。

var wrap = doc.createElement('div');

var metaEl = doc.querySelector('meta[name="viewport"]');
var flexibleEl = doc.querySelector('meta[name="flexible"]');
...
if (!metaEl) {
metaEl = doc.createElement('meta');
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
if (docEl.firstElementChild) {
docEl.firstElementChild.appendChild(metaEl);
} else {
var wrap = doc.createElement('div');
wrap.appendChild(metaEl);
doc.write(wrap.innerHTML);
}
}
有了

wrap.appendChild(metaEl);

标签之后,就可以动态改写data-dpr和font-size两个属性的值,因此也就达到了适配的效果。

documen.write(wrap.innerHTML);

二,手动设置的相关问题:

}

(一)手动配置dpr

事实上他做了这几样事情:

引入执行js之前,可以通过输出meta标签方式来手动设置dpr。语法如下:

动态改写标签

注意:initial-dpr=2, maximum-dpr=3这两个参数只能选其一。

给元素添加data-dpr属性,并且动态改写data-dpr的值

(二),当我们手动设置maximum-dpr=x时

给元素添加font-size属性,并且动态改写font-size的值

在flexible的github例子中,添加maximum-dpr这个属性,content="maximum-dpr=2",这个属性是给出一个最大的dpr限制,然后比较系统的dpr和给定的dpr,取最小值。

案例实战

(三),当我们手动设置initial-dpr=x时

了解Flexible相关的知识之后,咱们回到文章开头。我们的目标是制作一个适配各终端的H5页面。别的不多说,动手才能丰衣足食。

如果要使用flexible.js来做布局的话,建议不要添加这个属性,因为这个属性会把dpr强制设置为给定的值,如果手动设置initial-dpr=1之后,不管设备是多少dpr都会强制认为其dpr是你设备的值。
另外,在flexible中,只对IOS设备进行dpr判断,对于Android系列始终认为其dpr为1,手机淘宝并没有对安卓的dpr进行一个适配。咱们可以通过flexible.js的源码来看:

创建HTML模板

if (!dpr && !scale) {
var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
// iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
dpr = 3;
} else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
dpr = 2;
} else {
dpr = 1;
}
} else {
// 其他设备下,仍旧使用1倍的方案
dpr = 1;
}
scale = 1 / dpr;
}
作者:Scaukk 在这篇
android手机屏幕大小,宽高比是花开满地,要做的调整真的是太多了。如果根元素的font-size尺寸不对,页面效果不用多说。
就算把当前的设备信息都考虑进去了,那以后呢。
所以,考虑开发,维护,兼容性...淘宝这么做还是有道理的。

再来一波

(四),手动设置rem基准值的方法:

正如前面所介绍的一样,首先加载了Flexible所需的配置:

html{ font-size: 60px !important; }
三,需要注意的几个地方:

这个时候可以根据设计的图需求,在HTML文档的中添加对应的HTML结构,比如:

(一),遇到下面两种情况的时候,我们在切页面的时候需要切两套图片,即@2x和@3x:

9159.com 20

1,当图标被放大时会模糊。

2,当产品对页面上的图片清晰度要求很高时。

9159.com 21

@2x为750X1334的设计稿(高度会随着内容多少而改变)。@3x为1125X2001的设计稿(高度会随着内容多少而改变)。如果要放大设计稿来切图的时候是等比放大1.5倍。

{poductName}

(二), 解决雪碧图的问题,建议能用SVG的地方就尽量用SVG,或者有些常用的图标用iconfont来替代,另外,有些小图片在遇到dpr=2时,可能会模糊,这时建议用大图来切图。

双11价

五,几个后期我们开发中可能会遇到的名词:

¥{price}

Element.getBoundingClientRect().width 用来获取元素自身的宽度。

({preferential})

Element.getBoundingClientRect()用来获取页面中某个元素的左、上、右、下分别相对于浏览器视窗的位置,是DOM元素到浏览器可视范围的距离(不含页面不可见部分)。

{activityType}

设备的px不会改变,css的px改变%(百分比)时,不会影响设备的px,只是原本设备的1个px中可能会显示多个或不足一个css的px。当缩放级别100%时,1个单位的css px严格等于1个单位的设备px。

{activeName}

screen.width、screen.height用户屏幕的完整宽度和高度。

这仅是一个示例文档,大家可以根据自己风格写模板。

window.innerWidth、window.innerHeight浏览器窗口内部宽度和高度的尺寸,包含了滚动条的尺寸。

为了能更好的测试页面,给其配置一点假数据:

window.pageXOffset、window.pageYOffset用户滚动了多少滚动条的距离。

//define data

视窗viewport 简单的理解,viewport是严格等于浏览器的窗口。在桌面浏览器中,viewport就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。移动端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport:虚拟的viewportvisualviewport和布局的viewportlayoutviewport。

var pageData = {

Retina 是视网膜的意思,指显示屏的分辨率极高,使得肉眼无法分辨单个像素。

sections:[{

物理像素,也可以称为设备像素,他是显示设备中一个最微小的物理部件,每个像素可以根据操作系统设置自己的颜色和亮度。正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。

"brannerImag":"",

设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。

items:[{

CSS像素是一个抽像的单位,主要使用在浏览器上,用来精确度量Web页面上的内容。一般情况之下,CSS像素称为与设备无关的像素(device-independent pixel),简称DIPs。

"itemLink": "##",

屏幕密度,即设备表面上存在的像素数量,通常以每英寸有多少像素来计算(PPI)。

"imgSrc": "",

设备像素比(device pixel ratio),简称dpr,定义了物理像素和设备独立像素的对应关系,它的值可以按下面的公式计算得到:

"poductName":"Carter's1年式灰色长袖连体衣包脚爬服全棉鲸鱼男婴儿童装115G093",

设备像素比 = 物理像素 / 设备独立像素
众所周知,iPhone6的设备宽度和高度为375pt * 667pt,可以理解为设备的独立像素;而其dpr为2,根据上面公式,我们可以很轻松得知其物理像素为750pt * 1334pt。
在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。
在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。

"price": "299.06",

转自:

"preferential": "满400减100",

"activityType": "1小时内热卖5885件",

"shopLink":"##",

"activeName": "马上抢!"

}

....

}]

}]

}

接下来的工作就是美化工作了。在写具体样式之前,有几个点需要先了解一下。

把视觉稿中的px转换成rem

读到这里,大家应该都知道,我们接下来要做的事情,就是如何把视觉稿中的px转换成rem。在此花点时间解释一下。

首先,目前日常工作当中,视觉设计师给到前端开发人员手中的视觉稿尺寸一般是基于640px、750px以及1125px宽度为准。甚至为什么?大家应该懂的(考虑Retina屏)。

正如文章开头显示的示例设计稿,他就是一张以750px为基础设计的。那么问题来了,我们如何将设计稿中的各元素的px转换成rem。

我厂的视觉设计师想得还是很周到的,会帮你把相关的信息在视觉稿上标注出来。

目前Flexible会将视觉稿分成100份(主要为了以后能更好的兼容vh和vw),而每一份被称为一个单位a。同时1rem单位被认定为10a。针对我们这份视觉稿可以计算出:

1a  = 7.5px

1rem = 75px

那么我们这个示例的稿子就分成了10a,也就是整个宽度为10rem,对应的font-size为75px:

9159.com 22

这样一来,对于视觉稿上的元素尺寸换算,只需要原始的px值除以rem基准值即可。例如此例视觉稿中的图片,其尺寸是176px * 176px,转换成为2.346667rem * 2.346667rem。

如何快速计算

在实际生产当中,如果每一次计算px转换rem,或许会觉得非常麻烦,或许直接影响大家平时的开发效率。为了能让大家更快进行转换,我们团队内的同学各施所长,为px转换rem写了各式各样的小工具。

CSSREM

CSSREM是一个CSS的px值转rem值的Sublime Text3自动完成插件。这个插件是由@正霖编写。先来看看插件的效果:

9159.com 23

有关于CSSREM如何安装、配置教程可以点击这里查阅。

CSS处理器

除了使用编辑器的插件之外,还可以使用CSS的处理器来帮助大家处理。比如说Sass、LESS以及PostCSS这样的处理器。我们简单来看两个示例。

Sass

使用Sass的同学,可以使用Sass的函数、混合宏这些功能来实现:

@function px2em($px, $base-font-size: 16px) {

@if (unitless($px)) {

@warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";

@return px2em($px + 0px); // That may fail.

} @else if (unit($px) == em) {

@return $px;

}

@return ($px / $base-font-size) * 1em;

}

除了使用Sass函数外,还可以使用Sass的混合宏:

@mixin px2rem($property,$px-values,$baseline-px:16px,$support-for-ie:false){

//Conver the baseline into rems

$baseline-rem: $baseline-px / 1rem * 1;

//Print the first line in pixel values

@if $support-for-ie {

#{$property}: $px-values;

}

//if there is only one (numeric) value, return the property/value line for it.

@if type-of($px-values) == "number"{

#{$property}: $px-values / $baseline-rem;

}

@else {

//Create an empty list that we can dump values into

$rem-values:();

@each $value in $px-values{

// If the value is zero or not a number, return it

@if $value == 0 or type-of($value) != "number"{

$rem-values: append($rem-values, $value / $baseline-rem);

}

}

// Return the property and its list of converted values

#{$property}: $rem-values;

}

}

有关于更多的介绍,可以点击这里进行了解。

PostCSS(px2rem)

除了Sass这样的CSS处理器这外,我们团队的@颂奇同学还开发了一款npm的工具px2rem。安装好px2rem之后,可以在项目中直接使用。也可以使用PostCSS。使用PostCSS插件postcss-px2rem:

var gulp = require('gulp');

var postcss = require('gulp-postcss');

var px2rem = require('postcss-px2rem');

gulp.task('default', function() {

var processors = [px2rem({remUnit: 75})];

return gulp.src('./src/*.css')

.pipe(postcss(processors))

.pipe(gulp.dest('./dest'));

});

除了在Gulp中配置外,还可以使用其他的配置方式,详细的介绍可以点击这里进行了解。

配置完成之后,在实际使用时,你只要像下面这样使用:

.selector {

width: 150px;

height: 64px; /*px*/

font-size: 28px; /*px*/

border: 1px solid #ddd; /*no*/

}

px2rem处理之后将会变成:

.selector {

width: 2rem;

border: 1px solid #ddd;

}

[data-dpr="1"] .selector {

height: 32px;

font-size: 14px;

}

[data-dpr="2"] .selector {

height: 64px;

font-size: 28px;

}

[data-dpr="3"] .selector {

height: 96px;

font-size: 42px;

}

在整个开发中有了这些工具之后,完全不用担心px值转rem值影响开发效率。

文本字号不建议使用rem

前面大家都见证了如何使用rem来完成H5适配。那么文本又将如何处理适配。是不是也通过rem来做自动适配。

显然,我们在iPhone3G和iPhone4的Retina屏下面,希望看到的文本字号是相同的。也就是说,我们不希望文本在Retina屏幕下变小,另外,我们希望在大屏手机上看到更多文本,以及,现在绝大多数的字体文件都自带一些点阵尺寸,通常是16px和24px,所以我们不希望出现13px和15px这样的奇葩尺寸。

如此一来,就决定了在制作H5的页面中,rem并不适合用到段落文本上。所以在Flexible整个适配方案中,考虑文本还是使用px作为单位。只不过使用[data-dpr]属性来区分不同dpr下的文本字号大小。

div {

width: 1rem;

height: 0.4rem;

font-size: 12px; // 默认写上dpr为1的fontSize

}

[data-dpr="2"] div {

font-size: 24px;

}

[data-dpr="3"] div {

font-size: 36px;

}

为了能更好的利于开发,在实际开发中,我们可以定制一个font-dpr()这样的Sass混合宏:

@mixin font-dpr($font-size){

font-size: $font-size;

[data-dpr="2"] & {

font-size: $font-size * 2;

}

[data-dpr="3"] & {

font-size: $font-size * 3;

}

}

有了这样的混合宏之后,在开发中可以直接这样使用:

@include font-dpr(16px);

当然这只是针对于描述性的文本,比如说段落文本。但有的时候文本的字号也需要分场景的,比如在项目中有一个slogan,业务方希望这个slogan能根据不同的终端适配。针对这样的场景,完全可以使用rem给slogan做计量单位。

CSS

本来想把这个页面的用到的CSS(或SCSS)贴出来,但考虑篇幅过长,而且这么简单的页面,我想大家也能轻而易举搞定。所以就省略了。权当是给大家留的一个作业吧,感兴趣的可以试试Flexible能否帮你快速完成H5页面终端适配。

效果

最后来看看真机上显示的效果吧。我截了两种设备下的效果:

iPhone4

9159.com 24

iPhone6+

9159.com 25

本文由9159.com发布于前端,转载请注明出处:设计师通常会选择iPhone6作为基准设计尺寸,可没

关键词: