翻页H5全分辨率适配最佳实践

全分辨率适配是移动开发的一个永恒的话题,因为很多开发者只能做到“打折扣”的全适配,也就是用手头上的几个手机测试过,某些机型完美,某些机型略有缺陷,总体上马马虎虎过得去,就交工了。

全分辨率适配做的最好的我认为就是易企秀等H5平台,毕竟专业的就是不一样。今天我整理一下他们的最佳实践,当然,他们也会有过时的或者不健全的实践方式,只要我能发现,我定然会指出。

基础知识

首先请访问我的文章《通俗讲解CSS pixels、device pixels、device-width、layout viewport、visual viewport、ideal viewport六个概念》,了解一下基本概念。

另外我参考了https://isux.tencent.com/how-to-make-webpage-fit-screen.html ,不过注意,它并不是说翻页H5的,而是任意H5,所以只有部分内容可以借鉴。

最佳体验

我认为,凡是谈最佳实践,就要先定下最优结果。面向最优结果的实践才可能是最佳实践。那么全分辨率适配的最优结果或者说叫最佳体验是什么呢?

  • 当手机大小不同、视口宽高比例相同,那么两者的体验差别就应该像是放大缩小版的关系一样。思路:利用<meta name="viewport" content="width=device-width, initial-scale=xxxx, maximum-scale=xxxx, user-scalable=no">和背景图的background-position: 50% 50%; background-size: cover; background-origin: content-box;来解决,详细见下文。

  • 当手机大小不同,视口宽高比例也不同,那么除了放大缩小的关系,还有一些区别:比较矮的视口,它的背景图的上下边缘被裁剪的就多一点,比较瘦高的视口,它的背景图的上下边缘被裁剪的就少一点。思路:见下文。

屏幕分辨率的讨论

根据百度流量研究院的统计,安卓端和ios端的分辨率占有率如下:

安卓端

先说安卓,1080x1920的占有率虽然很高而且还在涨,但是720x1280也属于很高的分辨率了,而且手机端屏幕小、像素密度大,所以720x1280的图片显示在1080x1920分辨率下也不会有太大问题,安卓端我们暂时以720x1280为准。

iOS端

再说iOS,1242x2208是iPhone 6S PLUS的分辨率,是目前最高的分辨率,而且它份额也在涨。虽然话是这么说了,也由于手机端屏幕小、像素密度大,所以按照750x1334制图也不会有什么问题的。iOS端我们暂时以750x1334为准。

再对比一下,720x1280比750x1334的数字看起来更容易记,所以就720x1280吧。

以上并不是玄学或者胡乱估算,而是按720x1280作为主流分辨率就确实够用了。

那么问题来了,易企秀以什么为基准分辨率呢?易企秀是基于iPhone 5的640宽度的,因为易企秀毕竟是从iPhone5时代创立的。到今天这个宽度已经不适用了,安卓很少有这个分辨率,iOS虽然有这个分辨率,但是从百度统计来看,是一路走低的。所以,我们坚持我们的720宽度就好了。

Paste_Image.png

视口分辨率的研究

上文虽然说按照720x1280作为主流分辨率,但是又有一个现实就是,视口大小是小于屏幕整体大小的,因为浏览器一般都有地址栏和工具栏,微信还好一点,只有地址栏,但都会占有一些面积。我调查了一些手机的微信视口,如下:

iPhone 6S PLUS的微信浏览器的视口分辨率,是414x672,比例是0.616:1
iPhone 6S是375x603,比例是0.622:1
红米Note 4是360x572,比例是0.63:1
OPPO R7是360x527,比例是0.68:1

到底设什么尺寸作为背景图的标准尺寸才好呢?这需要先了解一下背景图CSS的相关知识。

直接说答案,参考了https://isux.tencent.com/how-to-make-webpage-fit-screen.html之后你就会知道,background-position: 50% 50%; background-size: cover; background-origin: content-box;是翻页H5的背景图的最佳方案。这些代码保证了背景图是从中心点向周围铺开的,而且cover的特点是:考察自身宽高比例与div的宽高比例,照顾其中一者保持相等,然后另一者会在屏幕外溢出。

Paste_Image.png

然后我们看看易企秀又是怎么做的。首先易企秀确实用了上一段的代码,然后我从他们作品的主背景图的尺寸看,他们用的是640x1008的背景图,把640x1008的背景图对应到720宽度是720x1134。这个尺寸是不是科学呢?

720x1134比例是0.635:1,也就是说,背景图在某些视口下是上下溢出,也有一些是左右溢出,上下溢出的概率很大,只有在很瘦的视口下,比如iPhone 6S PLUS里,会有略微的左右溢出。

我们分别分析一下上下被裁剪跟左右被裁剪导致的问题:

  • 上下被裁剪导致的问题主要是浮动元素跟背景图上下错位。这个问题很容易解决,下文有介绍,我们先看左右被裁减。

  • 左右被裁剪也会导致一些问题,就是浮动元素跟背景图比例失调,也就是说,不仅错位,而且比例尺不一致。这个问题就很麻烦,当视口很瘦高,比如iPhone6S PLUS的微信浏览器看页面,背景图会被左右裁剪,这样会导致背景图跟浮动元素无法严格匹配,也就是背景图只露出了中间的一部分,而浮动元素还是全宽显示,这样浮动元素就显得比背景图大,而且某些靠边的浮动元素也会被裁剪。总体说,左右被裁减导致的问题更加严重,上下被裁剪导致的问题很轻。解决左右被裁剪没有根本的办法,只能是不要出现这种情况。

所以结论是:
要么,设计师按照720x1170作为画布面积,把它当做标准网页面积来制图。
要么,设计师按照720x1134作为画布面积,把它当做标准网页面积来制图,导致的某些瘦视口里浮动元素偏大,某些靠边的浮动元素也会被裁剪,这些问题只好忍了。

综上,我建议选用720x1170作为画布面积。以下方案按照720x1170为例。

viewport元数据的写法

最著名的viewport元数据是<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">,然而,如果我们想实现“等比放大缩小”的最佳实践,那么这条最著名的声明其实是不适用的。原因是:

假设我们使用了这个声明,那么iPhone 5的css像素宽度是320px,iPhone6是375px,这时候,假设iPhone 5一行能写20个汉字,那么iPhone 6一行就能写23个汉字,这下就不符合“等比放大缩小”的关系了,大手机的字没见到大,只见到了大手机一行多写了3个字。

那么为什么这条看似不科学的声明还那么流行呢?因为它适用于普通手机网页。翻页H5与普通手机网页有本质区别:

  • 翻页H5要实现等比放大缩小,普通手机网页不需要实现这种效果。
  • 普通手机网页追求的是:字体在各个手机上看起来必须视觉大小一致,不需要管一行写20个字还是23个字。而翻页H5不追求大小一致,追求的是每行统一写20个字,所以大手机的字允许看起来稍大一点,小手机的字允许看着偏小一点。
  • 翻页H5的高度必须是视口的高度,普通手机网页不必,所以普通网页一行写几个字、写几行都随便,翻页H5则不可以这么随便。

所以,翻页H5的viewport的元数据应该怎么声明?易企秀的例子是(iPhone 6 plus下):<meta name="viewport" id="viewport" content="width=320, initial-scale=1.29375, maximum-scale=1.29375, user-scalable=no">,它的原理是:

写死width=320,然后由js动态计算scale。js必须紧贴<meta name="viewport" id="viewport">,保证在body显示之前修改元数据。

    <meta name="viewport" id="viewport" content="width=320, initial-scale=1, maximum-scale=1, user-scalable=no">
    <script>
      var initialscale = document.documentElement.clientWidth / 320;
      document.getElementById('viewport').content = 'width=320, initial-scale=' + initialscale +
        ', maximum-scale=' + initialscale + ', user-scalable=no';
    </script>

页面制作的过程

开发预览环境

开发预览环境可以有多种,通常有三种:

一、上策:可以用PC版网页,预览环境就是PC浏览器,然后配合device.js判断设备类型,这需要你先研究这个js库,用起来很简单。然后加入下方这段代码即可。这个方案可以直接作为PC端和平板端的适配方案。

html.desktop body, html.tablet body {
    margin: 0 auto;
    height: 520px;
}
body {
    height: 100%;
}

你问520px是怎么来的?因为背景图高度是1170px,然后1170 * 320 / 720 = 520px。为什么320x520是理想分辨率?因为我们在这个分辨率下开发,才能保证浮动元素的top、left值是准确的。

二、中策:可以用手机预览。需要给手机hosts文件做配置,指向你的电脑本地服务器的虚拟域名。缺点就是麻烦、调试困难。

三、下策:可以用chrome自带的device mode切换到iPhone 5模式开发,因为iPhone 5的视口宽度就是320px。但是有一个问题是chrome的device mode不可以动态调整高度,而真实世界的浏览器视口高度是多种多样的,尤其是我们应该在320x520的理想分辨率下开发,这就是它是下策的原因。这个方式只可用于测试手机特有的功能,不应该用来测量top和left值。

涉及到设计师的问题

设计师要按照720x1170的画布来设计,但是设计师要注意小视口的可能性。因为一些手机在使用非微信浏览器,也就是浏览器既有地址栏又有工具栏的时候,它视口很矮,另外翻页H5的上方一般有一个音乐播放按钮,下方一般要加一个小箭头,所以设计师要做到“留天留地”,在上方下方不要放主要元素,尤其是不要放LOGO和标题。

我建议主要内容都放在上下居中的720x1000的范围内即可,一定不要越界。

分页的处理

分页的容器的id我命名方式为page1、page2...或者其他规则都可以。

分页里的浮动元素主要有图片和文本段,先覆盖一下样式:

.page {
    position: relative;
    width: 100%;
    height: 100%;
    background-position: 50% 50%;
    background-size: cover;
    background-origin: content-box;
}
    <div class="page" id="page1">
      <div style="position: absolute; top: ...; left: ...;" id="imgbox1-1">浮动元素</div>
      <div style="position: absolute; top: ...; left: ...;" id="txtbox1-1">浮动元素</div>
    </div>

浮动元素的处理

浮动元素定位问题

开发的时候,浮动元素要在父元素里绝对定位,top和left的单位用px。

topleft的值是怎么得来的?

是在上述的三种开发环境下,通过F12 devtools微调,最后调出来的。注意,虽然top和left可以让设计师帮你测量出来,但其实没必要,因为测量出来的值是设备像素,之后你还要换算成我们写css用的css pixels。所以通过F12工具微调,视觉上大致没问题就可以了。

当把开发好的页面用手机预览的时候你会发现图片跟背景图错位了,因为背景图的上下边缘有裁剪,按照裁剪之后的高度来定位浮动图片的话,图片肯定会全部往下错位。怎么办?

解决方案:我们给浮动元素们包裹一个relative属性的父元素,比如叫div.editarea,Emmet表示为div.page>div.editarea>浮动元素们。注意,背景图是设在div.page身上的,不要给.editarea设背景图。然后给这个元素再加一个class叫.editarea-offset,让.editarea-offsettop等于calc((100% - 520px) / 2),它是一个负值,就是被裁减的厚度值,这样浮动元素们的向下的错位就被向上拉动,也就是修正了。

.editarea-offset {
    top: calc((100% - 520px) / 2);
}

什么时候不需要加这个.editarea-offset修正呢?比如,现在有个浮动元素,它内部不含图片,或者它虽然含图片,但不要跟背景图对位,现在我要求它必须占据100%视口高度,且不可溢出,这种情况下就不需要加.editarea-offset

这种情况一般是出现在只包含纯文字且文字很多的元素。这种情况下我们当然希望它尽可能占据最大面积,显示最多的文字,比如我打算在页面顶部放一个大标题,下面放列表,项目有很多,局部滚动。就如:

<div class="xxlist">
<h1>大标题</h1>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
...
</ul>
</div>

现在我想让.xxlist的高度尽可能高,达到100%高度,然后ul也尽量高,局部内容滚动,所以不能写死ul的height值,这时候height的正确姿势是:

ul {
    height: calc(100% - 32px);
}

也就是说,h1的容器高度是32px的话,ul的高度就calc计算一下,就好了。

浮动图片宽高问题

浮动元素的图片都是按照720x1170画布的前提下设计的,所以需要先算出相对于320x520的css像素宽高,然后才能写入代码里。这个运算让sass自己去算就行了。也就是:

  • 先看设计师发过来的图片的宽高,先如实抄到代码里。比如设计师给你的图就是23px的宽度,就抄23px。这个23px是设备像素。下一步我们把设备像素换算成css像素。
  • 比如你的width: 123px这样子的代码,应该写成width: round(123px * 320 / 720),也就是写成round(123px * 4 / 9)。sass编译的时候会自动帮你计算。高度值也是一样处理。

浮动文字的字号和行高问题

字体跟图片的处理是一样的道理,字号单位并不用什么高深的rem,直接用px即可。当然,用rem和em都是可以的。

比如:

.page .txtbox {
  position: absolute;
  font-size: 16px;
  line-height: 1.414;
}

.page p {
  display: inline-block;
  margin: 0;
  padding: 0;
}

#txtbox1-1 {
  top: 380px;
  left: 68px;
}

#txtbox1-1 p {
  font-size: 1em;
  color: #fff;
}

注意,不要给p元素设宽度,因为inline-block就可以保证宽度自适应,而且加动画之后,比如加中心放大的动画,可以确保中心点正确。

本文只为介绍适配,适配大致就是这些内容,至于怎么真正做出一个翻页H5,那就是本文之外的内容了。以后会写。

推荐阅读更多精彩内容