场景描述 1:适配移动端根据不同的手机机型保持整体的缩放比例不变
这里的适配方案用的是淘宝的 lib-flexible 下的 flexible.js
1 安装 lib-flexible
npm i lib-flexible
废话不多!想必大家对这个 flexible.js 的原理应该已经很了解了![奸笑],如不了解请自行百度
|| 谷歌
。大致的原理就是就以设计稿的宽度为基准,将设计稿平分为 10 份。然后将 1/10 份的大小设置成根节点的大小。1 个 rem 就是 1/10 份的宽度值!对,没错!他的作用就是这么个作用(我个人的理解)
比如设计稿的为375px
格式的,那么引入这个 flexble.js 以后,根节点的 font-size:37.5px(1rem),接下来先看下代码和效果来验证这个关系
<!--html-->
<div class="wrapper">
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
<div class="box4"></div>
<div class="box5"></div>
</div>
// scss
<style lang="scss">
.wrapper div {
height: 1rem;
}
.box1 {
width: 2rem;
background-color: coral;
}
.box2 {
width: 4rem;
background-color: skyblue;
}
.box3 {
width: 6rem;
background-color: palegreen;
}
.box4 {
width: 8rem;
background-color: wheat;
}
.box5 {
width: 10rem;
background-color: darkred;
}
</style>
vue.config.js
然后 如果我们不借助任何插件的话 我们要怎么跟跟设计稿保持一直呢???[狗头]
// -此处用的是less, scss的变量计算必须要单位一致,写起来比较麻烦这里为了方便演示所以用了less-->
<style lang="less">
@375: 37.5rem;
.wrapper div {
height: 37.5/@375;
}
.box1 {
width: 75/@375;
background-color: coral;
}
.box2 {
width: 150/@375;
background-color: skyblue;
}
.box3 {
width: 225/@375;
background-color: palegreen;
}
.box4 {
width: 300/@375;
background-color: wheat;
}
.box5 {
width: 375/@375;
background-color: darkred;
}
</style>
实践证明这端代码的效果跟上述的一毛一样~就是写法会比较麻烦在实际项目当中肯定不会这么做。所以接下来就会用到 px2rem-loader
2.0 安装 px2rem-loader
npm i px2rem-loader -D
2.1 配置 px2rem-loader
在 vue.config.js 中进行配置,配置后记得重启
项目使配置生效!
module.exports = {
.
.
.
chainWebpack: config => {
config.module
.rule('css')
.test(/\.css$/)
.oneOf('vue')
.resourceQuery(/\?vue/)
.use('px2rem')
.loader('px2rem-loader') // px2rem-loader这里只能仅限于css
.options({
remUnit: 37.5
})
},
}
它的作用就是字如其名一看便知![旺柴],这里以上述的为例。将 remUnit 设置为 37.5 后!那么他就会自动的帮你以 37.5 为基准进行 px to rem 转换。
举个栗子: 把一个 div 的宽度设置为 37.5px,得到的结果如下所示
width: 37.5px;
// 等价于
width: 37.5 / @375;
// 最终的结果:
width: 1rem;
<style lang="scss">
.wrapper div {
height: 37.5px;
}
.box1 {
width: 75px;
background-color: coral;
}
.box2 {
width: 150px;
background-color: skyblue;
}
.box3 {
width: 225px;
background-color: palegreen;
}
.box4 {
width: 300px;
background-color: wheat;
}
.box5 {
width: 375px;
background-color: darkred;
}
</style
所以到这里才算达到大家想要的效果,不在需要关心什么转换关系了。直接使用跟设计稿一致的 px 了[奸笑],剩下的一切交给px2rem-loader
爸爸就好了。[emmmmmmm]这个时候你以为你可以安心的走了[奸笑],结果苏不知这里有‘坑’!结果:
那么究竟是什么'坑'呢? 其实吧也不是什么坑,就是px2rem-loader
这个插件只能仅限于 css,也就是说 lang='scss || less'
类型的都不支持!
- 正常的 css 未设置 lang
- 设置 lang='less || scss'
那么有没有更好的解决方案呢?答案是有的。
弃用px2rem-loader(把 px2rem-loader 相关配置删除)使用postcss-plugin-px2rem
npm install postcss-plugin-px2rem --save-dev
依赖安装好以后只需要配置两个地方然后重启项目就ojbk了!
vue.config.js
module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [
require('postcss-plugin-px2rem')({
/**
* 换算基数, 默认100。
* 这样的话把根标签的字体规定为1rem为`${rootValue}px`,
* 这样就可以从设计稿上量出多少个px直接在代码中写多上px了。
*/
rootValue: 37.5,
/**
* 默认false,可以(reg)利用正则表达式排除某些文件夹的方法,
* 例如/(node_module)\/如果想把前端UI框架内的px也转换成rem,
* 请把此属性设为默认值
*/
exclude: /(node_module)/,
//(布尔值)允许在媒体查询中转换px。
mediaQuery: false,
}),
]
}
}
},
}
main.js
import 'lib-flexible' // 引入即可
package.json
{
"postcss": {
"plugins": {
"autoprefixer": {},
"precss": {}
}
}
}
场景 2: 如何适配 PC 端或者 iPad
还是以上面的为基础进行分析 先解除手机预览模式,开启浏览器模式
当我们调节浏览器窗口大小的时候会发现一个问题,就是根节点的 font-size 最大值只有 54px,然后不在随着屏幕宽度的变化而变化了。讲道理如果按照 1920px 的设计稿来开发的话,根节点的 font-size 应该是 192px 才对啊。靠!道理讲不通啊[奸笑][奸笑]
不知你是否还记得 flexible 是用来适配移动端的,你直接用来适配非移动端的肯定会有点问题。[旺柴][旺柴]看源码
// flexible.js
// 本篇文章以dpr为1的情况来分析
function refreshRem() {
var width = docEl.getBoundingClientRect().width
if (width / dpr > 540) {
width = 540 * dpr
}
var rem = width / 10
docEl.style.fontSize = rem + 'px'
flexible.rem = win.rem = rem
}
从上面代码分析不难看出,当 width > 540 的时候 with 就不在改变了。所以要想使得根字体大小跟设计稿一致,那就把 540 改成动态的不就完事了嘛
// flexible.js
function refreshRem() {
var width = docEl.getBoundingClientRect().width
if (width / dpr > width) {
width = width * dpr
}
var rem = width / 10
docEl.style.fontSize = rem + 'px'
flexible.rem = win.rem = rem
}
然后你在你的宽为 1920px 的显示器上按照设计稿开始撸代码,那可谓撸码一时爽,一直撸码一直爽[奸笑],最后完美收工开心的不了。
结果产品家里有个 21:9(3440*1440)的超宽的曲面屏显示器,打开了你认为完美的产品,然后惊奇的一幕发生了!
啊········这········辣眼睛
字体太大了!!亮瞎我的狗眼[旺柴] 所以在这里要改一下,让他在一定的范围内进行自适应,不在这个规定的范围内就不在随着屏幕的改变而改变了,完美~
// flexible.js
function refreshRem() {
var width = docEl.getBoundingClientRect().width
// 当屏幕超过1920px以后就不在随着屏幕的变大而变大了
if (width / dpr > 1920) {
width = 1920 * dpr
}
// 当屏幕小于1300px以后就不再随着屏幕的变小而变小了
if (width / dpr < 1300) {
width = 1300 * dpr
}
var rem = width / 10
docEl.style.fontSize = rem + 'px'
flexible.rem = win.rem = rem
}
以上就是大体的一个思路,因为自己在弄自己的 blog,刚好也想记录下自己遇到的问题。纯属个人的总结,可能理解的有出入,望指正~我虚心接受。哈哈哈哈哈
总结一下
flexible.js
: 根据屏幕的宽度,动态地设置根节点的字体大小(因为 rem 是根据根节点的字体大小来进行缩放的)- 但是默认根节点的最大 font-size 为 54px,所以屏幕宽度超过 540px 的时候就不在随着宽度变大而变大了。如果需要定制化那就改下源码就好啦
- 如果自定义化的话 建议把他的 js 复制到自己的项目当中
px2rem-loader
:将 px 转换成 rem- 缺点:只能转换普通的 css 样式,如果设置了 lang='less || scss',就无法转换成 rem 了
postcss-plugin-px2rem
:同样也是将 px 转换成 rem 但是更吊,更棒 [旺柴]
附项目信息
{
"name": "kaka-blog",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve --copy",
"build:dev": "vue-cli-service build --mode development --report",
"build:test": "vue-cli-service build --mode test --report",
"build:prod": "vue-cli-service build --mode production --report",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^3.6.5",
"element-ui": "^2.13.2",
"less-loader": "^6.1.1",
"lib-flexible": "^0.3.2",
"sass-loader": "^8.0.2",
"screenfull": "^5.0.2",
"vue": "^2.6.11",
"vue-router": "^3.3.2"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.4.0",
"@vue/cli-plugin-eslint": "~4.4.0",
"@vue/cli-service": "~4.4.0",
"babel-eslint": "^10.1.0",
"compression-webpack-plugin": "^4.0.0",
"eslint": "^6.7.2",
"eslint-plugin-vue": "^6.2.2",
"github-markdown-css": "^4.0.0",
"highlight.js": "^10.0.3",
"node-sass": "^4.14.1",
"postcss-plugin-px2rem": "^0.8.1",
"px2rem-loader": "^0.1.9",
"speed-measure-webpack-plugin": "^1.3.3",
"terser-webpack-plugin": "^3.0.3",
"thread-loader": "^2.1.3",
"uglifyjs-webpack-plugin": "^2.2.0",
"vue-loader": "^15.9.2",
"vue-markdown-highlight": "^1.0.5",
"vue-markdown-loader": "^2.4.1",
"vue-template-compiler": "^2.6.11",
"webpack": "^4.43.0",
"webpack-bundle-analyzer": "^3.8.0"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": ["plugin:vue/essential", "eslint:recommended"],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {
"no-unused-vars": [
1,
{
"vars": "all",
"args": "after-used"
}
]
}
},
"postcss": {
"plugins": {
"autoprefixer": {},
"precss": {}
}
},
"browserslist": ["> 1%", "last 2 versions", "not dead"]
}