像素级还原视觉稿

屏幕适配和像素级还原视觉稿是一个老生常谈的话题了,但是具体做到了这一点的线上项目并不多,相关技术并不复杂,只是老项目一但成形,改造成本不亚于重构整个项目。但是我们应该在新的项目中去实践这种技术,更好的还原视觉稿。

现有适配的方案

  • 百分比布局 / Flex 布局
    不同的屏幕宽度下布局不一致,宽屏下会布局被拉长,1px的边框使用hack的方式实现,例如:天猫
  • 查询+REM
    一定范围内固定的根字体大小,并不能完全适配所有手机屏幕,特别是Android手机,1px通过hack方式实现
  • REM 布局
    能保持布局一致,但高清适配需要结合其它方案,如:小米
  • REM布局 + Flex布局 + 视口缩放
    能灵活控制布局,也能高清适配,例如:手淘

其它布局方案及原理,这里不详细介绍了,如果有不明白的地方,请参考我之前写的 移动端高清屏适配方案

这里着重介绍如何应用实践 REM+视口缩放 的适配方案

高清适配

方案

手淘 Flexible.js 可伸缩布局方案

Ant.desigin的方案

这两种方案都是动态的根据屏幕宽度和当前设置的DPR的值,设置根字体的大小。

首先给定一个rem参考值,比如100px,750的设计稿还原到iphone6下,就是缩放一倍,根字体大小为50px,但iphone6中DPR为2,为了适配高清,应将原来的750大小的页面缩放0.5倍,这样,按照根字体100px的标准切出来的图,在iphone6下就高清还原视觉稿了

为了适应不同的DPR和屏幕宽度就需要JS动态设置当前的viewport的缩放比例和根字体的大小了

PX转REM

由于我们动态的要的屏幕度设置了不同的根字体大小,并且需要界面随根字体大小而调整,所以需要将px单位转换为rem单位。

结合Webpack插件,安装 postcss-pxtorem 插件,自动转换px为rem,在webpack.config.js里新增pxtorem配置、代码如下:

const pxtorem = require('postcss-pxtorem');
webpackConfig.postcss.push(pxtorem({
rootValue: 100,
propWhiteList: [],
}));

rootValue 为初始根字体参照大小,
比如750的设计稿,rootValue100px, 那么750设计稿中,30px 会被转换为 0.3rem

如果是采用上面 flexible.js 的方案,那么750设计稿的根字根会被计算为75px,使用 postcss-pxtorem时,rootValue 应该设置为 75px

当然也可以结合postcss的 px2rem 插件去做转换。

具体如何使用 flexible方案做适配,请查看大漠老师的教程使用Flexible实现手淘H5页面的终端适配

用来做适配的js必须在所有css引入之前加载

标注工具

Mark Man 部分功能收费

  • 长度、坐标、矩形、颜色、文字标注
  • 按Tab键自动测量
  • 拖拽删除和调整
  • 末尾是@2x的图自动缩小50%,以便测量

PxCool 免费且功能十分强大,智能标注绝对可以解放双手了,强烈推荐

PxCool 除以上功能外还具有:

  • 具有自动吸附
  • 自动检测边距、字体类型、字体大小、颜色等等

这两个工具都是Adobe AIR程序,兼容Win与Mac平台

应用实践

第一步

在html模板的头部引用适配JS并执行

<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>title</title>
<script>/** 高清方案脚本 */
!function(e){function t(a){if(i[a])return i[a].exports;var n=i[a]={exports:{},id:a,loaded:!1};return e[a].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var i={};return t.m=e,t.c=i,t.p="",t(0)}([function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=window;t["default"]=i.flex=function(e,t){var a=e||100,n=t||1,r=i.document,o=navigator.userAgent,d=o.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i),l=o.match(/U3\/((\d+|\.){5,})/i),c=l&&parseInt(l[1].split(".").join(""),10)>=80,p=navigator.appVersion.match(/(iphone|ipad|ipod)/gi),s=i.devicePixelRatio||1;p||d&&d[1]>534||c||(s=1);var u=1/s,m=r.querySelector('meta[name="viewport"]');m||(m=r.createElement("meta"),m.setAttribute("name","viewport"),r.head.appendChild(m)),m.setAttribute("content","width=device-width,user-scalable=no,initial-scale="+u+",maximum-scale="+u+",minimum-scale="+u),r.documentElement.style.fontSize=a/2*s*n+"px"},e.exports=t["default"]}]);
flex(100, 1);
</script>
</head>
<body></body>
</html>

这里使用的是 antd mobile 的flex高清适配方案

第二步

使用px to rem 插件转换px

webpack.config.js 中添加插件

const pxtorem = require('postcss-pxtorem');

module.exports = {
entry: pageEntries,
output: {}
resolve:{}
....
postcss:[
autoprefixer({browsers:['last 2 versions']}),
pxtorem({
rootValue: 100,
propWhiteList: [],
})
]
...
}

第三步

使用标注工具标注,按照标注图上的实际尺寸编写CSS,构建时,webpack或gulp借助插件自动将px转为rem。

另外,关于图片的高清适配,可以根当前的dpr的值,借助七牛的图片处理能加,使用不同的后缀加载不同的图片即可。

关于REM的参考标准

根字体应该设定为多少,并没有一定的标准,设置的根字体大小只是rem的参考标准,比如我的设计稿是750的宽度,那么根字体设置为100px,1rem就为100px,10px就等于0.1rem,这样设计稿上的尺寸就算不借助于工具也能心算出来,14px = .14rem,40px = .4rem,设置为100px的好处是可以心算出rem的值同时减少小数位。