移动端原理和适配方案

22次阅读

共计 3747 个字符,预计需要花费 10 分钟才能阅读完成。

移动端开发不可避免的一个点就是适配问题,由于机型繁多,屏幕尺寸大不相同,以及 retina 屏幕导致一套固定的样式布局无法满足所有的屏幕需求,因此需要解决各种屏幕的适配问题,让页面在所有手机上看起来都合适美观。
到目前为止,在适配问题上经历了几个阶段:

  1. 百分比布局,抛弃 px 尽量用%,对于一些较小的元素和边框来说并不友好,个人认为%比较适合做页面结构划分,不太适合较小元素的大小设置
  2. 媒体查询(@media), 根据屏幕宽度执行不同样式,但是只能按设备宽度区间做大体区分,不够细致,代码繁重
  3. 百分比+媒体查询,通过百分比做 layout 布局,具体元素用媒体查询单独设置,缺点同上
  4. rem 布局,通过 rem 单位,动态设置 html 标签的 fontSize, 目前比较成熟的适配方案,常用的有淘宝适配方案的 flexible, 蚂蚁金服的 ant design mobile
  5. flex 布局,移动端兼容较好

后面会针对 rem 适配具体说明

基本概念

物理像素
又叫设备像素,一个物理像素是屏幕上的最小显示单元,每个像素都有自己的显示颜色和亮度,例如,屏幕上显示的一张 100px*100px 的图片,实际上是由很多个拥有颜色和亮度的像素点组成。

设备独立像素
又叫做密度无关像素、逻辑像素,是由程序可以控制的虚拟像素,我们样式中的 css 像素也是逻辑像素的一种。系统会将逻辑像素转化为设备像素展示。

设备像素比
物理像素与设备像素之间的关系就是设备像素比,dpr = 物理像素/设备独立像素。
可以通过 window.devicePixelRatio 获取设备像素比。

即使知道了基本概念,可能也还是不清楚他们之间到底有什么关系?有怎样的表现?以下通过简单的例子来进行理解。

上图是屏幕尺寸相同,dpr 分别为 1 和 2 的展示效果,最直观的视觉效果就是左侧 dpr= 1 的显示比较模糊粗糙,右侧 dpr= 2 的更加清晰细致,产生区别的原因不是因为右侧的图案比左侧的大,而是在尺寸相同的情况下右侧屏幕为 retina 屏幕,dpr=2,这意味着,当展示一个 100px*100px 大小的图案时,dpr= 1 的屏幕上在 100px*100px 的区域内显示了 100*100 个物理像素点,用一个物理像素显示 1 个逻辑(css)像素,但是在 dpr= 2 的屏幕上却展示了 100*100* 4 个像素点,用 4 个物理像素展示 1 个逻辑(css)像素,所以图案更加清晰细腻。如下图所示:

也可以简单的理解为,在尺寸相同,密度不同的屏幕上展示同等大小的内容,那么密度大的就要用更多的像素去展示。这里的密度指单位面积内的像素点个数,像素点越多,分辨率越大,越清晰。

主流适配方案

目前流行的移动端适配方案分别为蚂蚁金服的 ant-design-mobile 中的高清适配方案和淘宝的 flexible, 但是两种方案的原理是一样的,viewport+rem,这里主要记录两种方案的使用方式,原理在下面分析。

ant-design

阿里蚂蚁金服的 react 组件库,在 antd mobile 中提供移动端高清适配方案,简单介绍下使用使用方式,在创建项目并安装 antd-mobile 后

1. 安装依赖

npm install --save-dev babel-plugin-import less less-loader

2. 修改 webpack 配置
修改配置支持按需引入,加载 antd-mobile 的 less 文件

增加配置,解析编译 less, 引入主题配置,这里的 theme 是 package.json 中的配置项

package.json 中增加 theme 设置项,theme 可以定制组件皮肤颜色,高清方案 hd 需为 2px, 具体参数参看 antd-mobile 官网,这里也有使用方式

3.px 转 rem
antd 里 px 转 rem 方便快捷的方式是通过依赖 postcss-plugin-px2rem,配置后在开发中可以直接写 px 单位,编译后生成 px 单位。
安装依赖:

npm install postcss-plugin-px2rem postcss-loader --save-dev

对.css 文件做解析编译配置,增加 postcss-loader 配置,postcss-loader 的 options 里增加 postcss-plugin-px2rem 相关配置,如下图,具体使用根据自己工程配置方式做变通:

rootValue 默认设置 100,即 1rem = 100px;

flexible

1. 引入 flexible.js 文件
flexible.js 可以下载到本地工程引入,也可以引 cdn 上的远程文件,该文件执行会自动生成 <meta name=’viewport’> 标签,不需要手动写

2. 开发使用
由于会自动生成 meta 标签,并自动设置 html 标签的 font-size 属性,所以只需要按照设计稿写 rem 单位的 css 即可。默认 iphone6 1rem = 75px,其计算方式是 1rem=document.documentElement.clientWidth*dpr/100 = 375*2/100=75px

无轮以上那种方式,在开发模式上可以用同一种,以 iphone6 为标准,UI 出 750*1334(高度不固定)的设计稿,前端开发元素大小同设计图。

px 转 rem 方式

px 转 rem 有几种比较好用的方式

1、不用 sass,less,直接在写 css 的过程中自行计算 rem, 麻烦耗时并且开工作量大,如果以后改变 rem 对 px 的开发标准,那么全部需要重新计算。
2、使用 sass 开发,且不用构建工具,那么可以使用 sass 的混合宏、函数计算 rem;也可以 IDE 安装转换插件。sass 函数如下:

// px rem 转换函数
@function px2rem($px, $base-font-size: 75px) {@if (unitless($px)) {@warn "Assuming #{$px} to be in pixels, attempting to convert it into pixels for you";
    @return px2rem($px + 0px);
  } @else if (unit($px) == rem) {@return $px;}
  @return ($px / $base-font-size) * 1rem;
}

3、使用构建工具,可以 npm 安装 px2rem 插件
antd 推荐:https://github.com/ant-tool/p…
flexible 推荐:https://github.com/songsiqi/p…

适配原理解析

移动端适配的根本在于 rem+viewport

css 单位由 px 转向 rem

这里暂时不考虑 retina 屏幕问题,下面解析

这里说一下 px、em、rem 单位的区别:
1px = 1px
1em = 父元素的 font-size
1rem = html 标签的 font-size

由于 rem 单位的特性,使得以 rem 作为单位的元素在大小等属性上具有相对性,以元素的 width,height 为例,根元素的 font-size 越大,那么元素的宽高越大,反之越小。这就意味着当我们以 iphone6 为基础做 rem 布局:
iphone6

html: font-size = 100px

div:  width = 1rem = 100px 
      height = 1rem = 100px

在 iphone6 plus 上的显示会如下,由于 plus 屏幕较大,html 的 fontSize 属性等比例变大,元素尺寸同样会相应变大,这样就可以达到根据屏幕尺寸不同,页面元素做等比例缩放,达到基本的适配目的。

html 标签的 fontSize 的值可在页面加载的时候通过 js 进行计算, 动态设置设置,计算方式为:
fontSize = 当前屏幕宽度/基础设备宽度*基础设备上约定的 html 标签 fontSize

iphone6 plus

screenWidth: 414px
html: font-size =  414/375*100px = 110.4px

div:  width = 1rem = 110.4px
      height = 1rem = 110.4px

以上根据屏幕尺寸计算 html 的 fontSize 值的方式能够实现的是页面在 iphone6(开发基础稿)的基础上根据屏幕宽度进行简单的等比例缩放,但是却无法解决 retina 屏幕的问题,如果开发中以 iphone6 为基础,那么考虑到其 dpr= 2 的问题,应该用宽度为 750px 的设计稿作为开发稿。

根据 dpr 做页面缩放
上面主要解释 rem 的适配原理,现在来解释 dpr 的问题。

如果忽略了 dpr 的不同,会有什么样的问题呢?

最主要的问题就是展示同样的大小的内容,在 dpr 越大的屏幕上页面元素内容会越虚,尤其是图片和 1px border 的问题。
原因是上面提到的 dpr 越大,一个逻辑像素对应的物理像素就越多,图片也会越清除细腻,反之越粗糙模糊。之所以会虚是因为展示 100px*100px 的图片,dpr= 1 的屏幕一个物理像素展示一个逻辑像素;dpr= 2 的屏幕四个物理像素展示 1 个逻辑像素,四个物理像素如何展示一个逻辑像素呢,系统在计算的时候,会把一个逻辑像素补充为 4 个色值,透明度等近似的逻辑像素点,这样图片展示就会显得虚。

移动开发 retian 屏幕常见问题

疑问思考

1.antd iphone6 1rem = 100px 6p 1rem=150rem 设置 width:7.5rem,6 上宽度 100%,6p 上无法显示宽度 100%,

正文完
 0