开发 - 移动端页面适配

移动端适配的基础知识和常见用例

viewport 视口

视口可以细分为:视觉视口(visual viewport)和布局视口(layout viewport)

视觉视口

视觉视口是页面的可视区域,相当于一个设置了overflow:hidden属性的 div 元素,这是由硬件决定的,不受缩放的影响。

布局视口

布局视口的尺寸是内容的初始尺寸,设置 viewport meta 的 width 属性其实就是在设置布局视口的初始尺寸。

如果想在不同尺寸的视觉视口中保持同样的分辨率,那么就需要设置布局视口的宽度。

举个例子,页面中有一张原尺寸 1690px 宽的图片,此时如果设置 viewport 的宽度为 800px:

<meta name="viewport" content="width=800, initial-scale=1">

显示效果如下图,html 的宽度既不是 375px 也不是 1690px,而是在 viewport 中设置的 800px,因为图片设置了 100% 的宽度,所以图片的宽度也是 800px,视觉视口并不能完全的显示出布局视口。

如果将 viewport 的宽度设置成小于页面宽度的值,会有什么结果?

<meta name="viewport" content="width=300, initial-scale=1">

效果如下图,宽度设置没有生效,html 使用的是视觉视口的宽度

现在为移动端开发的页面,通常将 viewport 的宽度设置为device-width(设备宽度),即让布局视口宽度与视觉视口宽度相等,这样就不会出现缩放和横向滚动条的问题

缩放属性

与缩放有关的值有 4 个:

inital-scale:初始缩放比例

maximum-scale:允许用户缩放到的最大比例

minimum-scale:允许用户缩放到的最小比例

user-scalable:用户是否可以手动缩放

meta 属性

meta 有些列属性:

viewport 视口

具体配置见上面的 viewport 视口部分,移动端常用 viewport 配置:

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

charset 字符编码

常用的编码为 utf-8

<meta charset="utf-8" />

cache-control 缓存策略

cache-control 的可选值:

  • no-store:不缓存数据到本地
  • no-cache:在提供给本地读取之前,强制要求缓存把请求提交给原始服务器进行验证(协商缓存)
  • max-age:最大可缓存时间

x-ua-compatible 浏览器版本

常用配置:加入客户端安装了 Chrome Frame,则在 IE 中使用 chrome 的渲染引擎来渲染页面,如果没有安装,则使用最高的 IE 版本模式来进行渲染

<meta http-equiv="x-ua-compatible" content="IE=Edge, chrome=1" />

seo 属性

  • author 作者

    <meta name="author" content="something" />
    
  • keywords 关键字

    <meta name="keywords" content="something" />
    
  • description 描述

    <meta name="description" content="something" />
    

format-detection 格式检测

telephone 电话识别

safari 浏览器会将疑似电话号码的数字处理为电话链接,比如:

  • 7位数字,形如:1234567
  • 带括号及加号的数字,形如:(+86)123456789
  • 双连接线的数字,形如:00-00-00111
  • 11位数字,形如:13800138000

如果需要关闭电话识别,则需要下述配置:

<meta name="format-detection" content="telephone=no" />

email 邮箱地址识别

安卓浏览器会将疑似邮箱地址转换为邮箱链接,如果需要关闭邮箱识别,则需要下述配置:

<meta name="format-detection" content="email=no" />

高 DPR 适配

对于高分屏,例如 Retina 屏幕这样 DRP 大于 1 的屏幕,1位图像素不在对应 1 物理像素,而是使用 4 个及以上的物理像素去模拟 1 位图像素,如下图所示:

不过者也会造成一个问题:将尺寸为 80px 的图片宽度设置为 80px,那么此时 1位图像素对应 1 物理像素,DRP = 2 的高分屏中,位图像素无法在继续分解,那就只能用 4 个物理像素去模拟 1 个位图像素,模拟的方式就是就近取色,这会导致图片有一定的色差,看起来变得模糊

解决方法就是:将图片的尺寸拓展成 80px*DRP,这样每一个位图像素都会有对应的物理像素,图片就会变得清晰。

img 解决方案

通过设置 srcset 属性配置显示的图片:

<img srcset="elva-fairy-320w.png,
             elva-fairy-480w.png 1.5x,
             elva-fairy-640w.png 2x"
src="elva-fairy-640w.png"/>

background 解决方案

通过媒体查询页面的 DRP 来决定显示的图片:

@mixin bg-image($url,$extension:'.png'){
    @media (min-device-pixel-ratio:2){
        background-image:url( $url + "@2x" + $extension )
    }
    @media (min-device-pixel-ratio:3){
        background-image:url( $url + "@3x" + $extension )
    }
}

阻止移动端双击缩放

添加下述属性:

touch-action: manipulation;

视口高度去除底部栏

当使用 height: 100vh 去设置页面高度时,往往会出现如下图所示的将导航栏算入 viewport height 的情况,而我们实际需要的是右侧的结果。

这时候就需要去修改 body 的高度属性,将height:100vh修改为height:fill-available,移动端除了 Opera 其他浏览器基本已经兼容了该属性,具体兼容情况

Safari

避免 safari 弹性效果遮挡 fixed 定位的元素

解决方式:给 html 标签设置overflow:hidden,给 body 标签设置overflow:auto

html {
    overflow: hidden;
}

body {
    overflow: auto;
}

border-radius 在 safari 上的失效问题

如果元素设置了 border-radius 属性且设置了 transform 属性,那么 border-radius 就会失效,解决方法是:给父元素加上 transform:translateX(0) 属性。

:active 状态失效

safari 中为按钮元素添加 :active 默认是不会生效的,只有在按钮元素绑定 touchstart 事件时才能激活 :active 状态,只需要给 touchstart 绑定一个空事件即可。

根据设备宽度计算全局字体

在引入全局css样式之前调用下述代码,通过设置 defaultFontSize 来定义 375 宽度下字体的大小,其他宽度的设备会以 defaultFontSize 和 375 宽度作为标准,动态改变全局字体大小。

(function (doc, win) {
  var defaultFontSize = 20;
  var docEl = doc.documentElement,
    resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
    recalc = function () {
      var clientWidth = docEl.clientWidth;
      if (!clientWidth) return;
      docEl.style.fontSize = defaultFontSize * (clientWidth / 375) + 'px';
    };
  recalc(); 
  if (!doc.addEventListener) return;
  win.addEventListener(resizeEvt, recalc, false);
})(document, window);

判断当前浏览器/机型

navigator.userAgent 能获取到当前浏览器的 user agent 字符串

判断是否为微信浏览器

const ua = navigator.userAgent.toLowerCase();
const isWeixin = /micromessenger/i.test(ua);

判断是否为安卓

const ua = navigator.userAgent.toLowerCase();
const isAndroid = /android/i.test(ua);

判断是否为iOS

const ua = navigator.userAgent.toLowerCase();
const isIOS = /(iPhone|iPod|iPad);?/i.test(ua);

开发 - 移动端页面适配

https://hashencode.github.io/post/98cf4503/

作者

BiteByte

发布于

2020-09-15

更新于

2024-01-11

许可协议