web移动端常见问题(一)
1.1物理像素
- 产生原因:css样式的最小值是1px,不过这个1px只是代表css像素,在高清屏上展示的物理像素要>1(iphone6 1css像素=2物理像素。而iph6p则是1css像素=3物理像素)
- 解决思路:想要展示1物理像素,只能使用scale缩放
- android设备中dpr值有多种,可知的有0.75,1,1.5,1.75,2,2.5,2.75,3,4等
方法一:局部缩放
哪个元素要用到1物理像素,就设置哪个元素进行垂直方向的缩放。至于是缩放1/2还是1/3就看屏幕的DPR(物理像素与设备独立像素的比例值)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>时钟</title>
<style>
.box{
padding: 20px;
}
.line{
height: 1px;
background-color: #000;
}
@media screen and (-webkit-device-pixel-ratio:2){
.line{
transform: scaleY(0.5)
}
}
@media screen and (-webkit-device-pixel-ratio:3){
.line{
transform: scaleY(0.3333333)
}
}
</style>
</head>
<body>
<div class="box">
<div class="line"></div>
</div>
<div class="box">
<div style="height: 1px;background-color: #000;margin-top: 50px;"></div>
</div>
</body>
</html>
方法二:全局缩放
使用meta标签方法对全局所有元素进行缩放,但是会影响到所有的元素。需要缩放的元素使用px设置大小,而不需要缩放的元素使用rem设置大小,所以rem的值必须是缩放前2-3倍,这样才保证最终缩放值是1
<script>
// 获取设备的dpr
var dpr = window.devicePixelRatio
// 计算缩放系数
var scale = 1 / dpr
// 获取meta viewport标签并设置相应的属性值
var meta = document.createElement("meta")
meta.name = "viewport"
meta.content = "width=device-width,initial-scale=" + scale
document.querySelector('head').appendChild(meta)
// 设置html标签font-size的值
var styleNode = document.createElement("style")
// 计算根标签font-size的值 因为要缩放,所以1rem比常规要大
var w = document.documentElement.clientWidth * dpr / 16
styleNode.innerHTML = "html{font-size:"+ w +"px}"
// 将style插入到head中
document.querySelector('head').appendChild(styleNode)
</script>
效果对比:
2.自动识别手机号码
移动浏览器会自动将符合格式的文本识别为手机号码,并展示成一个a链接,点击后可以调用拨打电话的功能,例如
(有些浏览器默认就已经屏蔽了自动识别手机号码这个功能)
<p>18011757617</p>
如果想禁用这功能,需要添加meta标签,告诉浏览器不要识别此类文本
<meta name="format-detection" content="telephone=no">
如果你想在页面中调用拨号或其他功能,可以这样设置
<body>
<div><a href="tel:12306">买票热线</a></div>
<div><a href="mailto:819251937@qq.com">发邮件给xxx</a></div>
<div><a href="sms:10086">发短信给10086</a></div>
</body>
3.禁止复制、选中文本
移动端长按会选中文字,这是个默认事件
如果有需要的话,可以禁止这个功能。方法就是给元素设定css,让元素的文本无法被选中
.forbid_select{
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
}
如果全局都想禁止复制、选中文本,可以使用通配符所有标签都禁止选中文本,但是这样会让iOS的input框无法聚焦(用户可以点击input弹出输入窗口,但是输入框内没有焦点,无法输入文字),可以重新给input标签设置user-select属性为auto
注意:某些浏览器使用通配符会失效,例如alook浏览器,但是单独给某个div设置就可以
<head>
<style>
*{
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
user-select:none;
}
input{-webkit-user-select:auto;}
</style>
</head>
4.touch-callout
当在iOS上一直按住一个目标元素时,Safari会展示一个关于这个链接的callout信息。
例如长按图片时:
长按a链接时:
webkit-touch-callout属性允许禁用掉这一行为。
a,img{
-webkit-touch-callout: none;
}
5.双击放大
在一些手机浏览器中,对一个元素进行双击会自动放大这个元素,这个设计本身可以方便用户查看他们点中的元素,但是有时候你想关闭这个效果时(例如游戏模拟器,你快速点击了按钮,会放大页面,导致无法正常游戏),下面给出解决办法:
注意:以下测试只在ios13的浏览器上通过,其他浏览器未能测试
1.行内元素双击不会放大,这个可以略过。
2.块级元素(div,p,h)的宽度达到屏幕宽度的90%以上时,双击不再放大
3.行内块元素和img/canvas这个元素的的宽度达到屏幕宽度的98%以上时,双击不再放大
除了上面的例子,还可以通过事件监听,屏蔽双击放大效果,例如:
//以下任选其一
dom.ontouchstart = function(){
//无需阻止默认行为,只需要监听即可
}
dom.onclick = function(){
e.preventDefault()
}
dom.ondblclick = function(e){
e.preventDefault()
}
6.双指缩放
浏览器默认有一些手势缩放,例如双指缩放。可以通过事件屏蔽,阻止这种默认行为
为对应的dom元素添加touchmove事件监听,阻止默认事件之后,这这个元素的范围内不再有双指缩放行为。但是对顶层元素无效
document.documentElement.addEventListener('touchmove',function(e){
//对顶层元素无效
//在根元素上能触发事件打印,但是不能禁止双指缩放
e.preventDefault()
})
document.querySelector('.box').addEventListener('touchmove',function(e){
//能禁止元素的范围内的双指缩放
e.preventDefault()
console.log('move')
})
如果想要让整个页面都禁止双指缩放,可以就需要为页面设置一个最外层的容器,然后把所有的元素放在这个容器里面(高度由内容撑开),在这个元素上监听并禁止默认事件即可。但是会产生一个问题:那就是无法拖动滚动条。如果一个页面有滚动条又想双指缩放,就需要进一步判断触点数量,当触点数量大于1时,禁止默认事件
document.querySelector('.box').addEventListener('touchmove',function(e){
//屏幕内触点数量大于1时禁止元素的范围内的双指缩放
if(e.touches.length > 1){
e.preventDefault()
}
console.log('move')
})
但是仍有一个小问题,当页面滚动时,一些浏览器仍然可以双指缩放(有些浏览器页面到顶或者到底了仍然可以继续滑动,会有一个回弹效果,甚至有下拉自动加载的设定,当然这只是某些浏览器本身设定的问题,不代表所有的浏览器都这样)
通过判断触点数量已经足够屏蔽双指缩放了,如果连这点小毛病都不能忍受,只能往下看了
我们分析下原因:当我们单个手指进行上下滑动时,因为没有对单手指操作的touchmove事件进行'阻止默认事件',导致页面滚动条发生了滚动。在页面滚动的过程中,用户可以进行双指缩放。我们无法禁止这种默认行为,只能通过一些方法避免页面滚动条的滚动。
这里给出一个解决思路:
(1)既然页面滚动条会出现这样的事件,那就不使用页面的滚动跳,转而使用box元素自己的滚动条
.box{
height: 100%;
overflow: auto;
}
(2)在为box容器设定固定的宽高后,在这个容器上面滑动时,默认滑动的是box元素的滚动条,此时页面滚动条不会有反应。但是box元素的滚动条到顶或者到底后,接着强行滑动,某些浏览器就会操作页面的滚动条(IOS13火狐),为了阻止这种行为,需要对滚动条的距离与滑动方向进行判断,符合条件则禁止默认行为
<script>
function preventScale(node){
var x0 = null
var direction = null
//监听start事件 记录x0的位置
node.addEventListener('touchstart',function(e){
x0 = e.changedTouches[0].screenY
})
//监听move事件
node.addEventListener('touchmove',function(e){
//更新方向信息
(e.changedTouches[0].screenY - x0 > 0) ? direction='down' : direction='up'
//console.log(direction)
//console.log(node.scrollTop)
if(e.touches.length > 1){
//双指则禁止默认事件
e.preventDefault()
}else{
//到顶且下滑时 禁止默认事件
if(node.scrollTop <= 0 && direction === 'down'){
console.log('已经到顶,不要再下滑')
e.preventDefault()
}
console.log(node.scrollHeight)
var max = node.scrollHeight - node.offsetHeight
//到底且上滑时 禁止默认事件
if(node.scrollTop >= max && direction === 'up'){
console.log('已经到底,不要再上滑')
e.preventDefault()
}
}
console.log('box move')
})
}
preventScale(document.querySelector('.box'))
</script>
7.按钮圆角过圆
每个浏览器默认的元素样式是有差异的,比如苹果手机中为了美化按钮,默认给按钮添加了圆角,例如
<body>
<button>我是button元素</button>
<input type="button" value="我是input[type=button]元素">
</body>
解决办法:设置appearance属性为none,另外苹果的浏览器默认input元素都有圆角,需要手动去除
button{
-webkit-appearance: none;
}
input{
-webkit-appearance: none;
border-radius: 0;
}
实际项目中不会用到原生的按钮,因为太丑,一般会搭配UI框架,所以这里了解即可。
8.字体增强 font boosting
这个特性被称做「Text Autosizer」,又称「Font Boosting」、「Font Inflation」,是 Webkit 给移动端浏览器提供的一个特性。
当我们在手机上浏览网页时,很可能因为原始页面宽度较大,为了在手机屏幕中完整的显示整个页面,就会把页面缩小。(参见布局视口,一般默认980px)
但是页面是显示完整了,但是里面的内容却因为缩小了而看不清。
而 Font Boosting 特性在这时会自动将其中的文字字体变大,让人们方便的阅读页面中的文本。
解决办法一:设置完美视口,不让页面缩放,自然就不会有 font boosting
<meta name="viewport" content="width=device-width,initial-scale=1.0">
解决办法二:设置max-height
<style>
p{
max-height: 9999px;
}
</style>
9.点击高亮
在移动端,点击可点击元素时(a,button),android下会出现淡蓝色背景,IOS下会出现灰色背景
可以通过-webkt-tap-hightlight-color属性的设置,取消点击时出现的背景效果
*{
-webkit-tap-highlight-color: transparent;
}
10.滚动回弹
-webkit-overflow-scrolling 属性控制元素在移动设备上是否使用滚动回弹效果,页面的滚动条默认就是回弹的效果,如果不想要滚动回弹的效果,需要进行设置
div{
height: 300px;
overflow: auto;
-webkit-overflow-scrolling: touch;
}
这个css属性有2个值:
auto:使用普通滚动, 当手指从触摸屏上移开,滚动会立即停止(默认)
touch:使用具有回弹效果的滚动
不同的浏览器对不同元素的默认效果不一样,chrome的手机模式默认div是没有滚动回弹的,但是真机上面有。