移动端适配浅析

1 前置知识

1.1 屏幕尺寸

屏幕尺寸指的是以屏幕对角线长度来计算的,单位是英寸,1英寸 = 2.54厘米。如:iphone6 Plus 屏幕尺寸5.5英寸(2.7*4.8)

1.2 像素pixel

从计算机技术的角度来解释,像素是硬件和软件所能控制的最小单位.
它指显示屏的画面上表示出来的最小单位,不是图画上的最小单位。一幅图像通常包含成千上万个像素,每个像素都有自己的颜色信息,它们紧密地组合在一起。
一个像素,就是一个点,或者说是一个很小的正方形。
像素单位有设备像素、逻辑像素、CSS 像素 3 种。

1.3 屏幕分辨率

屏幕分辨率指一个屏幕具体由多少个像素点组成,单位是px

1.4 物理像素(设备像素)

设备像素(device pixels)也叫物理像素,指的是显示器上的真实像素,每个像素的大小是屏幕固有的属性,屏幕出厂以后就不会再改变。

1.5 逻辑像素(设备独立像素)

设备独立像素(device independent pixels)是操作系统定义的一种像素单位,应用程序将设备独立像素告诉操作系统,操作系统再将设备独立像素转化为设备像素,从而控制屏幕上真正的物理像素点。

1.6 每英寸像素点ppi

ppi(pixel per inch) 表示每英寸所包含的像素点数目,数值越高,说明屏幕能以更高密度显示图像。

它的计算公式为:PPI=√(X^2+Y^2)/ Z (X:长度像素数;Y:宽度像素数;Z:屏幕大小)

ppi在120-160之间的手机被归为低密度手机,160-240被归为中密度,240-320被归为高密度,320以上被归为超高密度
如:iPhone6p为401ppiiphone6为326ppi

1.7 设备dpr

dpr(device pixel ratio) 表示设备像素比,设备像素/设备独立像素,代表设备独立像素到设备像素的转换关系,在JS中可以通过 window.devicePixelRatio 获取

计算公式为:DPR = 物理像素/逻辑像素

css像素

CSS中使用的 px 都是指 css 像素,比如 width: 128pxcss 像素的大小是很容易变化的,当我们缩放页面的时候,元素的 css 像素数量不会改变,改变的只是每个 css像素的大小。

1.8 概念关系图

屏幕尺寸、屏幕分辨率–>对角线分辨率/屏幕尺寸–>屏幕像素密度PPI | 设备像素比dpr = 物理像素 / 设备独立像素dip(dp) | viewport: scale | CSS像素px

1.3 视口viewport

viewport 表示浏览器的可视区域,也就是浏览器中用来显示网页的那部分区域。存在三种 viewport分别为 layout viewportvisual viewport 以及 ideal viewport

  • layout viewport:布局视口

  • visual viewport:视觉视口

  • ideal viewport:理想视口

2 移动端适配方案

2.1 rem适配

rem(font size of the root element)是CSS3新增的一个相对单位,是指相对于根元素的字体大小的单位。
使用rem模拟vw特性适配多种屏幕尺寸

// toRem.js
export default function() {
 const root = document.documentElement;
 /** 以iPhone6为例:布局视口为375px,我们把它分成10份,则1rem = 37.5px,
  * 这时UI给定一个元素的宽为375px(设备独立像素),
  * 我们只需要将它设置为375 / 37.5 = 10rem。
 */
 const scale = root.clientWidth / 10
 root.style.fontSize = scale + 'px'  
}

// main.js
import Vue from 'vue'
import App from './App.vue'
import toRem from "./utils/toRem" //
toRem()
window.addEventListener('resize', toRem)
Vue.config.productionTip = false

new Vue({
 render: h => h(App),
}).$mount('#app')

由于实际开发中计算rem比较麻烦,可以借助less文件计算,然后将@rem配置成less全局变量

/*rem.less*/
@device-width: 375; /*设备布局视口*/
@rem: (@device-width/10rem);

viewport单位得到众多浏览器兼容,lib-flexible这个过渡方案已经可以放弃使用。

2.2 vw\vh适配

vw(Viewport Width)vh(Viewport Height)是基于视图窗口的单位,是css3中提出来的,基于视图窗口的单位。

vhvw方案即将视觉视口宽度 window.innerWidth和视觉视口高度 window.innerHeight 等分为 100 份

上面的flexible方案就是模仿这种方案,因为早些时候vw还没有得到很好的兼容。

  • vw(Viewport's width)1vw等于视觉视口的1%
  • vh(Viewport's height) :1vh为视觉视口高度的1%
  • vmin : vwvh 中的较小值
  • vmax : 选取 vwvh 中的较大值
设置meta标签
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
px自动转换vw
  • 安装插件 + webpack配置
  npm install postcss-px-to-viewport --save-dev
module.exports = {
  plugins: {
    // ...
    'postcss-px-to-viewport': {
      // options
      unitToConvert: 'px',    // 需要转换的单位,默认为"px"
      viewportWidth: 750,     // 设计稿的视窗宽度
      unitPrecision: 5,       // 单位转换后保留的精度
      propList: ['*', '!font-size'],        // 能转化为 vw 的属性列表
      viewportUnit: 'vw',     // 希望使用的视窗单位
      fontViewportUnit: 'vw', // 字体使用的视窗单位
      selectorBlackList: [],  // 需要忽略的 CSS 选择器,不会转为视窗单位,使用原有的 px 等单位
      minPixelValue: 1,       // 设置最小的转换数值,如果为 1 的话,只有大于 1 的值会被转换
      mediaQuery: false,      // 媒体查询里的单位是否需要转换单位
      replace: true,          // 是否直接更换属性值,而不添加备用属性
      exclude: undefined,     // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
      include: /\/src\//,     // 如果设置了include,那将只有匹配到的文件才会被转换
      landscape: false,       // 是否添加根据 landscapeWidth 生成的媒体查询条件
      landscapeUnit: 'vw',    // 横屏时使用的单位
      landscapeWidth: 1125,   // 横屏时使用的视窗宽度
    },
  },
};
  • less文件配置
    同样算的过程交给less,直接按照设计稿去开发
// 还是rem.less 我们加一个@vw变量
@device-width: 375;
@rem: (@device-width/10rem);
@vw: (100vw/@device-width);

2.3 viewport + px

这个方案可以不用关注屏幕尺寸差异,直接按照设计稿上的标注进行开发,也无需单位换算,直接用px

在 HTML 的 head 标签里加入 <meta name="viewport" content="width={设计稿宽度}, initial-scale={屏幕逻辑像素宽度/设计稿宽度}" >

export function initViewport() {
  const width = 375;  // 设计稿宽度
  const scale = window.innerWidth / width
  let meta = document.querySelector('meta[name=viewport]')
  let content = `width=${width}, init-scale=${scale}, user-scalable=no`
  if(!meta) {
      meta = document.createElement('meta')
      meta.setAttribute('name', 'viewport')
      document.head.appendChild(meta)
  }
  meta.setAttribute('content', content)
}

3 开发案例分析

3.1 项目适配方案(含折叠屏适配)

采用flexible+改造方案

  • 适配方案
    浏览器如何简单模拟nex机型
    设置模拟机型,宽度为639,高度为616,dpr为3

  • 拉伸处理方案
    修改项目flexible.js文件;
    原理:通过对屏幕宽高比来判断,设置rootFontSize

  • 单独处理
    在具体需要处理的元素添加媒体查询来单独处理

@media screen and (min-device-aspect-ratio: ~"4/5")
(function(win, document) {
  var documentEl = document.documentElement
  var maxwidth = 540
  var dpr = devicePixelRatio === 4 ? 1 : devicePixelRatio
  var tid = null
  documentEl.dataset.dpr = dpr
  var designScale = (documentEl.dataset.width || 1080) / 100
  var rootFontSize = parseFloat(getComputedStyle(documentEl).fontSize)
  var screenWidth = win.screen.width
  var screenHeight = win.screen.height
  var isVivoBrowser = /vivoBrowser/i.test(window.navigator.userAgent)
  if (isVivoBrowser) {
    rootFontSize = 16 // vivo浏览器会影响字体大小,必须设置为16
  }
  var refreshRem = function() {
    var width = documentEl.clientWidth
    var screenWidth = win.screen.width
    var screenHeight = win.screen.height
    if (width / dpr > maxwidth) {
      width = maxwidth * 1
    }
    if (screenWidth / screenHeight < 0.8) {
      rootFontSize = 16 // 直屏
    }
    if (screenHeight / screenWidth < 0.8) {
      rootFontSize = 42 // 直屏横评
    }
    if (screenWidth / screenHeight >= 0.8 && screenWidth / screenHeight < 1) {
      rootFontSize = 32 // 折叠屏
    }
    if (screenHeight / screenWidth >= 0.8 && screenHeight / screenWidth < 1) {
      rootFontSize = 42 // 折叠屏横评
    }
    documentEl.style.fontSize = (width / designScale / rootFontSize) * 100 + '%'
  }
  refreshRem()
  win.addEventListener(
    'resize',
    function() {
      clearTimeout(tid)
      tid = setTimeout(refreshRem, 300)
    },
    false
  )
  win.addEventListener(
    'pageshow',
    function(e) {
      if (e.persisted) {
        clearTimeout(tid)
        tid = setTimeout(refreshRem, 300)
      }
    },
    false
  )
  win.addEventListener(
    'DOMContentLoaded',
    function(e) {
      var body = document.getElementsByTagName('body')[0]
      body.style.margin = '0 auto'
    },
    false
  )
})(window, document);

3.2 pad横屏适配

1、设计点检,给出优化设计稿
2、通过媒体查询

@media only screen and (orientation: landscape) 

总结

rem方案

适配原理稍复杂
需要使用 JS
设计稿标注的 px 换算到 cssrem 计算简单
方案灵活,既能实现整体缩放,又能实现局部不缩放

vw 方案

适配原理简单
不需要 JS 即可适配
设计稿标注的 px 换算到 cssvw 计算复杂
方案灵活,既能实现整体缩放,又能实现局部不缩放

viewport+px方案

适配原理简单
需要使用 JS
直接使用设计稿标注无需换算
方案死板,只能实现页面级别肢体缩放

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值