viewport适配方案
-
vw:是 viewport’s width 的简写,1vw 等于 window.innerWidth 的 1%;
-
vh:和 vw 类似,是 viewport’s height 的简写,1vh 等于 window.innerHeihgt 的 1%;
-
vmin:vmin 的值是当前 vw 和 vh 中较小的值;
-
vmax:vmax 的值是当前 vw 和 vh 中较大的值;
.logo { font-size: 10vw; // 1vw = 750px * 1% = 7.5px }
1. meta标签
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
2. px 自动转换为 vw
2.1 安装插件
npm install postcss-px-to-viewport --save-dev
2.2 webpack配置
module.exports = {
plugins: {
// ...
'postcss-px-to-viewport': {
// options
unitToConvert: 'px', // 需要转换的单位,默认为"px"
viewportWidth: 750, // 设计稿的视窗宽度
unitPrecision: 5, // 单位转换后保留的精度
propList: ['*', '!font-size'], // 能转化为 vw 的属性列表
viewportUnit: 'vw', // 希望使用的视窗单位
fontViewportUnit: 'vw', // 字体使用的视窗单位
selectorBlackList: [], // 需要忽略的 CSS 选择器,不会转为视窗单位,使用原有的 px 等单位
minPixelValue: 1, // 设置最小的转换数值,如果为 1 的话,只有大于 1 的值会被转换
mediaQuery: false, // 媒体查询里的单位是否需要转换单位
replace: true, // 是否直接更换属性值,而不添加备用属性
exclude: undefined, // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
include: /\/src\//, // 如果设置了include,那将只有匹配到的文件才会被转换
landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件
landscapeUnit: 'vw', // 横屏时使用的单位
landscapeWidth: 1125, // 横屏时使用的视窗宽度
},
},
};
2.3 效果展示
.hello {
color: #333;
font-size: 28px;
}
3. 标注不需要转换的属性
- /* px-to-viewport-ignore-next */ —> 下一行不进行转换.
- /* px-to-viewport-ignore */ —> 当前行不进行转换
/* example input: */
.class {
/* px-to-viewport-ignore-next */
width: 10px;
padding: 10px;
height: 10px; /* px-to-viewport-ignore */
}
/* example output: */
.class {
width: 10px;
padding: 3.125vw;
height: 10px;
}
4. Retina 屏问题
考虑 Retina 屏场景,可能对图片的高清程度、1px 等场景有需求,所以我们预留判断 Retina 屏坑位。 相关方案如下:在入口的 html 页面进行 dpr 判断,以及 data-dpr 的设置;然后在项目的 css 文件中就可以根据 data-dpr 的值根据不同的 dpr 写不同的样式类;
4.1 index.html文件
// index.html 文件
<script>
const dpr = devicePixelRatio >= 3? 3: devicePixelRatio >= 2? 2: 1;
document.documentElement.setAttribute('data-dpr', dpr);
</script>
4.2 样式文件
[data-dpr="1"] .hello {
background-image: url(image@1x.jpg);
[data-dpr="2"] .hello {
background-image: url(image@2x.jpg);
}
[data-dpr="3"] .hello {
background-image: url(image@3x.jpg);
}
postcss-px-to-viewport插件无法对行内样式进行单位转换,因此需要手动计算,或使用className的方式操作。
5. 1px 的问题
5.1 transform: scale(0.5)
可以使用 transform: scale(0.5) 进行 X、Y 轴的缩放,如下示例所示
.class1 {
height: 1px;
transform: scaleY(0.5);
}
5.2 推荐方案,伪元素
.calss1 {
position: relative;
&::after {
content:"";
position: absolute;
bottom:0px;
left:0px;
right:0px;
border-top:1px solid #666;
transform: scaleY(0.5);
}
}
5.3 box-shadow
不好看
.class1 {
box-shadow: 0 1px 1px -1px rgba(0, 0, 0, 0.5);
}
5.4 其他方案 不推荐
- viewport: 将页面进行缩小处理;
- border-image:切个 1px 图片来模拟;
- background-image:切个 1px 图片来模拟;
- linear-gradient:通过线性渐变,来实现移动端 1px 的线;
- svg:基于矢量图形(svg) 在不同设备屏幕特性下具有伸缩性。
6. 图片高清问题
根据不同dpr配置不同图片
[data-dpr="1"] .hello {
background-image: url(image@1x.jpg);
[data-dpr="2"] .hello {
background-image: url(image@2x.jpg);
}
[data-dpr="3"] .hello {
background-image: url(image@3x.jpg);
}
7. iPhoneX 适配方案
7.1 meta标签中设置网页在可视窗口的布局方式
<meta name="viewport" content="viewport-fit=cover">
7.2 fixed 完全吸底元素场景的适配
{
padding-bottom: constant(safe-area-inset-bottom); /* 兼容 iOS < 11.2 */
padding-bottom: env(safe-area-inset-bottom); /* 兼容 iOS >= 11.2 */
}
7.3 fixed 非完全吸底元素场景的适配
{
margin-bottom: constant(safe-area-inset-bottom);
margin-bottom: env(safe-area-inset-bottom);
}