也谈多终端屏幕适配

写在前面

在移动网民规模不断扩大的今天,手机、平板等移动设备俨然已成了网民主要上网终端。迎着这个势头,咱们这些前端汪们也接下了很多的移动web页面开发需求。当在感叹终于不须要兼容pc端低端浏览器时却面临了移动多终端屏幕适配这一问题。css

本人经验尚浅,在大牛们得出的数种适配方案的基础上也来谈谈这一问题。 //实际上是入职前太颓废了,找点事作html

因为本文目的不在于普及基础,因此移动端相关概念(viewportcss像素,独立像素,物理像素,dprdpippi)的阐明再也不赘述。前端

能够参考:android

还没有有时间研究原理的同行们,能够跳过这些直接看下面的解决方案。github

这里是以前记录的以 iPhone 6 例子的一个总结:web

clipboard.png

何为多终端适配?viewport 有多重要?

多终端适配即便某一套网页方案能完美地展现在不一样操做系统、尺寸、分辨率、dpr的设备上。适配的缘由相比也不用多说了——就是为了使网站各终端的用户都不流失。浏览器

来看看浏览器产商为咱们提供的最原始的解决方案。app

在iphone诞生前,为了留住移动端用户,手机浏览器尝试经过调整内容来适应网页,取得了不一样程度的成功。

iphone上的safari没有作丝毫的尝试,取而代之的是在各类各样的虚拟窗口上展现网页,这些虚拟窗口被称为“视图”。用户能够经过放大来查看网页的部份内容或缩小来查看网页的所有内容。为了给开发者提供必定程度的展示页面的控制权,苹果公司提供了viewportmeta元素,它能够指定虚拟窗口的大小。
——《HTML5触摸界面设计与开发》

iphone的viewport(视口)默认大小为980px。意味着会使得在pc端显示为980px的网页以必定比例缩小(浏览器会替咱们完成这一工做)成刚好能够容纳在4.7英寸(以iphone6为例)屏幕内。这样一来,整个网页缩小得咱们不容易直接观测到里面的信息,必须经过手势放大页面获取。

如图,这个页面我没设置viewport,设计稿基于iphone6,因此页面内容宽度定为750px。很明显看出左右两旁的空白,即宽度为达到视口宽980px所产生的。

clipboard.png

so——构建移动页面时,设置合理的viewport值是首要任务。

那么什么是合理的viewport值呢?其实每一个浏览器的viewport都不尽相同:

  • Safari iPhone:980px

  • Opera:850px

  • Android WebKit:800px

  • IE:974px

面对众多的默认viewport,使其统一为一个值是业界的广泛作法。常见的设置有:

<meta name="viewport" content="target-densitydpi=device-dpi,width=设计稿尺寸,initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5,user-scalable=no" />
<meta name="viewport" content="target-densitydpi=device-dpi,width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />

因此通常来讲,viewport的宽度会设定为device-width(设备宽度,与css逻辑像素同等大小,可经过document.documentElement.clientWidth获取)或者为设计稿尺寸(好比设计稿基于iphone6,width=750;基于ip5,width=640)。

这里须要注意:initial-scale=0.5,maximum-scale=0.5,minimum-scale=0.5 这几个缩放数值一般是经过ua检测,再经过js自动设置的。通常不会固定为1或者某一特定数值。但也有特殊状况。稍后讨论。

解决方案

前提

设计师给出的视觉稿应该严格按照某一移动设备的屏幕物理像素制定宽度,高度视页面内容而定。业界通常是基于iphone5或者6给出相应尺寸。因此最多见的视觉稿有750px、640px的。而1080px的大可能是基于6plus的。而其余的奇葩尺寸真心不建议了。因此应事先约定好。

对于多倍图处理能够看看 @南宮瑞揚 翻译的这张图:

clipboard.png

1、自适应适配方案

一、使用场景

布局简单,主要内容以列表形式展现:条目内容垂直分布。定位元素少,且不为主要内容元素。如知乎美团网微博通常结构为:

  • 顶栏:搜索框或网站logo等信息

  • banner

  • 横向导航:通常为若干个平分水平空间的tap

  • 内容:含有标题和描述或还包含略所图

二、解决方案

a.设置viewport:

<meta name="viewport" content="target-densitydpi=device-dpi,width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />;

b.水平方向宽度自适应,垂直方向高度固定

若元素无其余平分空间的兄弟元素,宽度可定为设计稿元素宽度/设计稿宽度*100%;如有宽度定为100%/平分空间元素个数,也能够用flex的方式定义;

c.小块的元素(如logo,装饰性图片)宽高都固定;

d.注意图片在retina屏幕下应使用多倍图,但仍以1倍图的大小肯定图片的宽高。如果sprite图,可设background-size: x1图片宽 auto;background-position: 以x1 sprite图片定义

三、弊端

元素高度和图片大小以同一个尺寸在多种不一样尺寸的设备下显示,没达到真正适配效果。没法适应结构复杂的页面布局。

2、固定viewport为设计稿大小

一、使用场景

页面只考虑移动设备,不考虑自适应,不须要作响应式布局。非h5专题活动页。如网易新闻、我以前作过的一个团购网站cocolife也用的是这种方式

二、解决方案

a.设置viewport

<meta name="viewport" content="target-densitydpi=device-dpi,width=设计稿宽度,user-scalable=no" />

或经过js写入meta

var scale= parseInt(window.screen.width)/设计稿宽度;
document.write('<meta name="viewport" content="width=设计稿宽度, initial-scale = '+scale+', maximum-scale = '+scale+', maximum-scale = '+scale+', target-densitydpi=device-dpi">');
}

注意这里的设计稿是指初始的设计稿大小。通常以iphone6:750px;iphone5:640px定宽。

b.页面全部元素的宽高都按设计稿元素自己大小直接定义。

三、弊端

乍眼看上去这种方法挺好的,所有按设计稿给出的元素大小写成固定px值,不须要各类单位转换。所看即所得,缩放交给浏览器,彻底按视觉稿切图。但,为何没有获得普片推广呢?

第一点是再也不支持响应式布局。好比咱们定义的`@media
(min-width:320px)`这里的width实际上指的是viewport的宽度值,而咱们的viewport已经固定成统一宽度了(如640px),因此,不管在哪一个尺寸的屏幕下,这句媒体查询也再也不起做用了。
第二点是这种方式会让浏览器去缩放,那么就可能会形成字体模糊,图像失真。1px border在 不一样分辨率下的显示也会有所不一样。
第三点是若是页面要嵌入到App中时,App是以webview的形式渲染页面的。webview实际上也是webkit内核,而最新的webkit内核对定宽支持不是很好,默认是以device-width来渲染的。
第四点是可能存在缩放失效的问题,某些安卓机不能正常的根据 meta 标签中 width 的值来缩放 viewport,须要配合 initial-scale(即上述js方式) 。

3、淘宝的作法

一、使用场景

广泛网站均可以采用这种方式。但不包括h5专题活动页。

二、解决方案

这里首先推荐大漠前辈的一篇文章使用Flexible实现手淘H5页面的终端适配

淘宝作法的原理相信你们可能比较熟悉。简单地说就是动态设置html下的font-size值,而后为页面的元素采用rem的方式制定宽高。

咱们知道rem的占据像素值是由根元素的font-size值大小决定的。打个比方,若html下设置了font-size:16px;那么1rem就至关于16px

淘宝的方案大体以下:

clipboard.png

把页面分红10等份,若视觉稿初始宽度为750px,那么每份大小为75px,将值给予font-size,那么1rem=75px。加上初始的缩放值

clipboard.png

使得宽度为10rem的盒子正好容纳在iphone6视口(375px)上。若此时视口的大小变成320px,那么js就会将htmlfont-size值动态改变为64px

来看看js是怎么动态改变font-size

//UA检测
var isAndroid = win.navigator.appVersion.match(/android/gi),
    isIPhone = win.navigator.appVersion.match(/iphone/gi);

//对ios设备的dpr进行判断,安卓统一设定为1
var dpr= isIPhone ? Math.min(win.devicePixelRatio, 3) : 1;
    scale = 1 / dpr;
    
var docEl = document.documentElement;
var metaEl = doc.createElement('meta');

//设定dpr和meta
docEl.dataset.dpr = dpr;
metaEl.setAttribute('name', 'viewport');
metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
docEl.documentElement.firstElementChild.appendChild(metaEl);

//动态设定根元素下的font-size大小
var width = docEl.getBoundingClientRect().width;
//pc等大屏幕下
if (width / dpr > 540) {
     width = 540 * dpr;
}
//将页面分为10等份,易得出750px视觉稿下根元素font-size为75px
var rem = width / 10;
docEl.style.fontSize = rem + 'px';

上面的js粗略地描述了一下淘宝的方案。即将font-size值设置成docWidth(视觉稿大小)/10,那么1rem大小同为docWidth/10。因此页面里的元素宽高为width/(docWidth/10)

举个栗子:

若咱们拿到一个基于iphone6的视觉稿,对其运用该种方式进行适配。因为iphone6视觉稿宽度为750px,那么只须要将视觉稿上的元素大小初始宽高/75写入css。

如宽度为750pxwrap,则width=10rem;宽度为375pxarticle,则width=5rem
scss$ppr(pixel per rem) 变量写法:$ppr: 750px/10/1rem
元素尺寸写法:html { font-size: $ppr*1rem; } body { width: 750px/$ppr; }

4、专题活动 h5

一、使用场景

针对专题活动的滑屏h5页面,特色是主题内容图片居多,而且基本采用绝对定位方式。

二、解决方案

原理:给每屏下的主要内容加一个container包裹元素,并设置margin: 0 auto使其水平居中。(保证内容在视线中央)使用jscontainer总体进行transform:scale()缩放,scale值根据屏幕窗口大小动态设置。

2.1 推荐一个框架以快速搭建适配的h5:pageResponsive

2.2 不使用框架的具体作法:

a.设定viewport

<meta name="viewport" content="target-densitydpi=device-dpi,width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no" />;

b.页面结构

通常为

<ul>
    /*---第一屏---*/
    <li><div class="container"><div><li>
    /*---第二屏---*/
    <li><div class="container"><div><li>
    /*---第三屏---*/
    <li><div class="container"><div><li>
    ...
<ul>

通常来讲h5有contain和cover两种适配模式。

contain即将页面固定在一个特定大小的盒子中。背景通常以与h5背景颜色相近的纯色替代。像这样:

clipboard.png

cover即将h5每一屏的背景或者从紧贴边缘的图像经过调整background-size使之刚好容纳在窗口中。像这样:

clipboard.png

下面说说两种模式的h5写法(默认遵循上述的html结构):

contain:

对于每一屏下背景或者从边缘开始显示的大图定义在li下,采用background-size:100% 图像高度的方式。

cover:

把全部元素放置在.container下统一进行缩放。背景定义在.container下。同时给.container设置固定的宽高,通常320*520的居多。

c.进行动态缩放的js

// 响应式缩放
var autoScale = function() {
var ratio = 320/508,
    winW = document.documentElement.clientWidth,
    winH = document.documentElement.clientHeight,
    ratio2 = winW/winH,
    scale;
//判断宽和高以哪一个为缩放基准    
if (ratio < ratio2) {
        scale = (winH/508).toString().substring(0, 6);
    } else {
        scale = (winW/320).toString().substring(0, 6);
    }
var cssText = '-webkit-transform: scale('+ scale +'); -webkit-transform-origin:top center; opacity:1;';
$(".container").attr('style', cssText);

};

//这里使用setTimeout是因为获取文档宽高时有时候不能马上获得,形成缩放失效
setTimeout(function() {
    if (document.documentElement.clientWidth/document.documentElement.clientHeight !== 320/508) {
        autoScale();
    } else {
        $('.container').css({'opacity': 1});
    }
}, 300);

总结

经过上述分析,得出如下总结供你们对适配方案进行选择。

拿到视觉稿
      ↓
判断布局是哪一种类型
      ↓
1.内容少,绝对定位图片少,布局简单,通常为上下结构
      ↓
是否须要适配PC?
是 → 自适应方式  
否 → 自适应、rem、viewport方式
      ↓
是否要嵌入APP或运用响应式布局?
是 → 自适应、rem方式
否 → 自适应、rem、viewport方式  //推荐使用自适应方式

2.内容适中,绝对定位元素少
      ↓
是否要嵌入APP或运用响应式布局?
      ↓
是 → rem方式
否 → rem方式或viewport方式  //推荐使用rem方式

3.整屏专题H5;绝对定位元素多  
      ↓
是否须要适配PC?
      ↓
是 → H5专题页面的cover方式
否 → H5专题页面的contain方式

^^感谢阅读!

相关文章
相关标签/搜索