移动端适配方案

Flexible适配方案
最早的文章,是15年阿里手淘团队的移动端适配方案。
设计师常选择iPhone6作为基准设计尺寸,交付给前端的设计尺寸是按750px * 1334px为准(高度会随着内容多少而改变)。
前端开发人员通过一套适配规则自动适配到其他的尺寸。
先了解一些基本概念
 
视窗viewport
 
简单理解,viewport是严格等于浏览器的窗口,在桌面浏览器中,viewport就是浏览器窗口的宽度高度。
但是在移动端的viewport太窄,为了能更好的为css布局服务,所以提供了两个viewport:虚拟的viewportvisualviewport和布局的viewportlayoutviewport(了解这两种viewport概念的可以查看这里)
设备像素比(device pixel ratio)
设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。
设备像素比 = 物理像素 / 设备独立像素
在JavaScript中,可以通过`window.devicePixelRatio`获取到当前设备的dpr。而在CSS中,可以通过`-webkit-device-pixel-ratio`,`-webkit-min-device-pixel-ratio`和 `-webkit-max-device-pixel-ratio`进行媒体查询,对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)
在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。
所以在移动端除了布局的适配外,还需要考虑到图片的显示质量,这就是我们所说的2倍图或者3倍图
 
meta标签
viewport的meta标签,主要是用来告诉浏览器如何规范渲染web页面,在开发移动端页面,我们需要设置meta标签为:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

  

css单位rem
 
font size of the root element.  来自w3c规范
简单的理解,rem就是相对于根元素<html>的font-size来做计算。而我们的方案中使用rem单位,是能轻易的根据<html>的font-size计算出元素的盒模型大小。
实现方案
 
手淘团队根据以上的概念,出了一套针对移动端的适配方案`amfe-flexible`库。
使用方法
前提是需要设置页面的viewport
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
然后引入功能文件
# 阿里CDN引入
<script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.4/??flexible_css.js,flexible.js"></script>
 
# 下载对应的文件,直接在页面中引入。
 
# 当然也可以 npm i -S amfe-flexible
需要注意的一点那就是:在Flexible中,只对iOS设备进行dpr的判断,对于Android系列,始终认为其dpr为1。
lexible实际上就是能过JS来动态改写meta标签,类似这样:
# 动态改写<meta>标签# 
给<html>元素添加data-dpr属性,并且动态改写data-dpr的值#
给<html>元素添加font-size属性,并且动态改写font-size的值
  var metaEl = doc.createElement('meta');
  var scale = isRetina ? 0.5:1;metaEl.setAttribute('name', 'viewport');
  metaEl.setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
  if (docEl.firstElementChild) {    
     document.documentElement.firstElementChild.appendChild(metaEl);
  } else {    
  var wrap = doc.createElement('div');    
  wrap.appendChild(metaEl);   
  documen.write(wrap.innerHTML);
}

  

接下来要做的事情就是`px`->`rem`
1.可以通过在编辑器中安装插件实现单位的换算
2.可以通过配置postCSS进行自动的单位转换,还按照正常的px进行布局,代码执行后会自动转成对应的rem数值。(具体的配置方法,需要看另外的关于postCSS的文章(待完善))
这套方案,在实际构建M站的过程中,我遇到的一个问题是,1px的border无法正常显示,目前网上没有一个很完美的解决方案,更多提到的是转为svg的方式实现。
 
不同的终端,我们面对的屏幕分辨率、DPR、1px、2x图等一系列的问题。那么这个布局方案也是针对性的解决这些问题,只不过解决这些问题不再是使用Hack手段来处理,而是直接使用原生的CSS技术来处理的。
vw是基于viewport视窗的长度单位。指的是浏览器可视化的区域,也就是window.innerWidth/window.innerHeight的大小。
 
1vw = window.innerWidth 的 1%

目前出视觉设计稿,我们都是使用750px宽度的,从上面的原理来看,那么100vw = 750px,即1vw = 7.5px。那么我们可以根据设计图上的px值直接转换成对应的vw值。
这里当然我们也去可以手动去转化单位,但是我们可以在项目的配置项中添加`postCSS`相关的配置,可以为我们自动去转化。我们也只需要按照设计稿给的px去进行布局即可。
下面介绍在`grunt`上配置`postCSS`
 
安装postCSS插件
 
# grunt
npm install grunt-postcss --save-dev
 
#webpack
npm install postcss-loader --save-dev
 
grunt中配置
 
在`gruntfile.js`中配置,通过`grunt.loadNpmTasks()`函数加载`grunt-postcss`插件
module.exports = function(grunt) {
    grunt.initConfig({
        postcss:{
            options:{
                //  配置postCSS所需插件
                processors:[
                    //  这是postCSS插件
                    //  自动添加前缀
                    require('autoprefixer'),
                    //  适配方案
                    require('postcss-px-to-viewport')({
                      viewportWidth: 750,
                        viewportHeight: 1670,
                        unitPrecision: 5,
                        viewportUnit: 'vw',
                        selectorBlackList: [],
                        minPixelValue: 1,
                        mediaQuery: false
                    })
                ]
            },
            dist:{
                //  设置CSS的源文件和postCSS编译后的CSS文件
                src: 'src/style.css',   //  源文件
                dest: 'dest/style.css'  //  输出文件
            }
        }
    });
    grunt.loadNpmTasks('grunt-postcss');
}

  

webpack中配置
 
配置webpack.config.js(即你的基本公用配置中)
 
module: {
  loaders: [
    {
      test: /.css$/,
      // 如果使用了 ExtractTextPlugin
      loader: ExtractTextPlugin.extract('style', 'css!postcss')
      // 否则
      // loader: "style-loader!css-loader!postcss-loader"
    }
  ]
},
//  当然,你也可以在根目录下设置.postcssrc.js中添加对postCSS的配置,会自动识别。
postcss: function () {
    return [ // 里面是我们要用的插件
    //  自动添加前缀
    require('autoprefixer'),
    //  适配方案
    require('postcss-px-to-viewport')({
        viewportWidth: 750,
        viewportHeight: 1670,
        unitPrecision: 5,
        viewportUnit: 'vw',
        selectorBlackList: [],
        minPixelValue: 1,
        mediaQuery: false
    })
    ];
}

  

注意的是,配置postCSS插件的时候,需要提前安装依赖。点击这里。看看postCSS的强大之处吧。
针对第二套适配方案,`vw`已经广泛被移动端浏览器良好的支持了。所以几乎是没有什么问题.
现有项目中的适配方案
现有的项目采用的适配方案,其实和第一种的原理是一样的。
//  动态计算px的大小,比如设计稿的尺寸宽是750px
(function(dew){
    var winW = document.documentElement.clientWidth;
    var ratio = winW/desW;
    document.documentElement.style.fontSize = ratio * 100 + 'px';
})(750);
//在css中对根字体大小进行设置:
 
// html,body{
//     font-size:100px;
// }
// 这样我们在对UI给的尺寸直接除以100,就是对应的rem单位了。

  

当然,px和rem之间的转换,可以通过编辑器自己的插件,也可以去配置postCSS去自动转换。
 
总结
PostCSS是一种工具,一款已成长为像Sass和LESS一样主流的处理器,这一切都归功于它的强大、速度和易用性。
 将 PostCSS 视为后处理器,或者将其视作是预处理器的相反处理,都是一种误导;PostCSS 有能力应对各种不同的使用场景,既可以处理已经被预处理器编译过的代码,也可以处理纯粹的 CSS 代码;它可以在开发者的开发工作流中处理更多的任务
postCSS其实算不上什么适配方案,1和3两套方案的本质是一样的。至于第2种适配方案,本质就是把我们经常用的rem变成了vw视窗单位。
对于postCSS,这个东西带给了我很多新的关于web自动化流程的设计感想。他可以实现很多我们针对CSS方面兼容性的处理。事实上页面的布局总是令人蛋疼的。但技术是不断革新的,我们可以随着保持对新技术的关注,尝试这些新特性运用到实际项目中,只有这样,我们解决问题的方案才会越来越完善。
 
原文地址:https://www.cnblogs.com/yangsg/p/10197212.html