移动端适配方案

简介

最常见的移动端适配分为两种,基于rem、基于viewport

目前应用的单位最多还是rem

移动端适配都需要在html页面中定义meta,定义用户通过手指放大缩小无效,页面比例始终保持为1:1

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

基于 rem

  • rem是一个单位,这个单位是基于html标签的font-size值计算的

  • 比如设置了html标签的font-size值为16px。那么对应的2rem计算出来实际上就是32px

  • 使用rem适配首先需要设置html标签的font-size值,可以直接在样式中设置,或者编写js设置,或者使用插件(比如:amfe-flexible

  • 然后再代码中用到尺寸的地方使用rem代替px作为单位

  • 也可以在代码中使用px作为单位,借助webpack的一些插件实现将px自动转换成rem。这类插件比如:postcss-pxtorempostcss-px2rempx2rem-loader

备注

  • lib-flexible方案已经不推荐使用

基于 viewport

viewport单位已经越来越受到众多浏览器的支持。可以使用viewport单位做移动端的适配

  • vw:屏幕宽度单位,100vw就是整个屏幕宽度
  • vh:屏幕高度单位,100vh就是整个屏幕高度

rem 适配之 手动计算值

  • 这里直接使用vw设置htmlfont-size
  • 手动计算效果图中的像素大小,对应于代码中是多少rem
  • 代码中的单位为rem
  • 修改公共样式文件,设置htmlfont-size值。比如:src/assets/less/base.less
html,body{ font-size: calc(100vw/7.5); } // 这里以效果图 750px 为例 // 750px 对应 100vw // 为了方便,我们将 750px 设置成 7.5rem;也就是:效果图中的像素大小 / 100 // 1rem 就是 100vw / 7.5 // 这样效果图上面,比如宽度是 320px,代码中就写 3.2rem // 同理如果效果图大小是 1024px,那么就设置 font-size: calc(100vw/10.24)
  • 在代码中,单位使用rem。大小为效果图中大小 / 100

rem 适配之设置 font-size

  • 使用rem首先需要设置htmlfont-size值。
  • 可以自己写js或者使用插件(如:amfe-flexible
  • 这里我们将屏幕宽度设置成10rem来计算,方便后面与postcss-pxtorem等集成

js设置

  • src/utils/目录下添加rem.js文件
// 设置 rem 函数 function setRem () { const htmlWidth = document.documentElement.clientWidth || document.body.clientWidth // 得到 html 的 Dom 元素 const htmlDom = document.getElementsByTagName('html')[0] // 设置根元素字体大小 htmlDom.style.fontSize = htmlWidth / 10 + 'px' } // 初始化 setRem() // 改变窗口大小时重新设置 rem window.onresize = function () { setRem() }
  • 修改src/main.js文件,引入该文件
// ... import './utils/rem' // ...

amfe-flexible

  • 安装amfe-flexible
npm i amfe-flexible --save
  • 修改src/main.js文件,引入amfe-flexible
// ... import 'amfe-flexible' // ...

备注

  • 使用此插件可以自动动态给html标签设置font-size
  • 比如设备尺寸414*736,在竖屏情况下font-size: 41.4px;横屏情况下font-size: 73.6px
  • 即:font-size的值被设置成了设备宽 / 10
  • 屏幕宽度就是10rem
  • 支持0.5px

rem 适配之 postcss-pxtorem

  • 首先需要设置htmlfont-size值。在上一节中已经介绍
  • 可以使用postcss-pxtorem,将px单位自动转换成rem单位
  • 效果图中尺寸多大,代码中就写多大。单位px

使用

  • 安装postcss-pxtorem
npm i postcss-pxtorem --save-dev
  • vue-cli2.x的项目中使用:修改.postcssrc.js文件
// ... module.exports = { "plugins": { // ... // to edit target browsers: use "browserslist" field in package.json "autoprefixer": {}, 'postcss-pxtorem': { rootValue: 75, // 换算的基数。这里填写 '效果图尺寸 / 10' 这样的话屏幕尺寸正好对应 10rem // 忽略转换正则匹配项。插件会转化所有的样式的px。比如引入了三方UI,也会被转化。目前我使用 selectorBlackList 字段,来过滤 // 如果个别地方不想转化px。可以简单的使用大写的 PX 或 Px。 // selectorBlackList : ['weui','mu'], propList: ['*'] } } }
  • vue-cli3.x的项目中使用:如果有postcss.config.js,修改此文件
module.exports = { plugins: { autoprefixer: {}, 'postcss-pxtorem': { rootValue: 75, // 换算的基数。这里填写 '效果图尺寸 / 10' 这样的话屏幕尺寸正好对应 10rem propList: ['*'] } } }
  • vue-cli3.x的项目中使用:如果没有postcss.config.js,修改vue.config.js文件
const autoprefixer = require('autoprefixer'); const pxtorem = require('postcss-pxtorem'); // ... module.exports = { // ... css: { loaderOptions: { postcss: { plugins: [ autoprefixer(), pxtorem({ rootValue: 75, // 结果为:设计稿元素尺寸 / 75,比如元素宽 750px,最终页面会换算成 10rem propList: ['*'] }) ] } } } };

参数

config = { rootValue: 16, // (Number) 根元素的font-size。这里可以理解成基数 unitPrecision: 5, // (Number) 指定`px`转换为视窗单位值的小数位数,默认是5 propList: ['font', 'font-size', 'line-height', 'letter-spacing'], // (Array) 指定可以转换的css属性,默认是['*'],代表全部属性进行转换 selectorBlackList: [], // (Array) 指定不转换为视窗单位的类,保留px,值为string或正则regexp,建议定义一至两个通用的类名 replace: true, // (Boolean) replaces rules containing vw instead of adding fallbacks mediaQuery: false, // (Boolean) 是否在媒体查询时也转换px,默认false minPixelValue: 0 // (Number) 默认值1,小于或等于`1px`不转换为视窗单位 }

rem 适配之 postcss-px2rem

  • 用法与postcss-pxtorem基本相同
  • postcss-pxtoremrootValue,对应postcss-px2rem中的remUnit

rem 适配之 px2rem-loader

  • 首先需要设置htmlfont-size值。在上一节中已经介绍
  • 可以使用px2rem-loader,将px单位自动转换成rem单位
  • 效果图中尺寸多大,代码中就写多大。单位px

使用

  • 安装px2rem-loader
npm i px2rem-loader --save-dev
  • vue-cli2.x的项目中使用:修改build/utils.js文件
// ... exports.cssLoaders = function (options) { // ... // 添加 px2remLoader const px2remLoader = { loader: 'px2rem-loader', options: { // 换算的基数。这里填写 '效果图尺寸 / 10' 这样的话屏幕尺寸正好对应 10rem // 如果个别地方不想转化px。可以简单的使用大写的 PX 或 Px。 remUnit: 75 } } // generate loader string to be used with extract text plugin function generateLoaders (loader, loaderOptions) { // const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] // 注释掉上面一行,添加下面一行 const loaders = options.usePostCSS ? [cssLoader, postcssLoader, px2remLoader] : [cssLoader, px2remLoader] // ... } // ... } // ...
  • vue-cli3.x的项目中使用:修改vue.config.js文件
// ... module.exports = { // ... chainWebpack: config => { config.module // // css // .rule('css') // .test(/\.css$/) // .oneOf('vue') // .resourceQuery(/\?vue/) // .use('px2rem') // .loader('px2rem-loader') // .options({ // // 结果为:设计稿元素尺寸 / 75,比如元素宽 750px,最终页面会换算成 10rem // remUnit: 75 // }) // 如果使用了 less .rule('less') .test(/\.less$/) .oneOf('vue') .use('px2rem-loader') .loader('px2rem-loader') .before('postcss-loader') // this makes it work. .options({ remUnit: 75 }) .end() } };

参数

config = { baseDpr: 2, // (Number) 设备像素比,默认为 2 remUnit: 75, // (Number) rem基数,默认 75 remPrecision: 6, // (Number) 指定'px'转换为视窗单位值的小数位数,默认是 6 forcePxComment: 'px', // (String) force px comment (default: 'px') keepComment: 'no' // (String) no transform value comment (default: 'no') }

viewport 适配之 postcss-px-to-viewport

  • 可以使用postcss-px-to-viewport,将px单位自动转换成viewport单位
  • viewportWidth大小设置成效果图尺寸,这样效果图中尺寸多大,代码中就写多大。单位px

使用

  • 安装postcss-px-to-viewport
npm i postcss-px-to-viewport --save-dev
  • vue-cli2.x的项目中使用:修改.postcssrc.js文件
// ... module.exports = { "plugins": { // ... // to edit target browsers: use "browserslist" field in package.json "autoprefixer": {}, 'postcss-px-to-viewport': { viewportWidth: 750, // 视窗的宽度,对应的是我们设计稿的宽度,一般是750 viewportHeight: 1334, // 视窗的高度,根据750设备的宽度来指定,一般指定1334,也可以不配置 unitPrecision: 3, // 指定`px`转换为视窗单位值的小数位数 viewportUnit: "vw", //指定需要转换成的视窗单位,建议使用vw selectorBlackList: ['.ignore'],// 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名 minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值 mediaQuery: false // 允许在媒体查询中转换`px` } } }
  • vue-cli3.x的项目中使用:如果有postcss.config.js,修改此文件
// ... module.exports = { plugins: { // ... autoprefixer: {}, 'postcss-px-to-viewport': { viewportWidth: 750 } } }
  • vue-cli3.x的项目中使用:如果没有postcss.config.js,修改vue.config.js文件
const autoprefixer = require('autoprefixer'); const pxtoviewport = require('postcss-px-to-viewport'); // ... module.exports = { // ... css: { loaderOptions: { postcss: { plugins: [ autoprefixer(), pxtoviewport({ viewportWidth: 750 }) ] } } } };

参数

viewportWidth就是设计稿的宽度
比如:设计稿宽度750px,设置的viewportWidth值也是750px
那么对应的100vw就是750px1vw也就是7.5px
编写代码时,设计稿上面是多少像素,代码就写多少px
代码中的300px转换后也就是300 / 7.5 = 40vw

config = { unitToConvert: 'px' // (String) 要转换的单位,默认是'px' viewportWidth: 320, // (Number) viewport的宽度,默认是320,可根据设计稿来,750的设计稿就写750 unitPrecision: 5, // (Number) 指定`px`转换为视窗单位值的小数位数,默认是5 propList: ['*'], // (Array) 指定可以转换的css属性,默认是['*'],代表全部属性进行转换 viewportUnit: 'vw', // (String)指定需要转换成的视窗单位,默认vw fontViewportUnit: 'vw', // (String)指定字体需要转换成的视窗单位,默认vw selectorBlackList: [], // (Array) 指定不转换为视窗单位的类,保留px,值为string或正则regexp,建议定义一至两个通用的类名 minPixelValue: 1, // (Number) 默认值1,小于或等于`1px`不转换为视窗单位 mediaQuery: false, // (Boolean) 是否在媒体查询时也转换px,默认false replace: true, // (Boolean) replaces rules containing vw instead of adding fallbacks exclude: [], // (Array or Regexp) 设置忽略文件,如node_modules landscape: false, // (Boolean) @media (orientation: landscape) with values converted via landscapeWidth landscapeUnit: 'vw', // (String) Expected unit for landscape option landscapeWidth: 568 // (Number) Viewport width for landscape orientation. }

问题

  • @keyframesmedia查询里的px默认是不转化的,设置mediaQuery:true则媒体查询里也会转换px

  • @keyframes可以暂时手动填写vw单位的转化结果


创作不易,若本文对你有帮助,欢迎打赏支持作者!

 分享给好友: