如何进行移动端适配

379 阅读5分钟

通过淘宝的flexible进行适配

  • viewport
<meta 
  name="viewport" 
  content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale: 1.0"
>

老版本flexible.js会修改scale值,会产生一些问题。

  • 计算rem
var docEl = document.documentElement
var rem = docEl.clientWidth / 10
docEl.style.fontSize = rem + 'px'

clientWidth是根元素的可视宽度,如果viewport缩放scale=1.0,那么对于iPhone4的clientWidth=320px,如果scale=0.5,那么clientWidth=640px,无论如何改变viewport值,rem都等于根节点可视宽度的1/10。

老版本0.3.2里有这样一段。

var isAndroid = win.navigator.appVersion.match(/android/gi);
var isIPhone = win.navigator.appVersion.match(/iphone/gi);
var devicePixelRatio = win.devicePixelRatio;
if (isIPhone) {
  // iOS下,对于2和3的屏,用2倍的方案,其余的用1倍方案
  if (devicePixelRatio >= 3 && (!dpr || dpr >= 3)) {
      dpr = 3;
  } else if (devicePixelRatio >= 2 && (!dpr || dpr >= 2)) {
      dpr = 2;
  } else {
      dpr = 1;
  }
} else {
  // 其他设备下,仍旧使用1倍的方案
  dpr = 1;
}
scale = 1 / dpr;

通过设备dpr,动态更新scale。这种方式并不影响rem的计算,好处是解决了1px的问题,坏处是破坏了css媒介media。

新版本2.0里面则去掉了动态计算scale的方式,改为检测是否支持0.5px的特性,通过添加类名hairlines来向下兼容

// detect 0.5px supports
if (dpr >= 2) {
    var fakeBody = document.createElement('body')
    var testElement = document.createElement('div')
    testElement.style.border = '.5px solid transparent'
    fakeBody.appendChild(testElement)
    docEl.appendChild(fakeBody)
    if (testElement.offsetHeight === 1) {
        docEl.classList.add('hairlines')
    }
    docEl.removeChild(fakeBody)
}
 

如何实现从px到rem单位的转换

1. 通过编译器设置1rem的值,开发过程中编译器会自动将px转为rem

  • 优点:使用方便,不需用通过其他方式转换
  • 缺点:不利于后期代码维护

2. 利用sass函数来转换单位

@function pxTorem($px){ //$px为需要转换的字号
    @return $px / $browser-font-size * 1rem; //100px为根字体大小
}
 
.first{
    font-size: pxTorem(100px); 
    height: pxTorem(10px);
    width: pxTorem(200px);
}

3. 借助webpack,px2rem-loader实现

下载loader

npm install style-loader css-loader px2rem-loader --save-dev

4. 借助PostCSS的px2rem插件

下载loader

npm i postcss-px2rem --save-dev

移动端REM适配原理总结:

  • 设计稿的像素单位px,称之为CSS像素

  • 我们需要百分百还原设计稿,就是要按照设计稿的比例,一比一还原到设备上。

  • 首先,每台移动设备都有自己的物理像素设备独立像素,它们之间的关系称之为DPR(device pixel ratio)。即 DPR = 物理像素 / 设备独立像素

  • iPhone公司为了吸引用户,引入了retina屏幕的概念,即在手机尺寸变化的情况下,DPR为2或者3。就是就是每一个设计独立像素,都会占用4个物理像素点9个物理像素点

  • 然后,我们说说视口和缩放比的概念,视口分为布局视口,视觉视口和理想视口,以及设备缩放比

  • 布局视口是指我们开发出来的页面占据多少设备独立像素,当然超过手机宽度(即视口宽度)会出现页面滚动。

  • 视觉视口就是我们当前可以看到的手机屏幕窗口大小。

  • 先说设备缩放比,类似于我们用放大镜看书本上的东西,放大意味着我们看到的文字大内容少。缩小意味着我们看到的文字小内容多,跟这里是一个道理。比如,设置设置缩放比为0.5,即手机可以看到之前4倍多的像素内容。我们可以通过meta标签对viewport进行缩放比设置。

  • 理想视口就是在设备缩放比为1的情况下,布局视口和视觉视口大小相等,我们不需要去通过滚动条去看更多的隐藏内容。一般情况下我们可以设置 width=device-width,即布局视口和视觉视口相等。

  • 再说flexible.js,flexible做了一件事,就是给根节点html设置字体大小,因为rem是相对于html的字体大小的单位,1rem = html的字体大小

  • 老版本的flexible在没有对viewport进行设置视,它会动态设置viewport,同时修改设置缩放比。这样虽然可以正常地解决适配问题,但是带来另一个问题是:破坏了css媒介media

  • css媒体查询media取到的值其实就是设置独立像素,修改设备缩放比会修改掉设备独立像素的值。因此flexible优化了这里。

  • 新版本的flexible.js采用了写死viewport的方式,不会动态修改meta和设备缩放比。这样就避免了上边对media的破坏,也很好的解决了适配问题。新增了检测是否支持0.5px的特性。

  • 最后说说rem单位,rem单位其实就是通过,把视口宽度等分为十等分(因为视口宽度一般是320px,360px,375px,414px,为了计算相对方便,取十等分)。比如320px十等分,1rem = 32px,这样我们写CSS的时候,如果设计稿上某元素的宽是64px,其实就是2rem。

  • 但是,为了开发高效,我们不可能对每个尺寸都手动去转rem。因此就需要通过以上四种方式去自动转rem,来提升开发效率。

本文参考以下文章:

从原理到方案,一步步讲解web移动端实现自适应等比缩放

H5移动多终端适配全解 - 从原理到方案

微网站—使用flexible.js实现移动端设备适配

关于移动端适配,你必须要知道的

淘宝flexible深度解读

大厂是怎么做移动端适配的