像素适配
1px 问题
所谓 1px 问题,即在高清屏下,移动端的 1px 会很粗,如下两个边框对比:
window.devicePixelRatio=物理像素 / CSS像素
目前主流的屏幕 DPR=2(iPhone 8),或者 3(iPhone 8 Plus)。拿 2 倍屏来说,设备的物理像素要实现 1 像素,而 DPR=2,所以 css 像素只能是 0.5。一般设计稿是按照 750 来设计的,它上面的 1px 是以 750 来参照的,而我们写 css 样式是以设备 375 为参照的,最简单的办法就是将边框设置为 0.5px。
border: 0.5px solid #e5e5e5;
或者使用边框图片:
border: 1px solid transparent;
border-image: url("./../../image/96.jpg") 2 repeat;
或者使用阴影:
box-shadow: 0 -1px 1px -1px #e5e5e5, //上边线
1px 0 1px -1px #e5e5e5,
//右边线
0 1px 1px -1px #e5e5e5, // 下边线
-1px 0 1px -1px #e5e5e5; /** 左边线 */
或者使用伪元素:
.setOnePx {
position: relative;
&::after {
position: absolute;
content: "";
background-color: #e5e5e5;
display: block;
width: 100%;
height: 1px; /*no*/
transform: scale(1, 0.5);
top: 0;
left: 0;
}
}
可以看到,将伪元素设置绝对定位,并且和父元素的左上角对齐,将 width 设置 100%,height 设置为 1px,然后进行在 Y 方向缩小 0.5 倍。最后,终极解决办法是使用基于 vw 进行适配:
<html>
<head>
<title>1px question</title>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
<meta
name="viewport"
id="WebViewport"
content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<style>
html {
font-size: 1px;
}
* {
padding: 0;
margin: 0;
}
.top_b {
border-bottom: 1px solid #e5e5e5;
}
.a,
.b {
box-sizing: border-box;
margin-top: 1rem;
padding: 1rem;
font-size: 1.4rem;
}
.a {
width: 100%;
}
.b {
background: #f5f5f5;
width: 100%;
}
</style>
<script>
var viewport = document.querySelector("meta[name=viewport]");
//下面是根据设备像素设置viewport
if (window.devicePixelRatio == 1) {
viewport.setAttribute(
"content",
"width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
);
}
if (window.devicePixelRatio == 2) {
viewport.setAttribute(
"content",
"width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no"
);
}
if (window.devicePixelRatio == 3) {
viewport.setAttribute(
"content",
"width=device-width,initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no"
);
}
var docEl = document.documentElement;
var fontsize = 32 * (docEl.clientWidth / 750) + "px";
docEl.style.fontSize = fontsize;
</script>
</head>
<body>
<div class="top_b a">下面的底边宽度是虚拟 1 像素的</div>
<div class="b">上面的边框宽度是虚拟 1 像素的</div>
</body>
</html>
软键盘将页面顶起来、收起未回落问题
Android 手机中,点击 input 框时,键盘弹出,将页面顶起来,导致页面样式错乱。移开焦点时,键盘收起,键盘区域空白,未回落。我们在 app 布局中会有个固定的底部。安卓一些版本中,输入弹窗出来,会将解压 absolute 和 fixed 定位的元素。导致可视区域变小,布局错乱。
解决方案是软键盘将页面顶起来的解决方案,主要是通过监听页面高度变化,强制恢复成弹出前的高度。
// 记录原有的视口高度
const originalHeight =
document.body.clientHeight || document.documentElement.clientHeight;
window.onresize = function () {
var resizeHeight =
document.documentElement.clientHeight || document.body.clientHeight;
if (resizeHeight < originalHeight) {
// 恢复内容区域高度
// const container = document.getElementById("container")
// 例如 container.style.height = originalHeight;
}
};
键盘不能回落问题出现在 iOS 12+ 和 wechat 6.7.4+ 中,而在微信 H5 开发中是比较常见的 Bug。兼容原理,1.判断版本类型 2.更改滚动的可视区域
const isWechat = window.navigator.userAgent.match(/MicroMessenger\/([\d\.]+)/i);
if (!isWechat) return;
const wechatVersion = wechatInfo[1];
const version = navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
// 如果设备类型为 iOS 12+ 和 wechat 6.7.4+,恢复成原来的视口
if (+wechatVersion.replace(/\./g, "") >= 674 && +version[1] >= 12) {
window.scrollTo(
0,
Math.max(document.body.clientHeight, document.documentElement.clientHeight)
);
}
window.scrollTo(x-coord, y-coord),其中 window.scrollTo(0, clientHeight)恢复成原来的视口
iPhone X 系列安全区域适配问题
头部刘海两侧区域或者底部区域,出现刘海遮挡文字,或者呈现黑底或白底空白区域。iPhone X 以及它以上的系列,都采用刘海屏设计和全面屏手势。头部、底部、侧边都需要做特殊处理。才能适配 iPhone X 的特殊情况。具体操作为:viewport-fit meta 标签设置为 cover,获取所有区域填充。判断设备是否属于 iPhone X,给头部底部增加适配层:
auto
:此值不影响初始布局视图端口,并且整个 web 页面都是可查看的。contain
:视图端口按比例缩放,以适合显示内嵌的最大矩形。cover
:视图端口被缩放以填充设备显示。强烈建议使用safe area inset
变量,以确保重要内容不会出现在显示之外。
设置 viewport-fit 为 cover
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=yes, viewport-fit=cover"
/>
增加适配层
/* 适配 iPhone X 顶部填充*/
@supports (top: env(safe-area-inset-top)) {
body,
.header {
padding-top: constant(safe-area-inset-top, 40px);
padding-top: env(safe-area-inset-top, 40px);
padding-top: var(safe-area-inset-top, 40px);
}
}
/* 判断iPhoneX 将 footer 的 padding-bottom 填充到最底部 */
@supports (bottom: env(safe-area-inset-bottom)) {
body,
.footer {
padding-bottom: constant(safe-area-inset-bottom, 20px);
padding-bottom: env(safe-area-inset-bottom, 20px);
padding-top: var(safe-area-inset-bottom, 20px);
}
}
safe-area-inset-top, safe-area-inset-right, safe-area-inset-bottom, safe-area-inset-left safe-area-inset-*由四个定义了视口边缘内矩形的 top, right, bottom 和 left 的环境变量组成,这样可以安全地放入内容,而不会有被非矩形的显示切断的风险。对于矩形视口,例如普通的笔记本电脑显示器,其值等于零。对于非矩形显示器(如圆形表盘,iPhoneX 屏幕),在用户代理设置的四个值形成的矩形内,所有内容均可见。
其中 env() 用法为 env(