移动端web开发的设计稿与工作流

致谢

一直以来移动端适配便是困扰自己的一个难题,今天休息,查阅了很多资料将其整理出来。本文中很多做法是直接借鉴了网上的文章,主要有从网易与淘宝的font-size思考前端设计稿与工作流手机端页面自适应解决方案—rem布局进阶版(附源码示例),向大神致谢。

移动设备的分辨率

设备 屏幕尺寸 逻辑分辨率(pt) Reader 物理分辨率(px)
iPhone 3GS 3.5寸 320*480 @1x 320*480
iPhone 4/4S 3.5寸 320*480 @2x 640*960
iPhone 5/5S/5C 4.0寸 320*568 @2x 640*1136
iPhone 6/6S 4.7寸 375*667 @2x 750*1134
iPhone 6/6S Plus 5.5寸 414*736 @3x 1242*2208
  1. pt是逻辑分辨率,简单理解就是跟屏幕的尺寸有关系,是个长度跟视觉的单位。
  2. px是物理分辨率,简单理解为像素点,跟屏幕的尺寸是没关系的。

小结:pt与px的关系是,一个单位的pt里包含几个px,包含的px越多,则越清晰。但因为人视网膜的关系,最多只能识别单位pt里2个像素点,大于2个像素点,人眼识别不出,所以6plus看上去不会比6更清晰。

移动端web开发的设计稿与工作流

移动端web开发的难点之一是适应各种分辨率的移动设备——众所周知,应该使用rem。
但实际操作中,如何确定html上的font-size,是一个难点。一般有以下几种方式:

使用CSS3媒体查询

html{font-size:10px}
@media screen and (min-width:321px) and (max-width:375px){html{font-size:11px}}
@media screen and (min-width:376px) and (max-width:414px){html{font-size:12px}}
@media screen and (min-width:415px) and (max-width:639px){html{font-size:15px}}
@media screen and (min-width:640px) and (max-width:719px){html{font-size:20px}}
@media screen and (min-width:720px) and (max-width:749px){html{font-size:22.5px}}
@media screen and (min-width:750px) and (max-width:799px){html{font-size:23.5px}}
@media screen and (min-width:800px){html{font-size:25px}}

用CSS3媒体查询明显不足有:

  1. 需要写大量的媒体查询以适应不同的设备
  2. 媒体查询的范围不一定合适
  3. 每个媒体查询里的font-size难以定义
  4. 每次给元素设置rem都需要根据某个分辨率html的font-size去算,工作量大。

小结:CSS3媒体查询理论上可以,但操作起来不灵活

简单问题简单解决

有些web app比较简单,记住一个开发原则就好:文字流式,控件弹性,图片等比缩放。以图描述:


移动端布局1.png

网易的做法

网易的页面复杂度较高,随着分辨率增大,网易页面的效果也会发生明显变化,要达到这种效果,就需要使用rem作为单位,且<font color="red">html的font-size是通过js计算出来的。</font>
网易移动web的工作流可以总结如下:

第一步 设置视口的viewport

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

第二步 以iphone6/6S设计稿为基准确定body及页面元素的尺寸

网易网页的设计稿是基于iphone6/6S,物理分辨率(设计稿宽度)为750px,逻辑分辨率(deviceWidth)为375。
为了计算方便,先拿设计稿竖着的横向分辨率除以100得到body元素的宽度:750 / 100 = 7.5rem
同理,布局时页面上的元素的尺寸,可以拿设计图标注的尺寸除以100得到。

第三步 计算html的fontSize以适配各个尺寸的屏幕

    document.documentElement.style.fontSize = document.documentElement.clientWidth / 7.5 + 'px';

第四步 细节调整

当deviceWidth大于设计稿的横向分辨率时,html的font-size始终等于横向分辨率/body元素宽。

之所以这么干,是因为当deviceWidth大于640时,则物理分辨率大于1280,应该去访问pc网站了。只需将第三步做下调整即可。

    var deviceWidth = document.documentElement.clientWidth;
    if(deviceWidth > 640) deviceWidth = 640;
    document.documentElement.style.fontSize = deviceWidth / 6.4 + 'px';

可能需要额外的媒介查询

网页上有一些结构是不需要随着屏幕变大而相应调整,比如底部导航栏,此时可以使用媒体查询。

淘宝的做法

知识预备,了解viewport

通常我们采用如下代码设置viewport:

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

这样整个网页在设备内显示时的页面宽度就会等于设备逻辑像素大小,也就是device-width。这个device-width的计算公式为:设备的物理分辨率/(devicePixelRatio * scale)

devicePixelRatio称为设备像素比,每款设备的devicePixelRatio都是已知,并且不变的,目前高清屏,普遍都是2,不过还有更高的,比如2.5,3等。淘宝触屏版布局的前提就是viewport的scale根据devicePixelRatio动态设置.

  • 在devicePixelRatio为2的时候,scale为0.5
  • 在devicePixelRatio为3的时候,scale为0.3333

这么做目的是为了保证页面的大小与设计稿保持一致,比如如果是750的横向物理分辨率,那么实际页面的device-width也等于750。

接下来要解决的问题是:
元素的尺寸该如何计算,比如说设计稿上某一个元素的宽为150px,换算成rem应该怎么算呢?这个值等于设计稿标注尺寸/该设计稿对应的html的font-size。拿淘宝来说的,他们用的设计稿是750的,所以html的font-size就是75,如果某个元素时150px的宽,换算成rem就是150 / 75 = 2rem。

第一步 动态设置viewport的scale

    var scale = 1 / devicePixelRatio;
    document.querySelector('meta[name="viewport"]').setAttribute('content','initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');

第二步 动态计算html的font-size

    document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';

因为第一步已经根据devicePixelRatio动态设置scale,此时device-width便等于页面的横向物理分辨率(document.documentElement.clientWidth),也就是设计稿的的横向物理分辨率。
淘宝的做法是,设计稿是750,那么html的font-size就是75。

第三步 确定布局时各个元素的尺寸

布局的时候,各元素的css尺寸 = 设计稿标注尺寸/设计稿横向分辨率/10 = 设计稿标注尺寸/html的font-size

第四步 细节调整

  1. font-size可能需要额外的媒介查询,并且font-size不使用rem,这一点跟网易是一样的。
  2. 跟网易一样,淘宝也设置了一个临界点,当设备竖着时横向物理分辨率大于1080时,html的font-size就不会变化了,原因也是一样的,分辨率已经可以去访问电脑版页面了。

与网易的做法比较

共同点:

  1. 都能适配所有的手机设备,对于pad,网易与淘宝都会跳转到pc页面,不再使用触屏版的页面
    都需要动态设置html的font-size
  2. 布局时各元素的尺寸值都是根据设计稿标注的尺寸计算出来,由于html的font-size是动态调整的,所以能够做到不同分辨率下页面布局呈现等比变化
  3. 容器元素的font-size都不用rem,需要额外地对font-size做媒介查询
  4. 都能应用于尺寸不同的设计稿,只要按以上总结的方法去用就可以了

不同点

  1. 淘宝还需要动态设置viewport的scale,网易不用
  2. 网易的做法,rem值很好计算,淘宝的做法可能需要使用less和sass的css处理器

阿里团队的高清方案布局

高清方案的源码

    'use strict';

    /**
     * @param {Boolean} [normal = false] - 默认开启页面压缩以使页面高清;  
     * @param {Number} [baseFontSize = 100] - 基础fontSize, 默认100px;
     * @param {Number} [fontscale = 1] - 有的业务希望能放大一定比例的字体;
     */
    const win = window;
    export default win.flex = (normal, baseFontSize, fontscale) => {
      const _baseFontSize = baseFontSize || 100;
      const _fontscale = fontscale || 1;

      const doc = win.document;
      const ua = navigator.userAgent;
      const matches = ua.match(/Android[\S\s]+AppleWebkit\/(\d{3})/i);
      const UCversion = ua.match(/U3\/((\d+|\.){5,})/i);
      const isUCHd = UCversion && parseInt(UCversion[1].split('.').join(''), 10) >= 80;
      const isIos = navigator.appVersion.match(/(iphone|ipad|ipod)/gi);
      let dpr = win.devicePixelRatio || 1;
      if (!isIos && !(matches && matches[1] > 534) && !isUCHd) {
        // 如果非iOS, 非Android4.3以上, 非UC内核, 就不执行高清, dpr设为1;
        dpr = 1;
      }
      const scale = normal ? 1 : 1 / dpr;

      let metaEl = doc.querySelector('meta[name="viewport"]');
      if (!metaEl) {
        metaEl = doc.createElement('meta');
        metaEl.setAttribute('name', 'viewport');
        doc.head.appendChild(metaEl);
      }
      metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`);
      doc.documentElement.style.fontSize = normal ? '50px' : `${_baseFontSize / 2 * dpr * _fontscale}px`;
    };

原理

与上述淘宝的原理一致。
动态设置 html 的font-size, 同时根据设备DPR调整页面的缩放值,此时device-width便等于页面的横向物理分辨率(document.documentElement.clientWidth),也就是设计稿的的横向物理分辨率。

优势

  1. 引用简单,布局简便
  2. 根据设备屏幕的DPR,自动设置最合适的高清缩放。
  3. 保证了不同设备下视觉体验的一致性。(老方案是,屏幕越大元素越大;此方案是,屏幕越大,看的越多)
  4. 有效解决移动端真实1px问题(这里的1px 是设备屏幕上的物理像素)

使用

此方案也是默认 1rem = 100px,布局时,根据设计稿尺寸/100即可得到物理分辨率的尺寸

注意事项

  1. 如果元素的宽度超过效果图宽度的一半(效果图宽为640或750),果断使用百分比宽度,或者flex布局。可以避免类似于在 iphone6 上没问题, 在 iphone5上会有横向滚动条的问题
  2. 此方案是根据设备的dpr动态设置html的font-size,且默认DPR是2,1rem = 100px,如果设计稿是iphone 6 sp (dpr = 3),将代码的最后的flex(false, 100, 1)修改成flex(false, 66.66667, 1)

如何与设计师协作

手机淘宝团队适配协作模式.png
  1. 视觉设计阶段,设计师按宽度750px(iPhone 6)做设计稿,除图片外所有设计元素用矢量路径来做。设计定稿后在750px的设计稿上做标注,输出标注图。同时等比放大1.5倍生成宽度1125px的设计稿,在1125px的稿子里切图。
  2. 输出两个交付物给开发工程师:一个是程序用到的@3x切图资源,另一个是宽度750px的设计标注图。之所以要在@3x的图里切,这是因为现在市面上也有不少像魅蓝note这种超高清屏幕,devicePixelRatio已经达到3了,这个切图保证在所有设备都清晰显示。
  3. 开发工程师拿到750px标注图和@3x切图资源,完成iPhone6(375pt)的界面开发,需要使用上文提到的适配方法。
  4. 适配调试阶段,基于iPhone 6的界面效果,分别向上向下调试iPhone 6 plus(414pt)和iPhone 5S及以下(320pt)的界面效果。由此完成大中小三屏适配。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容