谈谈移动端屏幕适配的几种方法

移动端web开发相对于PC端web开发,我们可以庆幸不用兼容那么多浏览器了,但是随之而来的却是各种屏幕尺寸的适配,个人觉得,比PC端还要费精力。在使用了腾讯优测进行软件测试后,问题得到了有效解决。


响应式布局

简而言之,就是页面元素的位置随着屏幕尺寸的变化而变化,通常会用百分比来定位,而在设计上需要预留一些可被“压缩”的空间。


如上图,其实就相当于页面被压矮了。

Cover布局

就跟background-size的cover属性一样,保持页面的宽高比,取宽或高之中的较小者占满屏幕,超出的内容会被隐藏。此布局适用于主要内容集中在中部,边沿无重要内容的设计。

如上图,第一张是原设计稿,第二张把左右隐藏掉了一部分,第三张则是把上下隐藏掉了一部分。


Contain布局

同样,也跟background-size的contain属性那样,保持页面的宽高比,取宽或高之中的较大者占满屏幕,不足的部分会用背景填充。个人比较推荐用这种方式,但在设计上需要背景为单色,或者是可平铺的背景。


如上图,红框部分为原始宽高比,根据不同屏幕尺寸进行缩放,并加背景填充。

好了,接下来再说说常用的实现方法吧。

样式缩放

最省事的适配方法,直接用px为单位按视觉进行开发,然后通过计算屏幕与网页的宽高比,用transform:scale来对网页进行全局缩放。

不过此方法会有一个小问题,就是如果网页内有动画的话,缩放后会稍微降低页面性能,在低配的安卓机器上表现的比较明显,iOS上没发现有性能问题。

Rem缩放

Rem是个好东西呀,谁用谁知道,这里就不多做解释了。原理跟上面的样式缩放相通,只不过是通过Rem为单位来进行视觉开发,然后通过计算后改变html的front-size来对页面进行缩放。

关于以Rem为单位进行开发,目前比较流行Font-size=62.5%,而后1rem=10px的这种方法,有试过直接换成px也是可以的,就看个人的计算习惯吧。


在网上搜了一下,很多面试都会被问到移动端适配方法的问题,最近看了一些文章,这里总结一下。

首先,谈一下目前为止出现的一些关于移动端适配的技术方案:

    1通过媒体查询的方式即CSS3的meida queries
    2以天猫首页为代表的 flex 弹性布局
    3以淘宝首页为代表的 rem+viewport缩放
    4rem 方式

1.Media Queries

meida queries 的方式可以说是我早期采用的布局方式,它主要是通过查询设备的宽度来执行不同的 css 代码,最终达到界面的配置。核心语法是:

@media screen and (max-width: 600px) { /*当屏幕尺寸小于600px时应用下面的CSS样式*/
  /*你的css代码*/
}

优点


media query可以做到设备像素比的判断,方法简单,成本低,特别是对移动和PC维护同一套代码的时候。目前像Bootstrap等框架使用这种方式布局

图片便于修改,只需修改css文件

调整屏幕宽度的时候不用刷新页面即可响应式展示

缺点


代码量比较大,维护不方便

为了兼顾大屏幕或高清设备,会造成其他设备资源浪费,特别是加载图片资源

为了兼顾移动端和PC端各自响应式的展示效果,难免会损失各自特有的交互方式

2.Flex弹性布局

以天猫的实现方式进行说明:


它的viewport是固定的:

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

高度定死,宽度自适应,元素都采用 px 做单位。

随着屏幕宽度变化,页面也会跟着变化,效果就和PC页面的流体布局差不多,在哪个宽度需要调整的时候使用响应式布局调调就行(比如网易新闻),这样就实现了『适配』。

高度定死,宽度自适应,元素都采用 px 做单位。

随着屏幕宽度变化,页面也会跟着变化,效果就和PC页面的流体布局差不多,在哪个宽度需要调整的时候使用响应式布局调调就行(比如网易新闻),这样就实现了『适配』。

PSrem 
rem是CSS3新增的一个相对单位root em根em),这个单位引起了广泛关注这个单位与em有什么区别呢
区别在于使用rem为元素设定字体大小时仍然是相对大小但相对的只是HTML根元素这个单位可谓集相对大小和绝对
大小的优点于一身通过它既可以做到只修改根元素就成比例地调整所有字体大小又可以避免字体大小逐层复合的连锁
反应目前除了IE8及更早版本外所有浏览器均已支持rem对于不支持它的浏览器应对方法也很简单就是多写一
个绝对单位的声明这些浏览器会忽略用rem设定的字体大小比如p{font-size:14px;font-size:0.875rem;}
(推荐一个单位转换的工具http://pxtoem.com/)

实现原理

根据rem将页面放大dpr倍, 然后viewport设置为1/dpr.


如iphone6 plus的dpr为3, 则页面整体放大3倍, 1px(css单位)在plus下默认为3px(物理像素)

然后viewport设置为1/3, 这样页面整体缩回原始大小. 从而实现高清。

这样整个网页在设备内显示时的页面宽度就会等于设备逻辑像素大小,也就是device-width。

这个device-width的计算公式为:设备的物理分辨率/(devicePixelRatio * scale),

在scale为1的情况下,device-width = 设备的物理分辨率/devicePixelRatio 。

4、rem实现

比如说“魅族”移动端的实现方式,viewport也是固定的:

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

通过以下代码来控制rem基准值(设计稿以720px宽度量取实际尺寸)

!function (d) {
    var c = d.document;
    var a = c.documentElement;
    var b = d.devicePixelRatio;
    var f;
    function e() {
      var h = a.getBoundingClientRect().width, g;
      if (b === 1) {
        h = 720
      if(h>720) h = 720;//设置基准值的极限值
      g = h / 7.2;
      a.style.fontSize = g + "px"
    if (b > 2) {
      b = 3
    } else {
      if (b > 1) {
        b = 2
      } else {
        b = 1
    a.setAttribute("data-dpr", b);
    d.addEventListener("resize", function () {
      clearTimeout(f);
      f = setTimeout(e, 200)
    }, false);
  }(window);

css 通过 sass 预编译,设置量取的 px 值转化 rem 的变量 $px: (1/100)+rem;

1像素边框高清

1.淘宝实现方式
上面说到的淘宝的实现方式即 rem + viewport 缩放 来实现。

transform: scale(0.5)

CSS 代码:

div{
    width: 1px;
    height: 100%;
    display: block;
    border-left: 1px solid #e5e5e5;
    -webkit-transform: scale(.5);
    transform: scaleX(.5);

缺点:

圆角无法实现,实现4条边框比较麻烦,并且只能单独实现,如果嵌套,会对包含的效果产生不想要的效果,所以此方案配合:after和before独立使用较多。

box-shadow

实现方法:
利用CSS对阴影处理的方式实现0.5px的效果。

-webkit-box-shadow:0 1px 1px -1px rgba(0, 0, 0, 0.5);

优点:


基本所有场景都能满足,包含圆角的button,单条,多条线。


缺点:


颜色不好处理, 黑色 rgba(0,0,0,1) 最深的情况了。有阴影出现,不好用。

大量使用box-shadow可能会导致性能瓶颈。

四条边框实现效果不理想。


2.图片实现


使用 background-image 实现1px有两种方式: 渐变 linear-gradient 或直接使用图片(base64)。


渐变 linear-gradient (50%有颜色,50%透明)


单条线:

div{
    height: 1px;
    background-image:-webkit-linear-gradient(top,transparent 50%,#000 50%);
    background-position: top left;
    background-repeat: no-repeat;
    background-size: 100% 1px;

多线条:

div{
    background-image: -webkit-linear-gradient(top,transparent 50%,#000 50%),
    -webkit-linear-gradient(bottom, transparent 50%, #000 50%),