前言
移动端适配在开发中经常遇到,这里做了如下汇总:
一、1px物理像素线
1、实现普通屏幕下1px,高清屏幕下0.5px,伪类+采用transform属性scale实现
.mod_grid {
position: relative;
&::after {
// 实现1物理像素的下边框线
content: '';
position: absolute;
z-index: 1;
pointer-events: none;
background-color: #ddd;
height: 1px;
left: 0;
right: 0;
top: 0;
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
-webkit-transform: scaleY(0.5);
-webkit-transform-origin: 50% 0%;
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.border_1px:before{
transform: scaleY(0.33);
-webkit-transform-origin: 33.333% 0%;
}
}
}
...
}
2、border-image
基于media查询判断不同的设备像素比给定不同的border-image:
.border_1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px{
border-bottom: none;
border-width: 0 0 1px 0;
border-image: url(../img/1pxline.png) 0 0 2 0 stretch;
}
}
3、background-image
和border-image类似,准备一张符合条件的边框背景图,模拟在背景上。
.border_1px{
border-bottom: 1px solid #000;
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.border_1px{
background: url(../img/1pxline.png) repeat-x left bottom;
background-size: 100% 1px;
}
}
上面两种都需要单独准备图片,而且圆角不是很好处理,但是可以应对大部分场景。
4、svg
上面我们border-image和background-image都可以模拟1px边框,但是使用的都是位图,还需要外部引入。
借助PostCSS的postcss-write-svg我们能直接使用border-image和background-image创建svg的1px边框:
@svg border_1px {
height: 2px;
@rect {
fill: var(--color, black);
width: 100%;
height: 50%;
}
}
.example { border: 1px solid transparent; border-image: svg(border_1px param(--color #00b1ff)) 2 2 stretch; }
编译后:
.example { border: 1px solid transparent; border-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' height='2px'%3E%3Crect fill='%2300b1ff' width='100%25' height='50%25'/%3E%3C/svg%3E") 2 2 stretch; }
二、移动端px转vw适配方案(vue+vant)
1、安装插件
npm install postcss-px-to-viewport --save-dev
2、项目根目录添加配置文件
postcss.config.js
3、添加配置
const path = require('path');
module.exports = ({ file }) => {
const designWidth = file.dirname.includes(path.join('node_modules', 'vant')) ? 375 : 750;
return {
plugins: {
autoprefixer: {},
"postcss-px-to-viewport": {
unitToConvert: "px", // 需要转换的单位,默认为"px"
viewportWidth: designWidth, // 设计稿的视口宽度
unitPrecision: 6, // 单位转换后保留的精度
propList: ["*"], // 能转化为vw的属性列表
viewportUnit: "vw", // 希望使用的视口单位
fontViewportUnit: "vw", // 字体使用的视口单位
selectorBlackList: [], // 需要忽略的CSS选择器,不会转为视口单位,使用原有的px等单位。
minPixelValue: 1, //设置最小的转换数值,如果为1的话,只有大于1的值会被转换
mediaQuery: true, // 媒体查询里的单位是否需要转换单位
exclude: /(\/|\\)(node_modules)(\/|\\)/, // 忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
landscape: false, // 是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
landscapeUnit: 'vw', // 横屏时使用的单位
landscapeWidth: 1920 // 横屏时使用的视口宽度
}
}
}
}
三、适配iphoneX
现在很多手机也出现了一些圆角(corners)、刘海(sensor housing)和小黑条(Home Indicator)为了适配这些手机,安全区域这个概念变诞生了:安全区域就是一个不受上面三个效果的可视窗口范围。
1、viewport-fit
viewport-fit是专门为了适配iPhoneX而诞生的一个属性,它用于限制网页如何在安全区域内进行展示。
contain: 可视窗口完全包含网页内容
cover:网页内容完全覆盖可视窗口
默认情况下或者设置为auto和contain效果相同。
2、env、constant
我们需要将顶部和底部合理的摆放在安全区域内,
iOS11新增了两个CSS函数env、constant,用于设定安全区域与边界的距离。
函数内部可以是四个常量:
safe-area-inset-left:安全区域距离左边边界距离safe-area-inset-right:安全区域距离右边边界距离safe-area-inset-top:安全区域距离顶部边界距离safe-area-inset-bottom:安全区域距离底部边界距离
注意:我们必须指定viweport-fit后才能使用这两个函数
<meta name="viewport" content="viewport-fit=cover">
constant在iOS < 11.2的版本中生效,env在iOS >= 11.2的版本中生效,这意味着我们往往要同时设置他们,将页面限制在安全区域内:
body {
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
}
当使用底部固定导航栏时,我们要为他们设置padding值:
padding-bottom: constant(safe-area-inset-bottom);
padding-bottom: env(safe-area-inset-bottom);
四、横屏适配
很多视口我们要对横屏和竖屏显示不同的布局,所以我们需要检测在不同的场景下给定不同的样式:
1、JavaScript检测横屏
window.orientation:获取屏幕旋转方向
window.addEventListener("resize", ()=>{
if (window.orientation === 180 || window.orientation === 0) {
// 正常方向或屏幕旋转180度
console.log('竖屏');
};
if (window.orientation === 90 || window.orientation === -90 ){
// 屏幕顺时钟旋转90度或屏幕逆时针旋转90度
console.log('横屏');
}
});
2、CSS检测横屏
@media screen and (orientation: portrait) {
/*竖屏...*/
}
@media screen and (orientation: landscape) {
/*横屏...*/
}
五、图片模糊问题
为了保证图片质量,我们应该尽可能让一个屏幕像素来渲染一个图片像素,所以,针对不同DPR的屏幕,我们需要展示不同分辨率的图片。
如:在dpr=2的屏幕上展示两倍图(@2x),在dpr=3的屏幕上展示三倍图(@3x)。
使用media查询判断不同的设备像素比来显示不同精度的图片:
1、media查询
.avatar{
background-image: url(conardLi_1x.png);
}
@media only screen and (-webkit-min-device-pixel-ratio:2){
.avatar{
background-image: url(conardLi_2x.png);
}
}
@media only screen and (-webkit-min-device-pixel-ratio:3){
.avatar{
background-image: url(conardLi_3x.png);
}
}
2、image-set
.avatar {
background-image: -webkit-image-set( "conardLi_1x.png" 1x, "conardLi_2x.png" 2x );
}
3、srcset
使用img标签的srcset属性,浏览器会自动根据像素密度匹配最佳显示图片:
<img src="conardLi_1x.png"
srcset=" conardLi_2x.png 2x, conardLi_3x.png 3x">
4、JavaScript拼接图片url
const dpr = window.devicePixelRatio;
const images = document.querySelectorAll('img');
images.forEach((img)=>{
img.src.replace(".", `@${dpr}x.`);
})
5、使用svg
SVG 的全称是可缩放矢量图(Scalable Vector Graphics)。不同于位图的基于像素,SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。
除了我们手动在代码中绘制svg,我们还可以像使用位图一样使用svg图片:
<img src="conardLi.svg">
<img src="data:image/svg+xml;base64,[data]">
.avatar {
background: url(conardLi.svg);
}