一、前言
大家都知道现在市面上的手机尺寸越来越多,对于一名前端开发来说,面临着开发上的挑战。要使各个手机上的UI达成一致效果,就需要我们采用各种方案规避差距。
二、rem方案
最常见的就是利用手淘的flexible.js,包含amfe-flexible和lib-flexible两种,
amfe-flexible是lib-flexible的升级版。
2.1 实现原理
2.1.1 使用rem实现尺寸自适应
flexible的核心思想是利用rem单位,rem单位是基于html的font-size来做计算的,例如font-size为100px,那么200px就可以用2rem表示
// 在手淘里认为1rem = 屏幕尺寸 / 10
function setRem () {
var rem = docEl.clientWidth / 10
document.documentElement.style.fontSize = rem + 'px'
}
setRem ();
如上代码所示,Flexible将整个页面的宽度切成了10份,然后将计算出来的页面宽度的1/10设置为html节点的fontSize,也就意味着,页面上以 rem为单位的元素的尺寸 都是和 页面宽度 息息相关的
2.1.2 rem解决1px问题
设置viewport的width为device-width,改变浏览器viewport(布局视口和视觉视口)的默认宽度为理想视口宽度,从而使得用户可以在理想视口内看到完整的布局视口的内容。
等比设置viewport的initial-scale、maximum-scale、minimum-scale的值,从而实现1物理像素=1css像素,以适配高倍屏的显示效果(就是在这个地方规避了大家熟知的“1px问题”)
var metaEL= doc.querySelector('meta[name="viewport"]');
var dpr = window.devicePixelRatio;
var scale = 1 / dpr
metaEl.setAttribute('content', 'width=device-width, initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
2.2 使用教程
2.2.1 使用flexible
项目前提是基于Vue Cli3.x的Webpack项目,flexible可以动态改变 根元素的 font-size
cnpm intall amfe-flexible -D // 安装amfe-flexible
import ‘amfe-flexible’ // 在 src\main.js 中引入 amfe-flexible
2.2.2 px2rem 配置
作用: 可以让根元素fontSize根据屏幕宽度自动变化
// px自动转rem
cnpm intall postcss-px2rem -D
在项目根目录下创建postcss.config.js文件
plugins: {
...,
'postcss-pxtorem': {
// 750设计标准,rootValue为设计图宽度/10
rootValue: 75,
// 转换成的rem后,保留小数点后几位
unitPrecision: 5,
/**
* 将会被转换的css属性列表,
* 设置为*表示全部,['*','*position*','!letter-spacing','!font*']
* *position* 表示所有包含 position 的属性
* !letter-spacing 表示非 letter-spacing 属性
* !font* 表示非font-size font-weight ... 等的属性
* */
propList: ['*', '!letter-spacing'],
// 不会被转换的class选择器名,支持正则
selectorBlackList: ['.rem-'],
replace: true,
// 允许在媒体查询中转换`px`
mediaQuery: false,
// 小于1px的将不会被转换
minPixelValue: 1
}
}
2.3 现有问题
2.3.1 无法兼容安卓手机视网膜屏
市面上的安卓手机的dpr比较杂乱,1 到 4 甚至到 5,更甚者1.75、2.6、3.5,所以flexible放弃了对安卓手机多倍屏的适配,直接把dpr=1。
2.3.2 使用iframe引用也会出现问题。
iframe中的css单位还是px
三、viewport
viewport适配是现在 很主流 且 更完美 的适配方案,兼容性也很不错
3.1 实现原理
我们都知道屏幕的宽度可以用 100vw 表示,所以对于 750px 的设计图来说, 100vw =750px,代表 1vw = 7.5px,在使用中直接用vw作为单位,就可以实现 容器和文字 的适配。
3.2 使用教程
3.2.1 安装px-to-viewport
主要用来把 px 单位转换为 vw、vh、vmin 或者 vmax 这样的视窗单位(推荐转换为 vw,其他单位兼容性问题比较多)。项目前提是基于Vue Cli3.x的Webpack项目。
cnpm install postcss-px-to-viewport -D
3.2.2 px-to-viewport配置
在项目根目录下创建postcss.config.js文件,px会自动转换为vw
module.exports = {
plugins: {
"postcss-px-to-viewport": {
unitToConvert: "px", // 需要转换的单位,默认为"px"
viewportWidth: 750, // 设计稿的视口宽度
unitPrecision: 5, // 单位转换后保留的精度
propList: ["*"], // 能转化为vw的属性列表
viewportUnit: "vw", // 希望使用的视口单位
fontViewportUnit: "vw", // 字体使用的视口单位
selectorBlackList: [], // 需要忽略的CSS选择器
minPixelValue: 1, // 最小的转换数值,如果为1的话,只有大于1的值会被转换
mediaQuery: false, // 媒体查询里的单位是否需要转换单位
replace: true, // 是否直接更换属性值,而不添加备用属性
exclude: [], // 忽略某些文件夹下的文件或特定文件
include: undefined, // 如果设置了include,那将只有匹配到的文件才会被转换,例如只转换 'src/mobile' 下的文件 (include: /\/src\/mobile\//)
landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
landscapeUnit: "vw", // 横屏时使用的单位
},
"postcss-preset-env": {
browsers: "last 2 versions", //指定只对最近 2 个版本的浏览器进行兼容性处理。
},
},
};
3.3 存在问题
3.3.1 边框1px问题
-
border-image
安卓低端机和部分ios存在兼容性问题,而且无法实现圆角 -
background-image
background-image方案,在机型上都能比较好的展现,但是在背景图方案中需要提供2像素的图片。 -
渐变背景图
虽然无法实现圆角,但使用率还是挺高的 -
伪类+transform
我认为最值得灵活,最值得提倡的方案,既可以实现圆角,兼容性也好
border-1px($color = #ccc, $radius = 2PX, $direction = all)
position: relative
&::after
content: ""
pointer-events: none
display: block
position: absolute
border-radius: $radius
box-sizing border-box
width 100%
height 100%
left: 0
top: 0
transform-origin: 0 0
if $direction == all
border: 1PX solid $color
else
border-{$direction}: 1PX solid $color
@media only screen and (-webkit-min-device-pixel-ratio:2)
width: 200%
height: 200%
border-radius: $radius * 2
transform: scale(.5)
@media only screen and (-webkit-min-device-pixel-ratio:3)
width: 300%
height: 300%
border-radius: $radius * 3
transform: scale(.333)
3.3.2 宽度大于100vw问题
如果 容器 用vw作为单位,margin用px的话,宽度容易超过100vw,出现滚动问题
解决方式可以用padding代替margin,或者用calc算margin
四 多倍屏图片问题
多倍屏的1px问题,Flexible默认就可以实现适配,viewport可以自己写伪类解决。但是无论是rem还是viewport,图片适配都需要单独处理。
4.1 媒体查询+预编译语言
直接写死不灵活,可以结合预编译语言实现
@mixin bg-image($url) {
background-image: url($url + "@2x.png");
@media (-webkit-min-device-pixel-ratio: 3),(min-device-pixel-ratio: 3) {
background-image: url($url + "@3x.png");
}
}
.div{
width:30px;
height:20px;
background-size:30px 20px;
background-repeat:no-repeat;
//在这里相当于调用了上面媒体查询的方法 ,传入图片url
@include bg-image('special_1');
}
4.2 image-set
仅支持背景图
.avatar {
background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x );
}
4.3 srcset
仅仅支持img图片
<img src="conardLi_1x.png" srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">
4.4 svg
可伸缩矢量图,放大缩小都不会失真
参考大神知乎的文章
https://zhuanlan.zhihu.com/p/291013307