原文链接:https://geniuspeng.github.io/2017/08/24/mobile-issues/

扔了N久,还是捡回来了。好好弄一下吧。刚工作的时候挺忙的,后来不那么忙了,但是变懒了。
这一年大多数时间都在在做移动端的东东,做了之后才发现,同样是web前端,移动端的坑真的是深不可测,各种各样的,只有想不到,没有遇不到。在这里把最近踩过的坑整理一下。

No.1 大字体问题

首先,要解决的关键问题是如何为设备选择可视视口尺寸,采用理想视口尺寸作为可视视口尺寸,代码也十分简单,只需要将缩放比定为 1

1
<meta name="viewport" content="initial-scale=1,maximum-scale=1, minimum-scale=1">

之所以把它放在第一个也是因为这个印象最深,记得第一次做移动端html5页面的时候,啥都不懂,还在用px作为像素单位,当然这个px是相对的(关于px可参考css 长度单位知多少),然而在移动端使用px是相当不靠谱的,随随便便换一个大小不一样的设备,可能就会出现样式错乱。。。当然后来使用了rem,众所周知1rem=1 htmlFontSize,所以这里只要我们把html的字体大小事先定好,就可以基本上解决字体的适配问题。那么怎么选择这个htmlFontSize呢?
一般UI的设计稿都是3倍大小,这里已1080为例子(我拿到的一般都是1080的),实际上就是360px宽度的device,比如我自己习惯上想让1rem=100px(这里的px是实际像素,相当于设计稿的300像素),那么问题关键就在于,htmlFontSize的多少px正好对应设计稿的300px,那么根元素html的fontsize(设为fz)与设备实际宽度(设为dw)的对应关系应为:

1
2
dw/1080 = fz/300
fz = dw/3.6

这样,你的设备宽度用rem表示其实就是3.6rem,即使不是360px,也可以按比例来缩放,而设计稿中的每300px对应为1rem,使用rem布局,字体大小就可以随着设备宽度来自己调整。

1
2
3
4
5
6
7
8
function setRootFontSize() {
var r = document.documentElement;
var dw = r.getBoundingClientRect().width;
var fz = ~~( dw <= 720 ? dw : 720 ) / 3.6;
r.style.fontSize = fz + "px";
}
window.addEventListener("resize",setRootFontSize);
setRootFontSize();

这段代码基本上可以满足字体在移动端的自适应要求,可是如果用户主动把设备字体调大,也就是1px对应的大小变大,字体虽然px数不变,显示还是会变大,而有些比较复杂的h5页面字体稍微有些变化就会有问题,所以有时候还需要限定页面的字体大小不随设备字体的调整而影响,这时需要用到getComputedStyle这个方法,getComputedStyle是一个可以获取当前元素所有最终使用的CSS属性值(可参考获取元素CSS值之getComputedStyle方法熟悉)。通过对比算出来的fz和实际的realfz,对其进行相应缩放即可。

1
2
3
4
5
6
7
8
9
10
function setRootFontSize() {
var r = document.documentElement;
var dw = r.getBoundingClientRect().width;
var fz = ~~( dw <= 720 ? dw : 720 ) / 3.6;
r.style.fontSize = fz + "px";
var realfz = ~~(+window.getComputedStyle(document.getElementsByTagName("html")[0]).fontSize.replace('px','') * 10000) / 10000;
if(fz !== realfz){ r.style.fontSize = fz *(fz / realfz) + "px" }
}
window.addEventListener("resize",setRootFontSize);
setRootFontSize();

No.2 滚动时最底层(或顶层)回弹问题

这个坑应该做过移动端的都踩过(只是大多数情况根本不算坑,然而我要做的东西基本上都要禁掉这玩意),试过很多方法,都不是很理想,最终的解决方案就是禁用父级元素的滚动,手动模拟滚动条:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
var scroll = function(container, childSelector, style) {
if (!container || !container.length) return;
if (!(container instanceof $)) {
container = $(container);
}
if (container.css('position') === 'static') {
container.css('position', 'relative');
} var child = container.find(childSelector);
child.css({
'transform': 'translate3d(0px, 0px, 0px)',
'-webkit-transform': 'translate3d(0px, 0px, 0px)'
});
var childTop = 0; //距离容器顶部的距离
var conHeight = container.height(); //容器高度
var childHeight = child.height(); //子容器高度
var diffHeight = conHeight - childHeight; //父子容器高度差
var clientY = 0; //手指在当前对象上触摸时的坐标
//添加滚动条
var defaultStyle = {
width: '6px',
position: 'absolute',
'border-radius': '10000px',
'background-color': 'rgba(0, 0, 0, 0.3)',
'pointer-events': 'none',
};
$.extend(defaultStyle, style);
if (!defaultStyle.height) {
if (diffHeight < 0) {
defaultStyle.height = conHeight/childHeight * (conHeight);
} else {
defaultStyle.height = '0px';
}
}
if (!defaultStyle.top && !defaultStyle.right && !defaultStyle.bottom && !defaultStyle.left) {
defaultStyle.top = 0;
defaultStyle.right = 0;
}
var scrollBar = $('<section class="scroll-bar ui-scroll-bar"><section>');
scrollBar.css(defaultStyle);
container.find('.scroll-bar').remove();
container.append(scrollBar); //绑定前先移除事件
container.off('touchstart');
container.off('touchmove');
container.on('touchstart', function(e) {
e.preventDefault();
childTop = child.position().top;
clientY = e.targetTouches[0].clientY;
}); container.on('touchmove', function(e) {
if (diffHeight > 0) return;
var curClientY = e.targetTouches[0].clientY;
var tempTop = childTop + (curClientY - clientY);
if (tempTop <= diffHeight) {
tempTop = diffHeight;
}
if (tempTop >= 0) {
tempTop = 0;
}
child.css({
'transform': 'translate3d(0px, ' + tempTop + 'px, 0px)',
'-webkit-transform': 'translate3d(0px, ' + tempTop + 'px, 0px)'
});
scrollBar.css({
'transform': 'translate3d(0px, ' + (-tempTop* (conHeight/childHeight)) + 'px, 0px)',
'-webkit-transform': 'translate3d(0px, ' + (-tempTop* (conHeight/childHeight)) + 'px, 0px)'
})
});
}
scroll($('.parent'), '.child')

原理其实还是很简单,先计算一下滚动条的高度,然后按照比例去设置transform(还有很多可优化扩展的地方),第一个参数是父元素的zepto(或jquery)选择器对象,第二个参数是需要滚动的子元素包裹层,第三个是滚动条的样式(可选,有默认),需要把parent元素设置为overflow:hidden,child元素的height设置为auto。

No.3 Modal弹出层滚动带动底层一起滚动

这个也是只有移动端才有的坑,类似与一种穿透吧,手指在弹出层滑动的同时,如果底层有滚动条的话也会跟着一起滑动,解决方案:
css添加:

1
2
3
4
5
/*禁止modal底层滚动*/
body.dialog-open {
position: fixed;
width: 100%;
}

js添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var SCROLL_TOP = 0;
/*禁止modal带动底部滚动*/
function to(scrollTop){
document.body.scrollTop = document.documentElement.scrollTop = scrollTop;
}
function getScrollTop(){
return document.body.scrollTop || document.documentElement.scrollTop;
}
/*modal弹出时使用*/
SCROLL_TOP = getScrollTop();
document.body.classList.add('dialog-open');
document.body.style.top = -SCROLL_TOP + 'px';
/*modal关闭时使用*/
to(SCROLL_TOP);

No.4 tap事件穿透

这算是zepto的一个bug了,具体这个bug的源头还得追到zepto对于tap事件的模拟(参考也来说说touch事件与点击穿透问题),我后来用的解决方法也是参考这里来的,就是使用pointer-events这个属性,这里就不多介绍了,这里的第三种方法,使用fastclick库模拟click也可以完美解决移动端的点穿问题。

1
2
3
4
5
6
7
8
9
10
$('#closePopup').on('tap', function(e){
$('#popupLayer').hide();
$('#bgMask').hide(); $('#underLayer').css('pointer-events', 'none'); setTimeout(function(){
$('#underLayer').css('pointer-events', 'auto');
}, 400);
});

参考链接

文末福利:

福利一:前端,Java,产品经理,微信小程序,Python等10G资源合集大放送:https://www.jianshu.com/p/e8197d4d9880

福利二:微信小程序入门与实战全套详细视频教程。

【领取方法】

关注 【编程微刊】微信公众号:

回复【小程序demo】一键领取130个微信小程序源码demo资源。

回复【领取资源】一键领取前端,Java,产品经理,微信小程序,Python等资源合集10G资源大放送。

那些移动端web踩过的坑的更多相关文章

  1. 那些移动端web踩过的坑2

    原文链接:https://geniuspeng.github.io/2018/04/26/mobile-issues2/ 坑是无穷无尽的,嗯-长江后坑推前坑~~ 关于音频自动播放 H5的audio标签 ...

  2. 【饿了么】—— Vue2.0高仿饿了么核心模块&移动端Web App项目爬坑(三)

    前言:接着上一篇项目总结,这一篇是学习过程记录的最后一篇,这里会梳理:评论组件.商家组件.优化.打包.相关资料链接.项目github地址:https://github.com/66Web/ljq_el ...

  3. 移动端web开发的那些坑

    1.为非a列表项添加触感样式 通过js注册touchstart和touchend事件,添加触感class的方式, 有个坑,低版本的Android浏览器,经常触发不到touchend,需要再额外注册一个 ...

  4. web开发实战--弹出式富文本编辑器的实现思路和踩过的坑

    前言: 和弟弟合作, 一起整了个智慧屋的小web站点, 里面包含了很多经典的智力和推理题. 其实该站点从技术层面来分析的话, 也算一个信息发布站点. 因此在该网站的后台运营中, 富文本的编辑器显得尤为 ...

  5. 第八篇:web之前端踩的一些坑

    前端踩的一些坑   前端踩的一些坑 本节内容 事件代理 清除标签的所有事件 bootstrap的模态框自定义方法 ajax在django里面实现post提交 ajax提交数据嵌套 1.事件代理 之前写 ...

  6. 移动端h5页面的那些坑

    最近一直在写移动端页面,由于之前写移动端写的比较少,所以此次踩过许多坑.特此总结一下: 1.<input type='button'>背景色在ios中的兼容性,颜色发白 解决办法:在全局样 ...

  7. apicloud地图、即时通讯、人脸识别登录、以及平时踩过得坑

    apicloud技术浅谈 导语 apicloud 的学习也有一段时间了,这是我个人的一些经验,和踩过的坑,希望对大家能有一些帮助. apicloud的知识准备 apicloud 是一个用原生的思想搭建 ...

  8. H5 缓存机制浅析 移动端 Web 加载性能优化

    腾讯Bugly特约作者:贺辉超 1 H5 缓存机制介绍 H5,即 HTML5,是新一代的 HTML 标准,加入很多新的特性.离线存储(也可称为缓存机制)是其中一个非常重要的特性.H5 引入的离线存储, ...

  9. 简述移动端IM开发的那些坑:架构设计、通信协议和客户端

    1.前言 有过移动端开发经历的开发者都深有体会:移动端IM的开发,与传统PC端IM有很大的不同,尤其无线网络的不可靠性.移动端硬件设备资源的有限性等问题,导致一个完整的移动端IM架构设计和实现都充满着 ...

随机推荐

  1. android基于开源网络框架asychhttpclient,二次封装为通用网络请求组件

    网络请求是全部App都不可缺少的功能,假设每次开发都重写一次网络请求或者将曾经的代码拷贝到新的App中,不是非常合理,出于此目的,我希望将整个网络请求框架独立出来,与业务逻辑分隔开,这样就能够避免每次 ...

  2. opencv中的Java库

    opencv中有一个用Java编写的库,opencv2.4.4以上,在opencv解压包里路径:opencv/build/java/opencv.jar,再依据用户计算机位数选择,假设是32位计算机, ...

  3. 写了个去重复文件的 PHP 脚本,

    写了个去重复文件的 PHP 脚本点击打开链接 把各个零散网盘.邮箱和服务器上的文件,三台电脑上的文件收集在新硬盘里,然后清空了网络和电脑上的文件.才发现这个文件不能这里放点,那里存点,到时候不知道在哪 ...

  4. js12--块作用域函数作用域

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

  5. 3.1 Broker Configs 官网剖析(博主推荐)

    不多说,直接上干货! 一切来源于官网 http://kafka.apache.org/documentation/ 3.1 Broker Configs 3.1 broker配置 The essent ...

  6. DG查看恢复进度

    查看恢复进度 (1)查看进程的活动状态 V$MANAGED_STANDBY视图专用于显示物理Standby数据库相关进程的当前状态,该视图中的列也很有特点,查看进程状态时,通常我们会关注PROCESS ...

  7. CListCtrl 隔行变色

    响应消息 ON_NOTIFY(NM_CUSTOMDRAW, ListCtrl的ID, OnNMCustomdrawList) 实现函数OnNMCustomdrawList void CFinishWe ...

  8. ViewPager+Fragmrnt最简单结合方法

    Fragment和ViewPager 本博文系本菜鸟第一次博文展示,有错误之处请虽然提出 FragmentPagerAdapter 谷歌官方提供了这么一个adapter(FragmentPagerAd ...

  9. PHP中 “ . ” 和 “ ,”的区别

    在PHP中,“ . ”可以串接两个变量.而“ , ”却没什么用处.

  10. LeetCode_Construct Binary Tree from Preorder and Inorder Traversal

    一.题目 Construct Binary Tree from Preorder and Inorder Traversal My Submissions Given preorder and ino ...