移动端开发

# 移动端开发

### 1. 1px问题如何解决

#### ①伪类 + transform(比较完美)

> 原理是把原先元素的 border 去掉,然后利用 :before 或者 :after 重做 border ,并 transform 的 scale 缩小一半,原先的元素相对定位,新做的 border 绝对定位

##### 单条border

```

.hairlines li{

position: relative;

border:none;

}

.hairlines li:after{

content: '';

position: absolute;

left: 0;

background: #000;

width: 100%;

height: 1px;

-webkit-transform: scaleY(0.5);

transform: scaleY(0.5);

-webkit-transform-origin: 0 0;

transform-origin: 0 0;

}

```

##### 四条 border

```

.hairlines li{

position: relative;

margin-bottom: 20px;

border:none;

}

.hairlines li:after{

content: '';

position: absolute;

top: 0;

left: 0;

border: 1px solid #000;

-webkit-box-sizing: border-box;

box-sizing: border-box;

width: 200%;

height: 200%;

-webkit-transform: scale(0.5);

transform: scale(0.5);

-webkit-transform-origin: left top;

transform-origin: left top;

}

```

> 样式使用的时候,也要结合 JS 代码,判断是否 Retina 屏

```

if(window.devicePixelRatio && devicePixelRatio >= 2){

document.querySelector('ul').className = 'hairlines';

}

```

#### ②淘宝M站是通过 viewport + rem 实现的(适合新项目,方便)

> lib-flexible的库,而这个库就是用来解决H5页面终端适配的。

---

### 2.300ms延时问题

#### 产生原因

> 用户在 iOS Safari 里边点击了一个链接。由于用户可以进行双击缩放或者双击滚动的操作,当用户一次点击屏幕之后,浏览器并不能立刻判断用户是确实要打开这个链接,还是想要进行双击操作。因此,iOS Safari 就等待 300 毫秒,以判断用户是否再次点击了屏幕。

- [ ] **于是,300 毫秒延迟就这么诞生了。**

#### 解决方案

1. 禁用缩放

```

```

> 这个解决方案看似完美,但也带来一个明显的缺陷 —— 你必须完全禁用缩放来达到目的,而从移动端站点的可用性和可访问性来看,缩放是相当关键的一环。你很可能已经遇到过这个问题,即你想要放大一张图片或者一段字体较小的文本,却发现无法完成操作。

2. width=device-width Meta 标签

```

```

- [x] **没有双击缩放就没有 300 毫秒点击延迟。**

> 这一解决方案的另一个关键之处在于它只是去除了双击缩放,但用户仍可以使用双指缩放 (pinch to zoom)。可见,缩放功能并非被完全禁用,也就不存在可用性和可访问性的问题了。

这是一个令人振奋的方案,很好地提升了移动端站点的性能。当然,主要的问题是 width=device-width 这一优化目前仅被 Chrome 32 所支持。

3.指针事件

> touch-action 的默认值为 auto,将其置为 none 即可移除目标元素的 300 毫秒延迟。例如,下面的代码在 IE10 和 IE11 上移除了所有链接和按钮元素的点击延迟。

```

a[href], button {

-ms-touch-action: none; /* IE10 */

touch-action: none; /* IE11 */

}

```

> 你甚至可以在 元素上设置 touch-action: none,这就彻底禁用了双击缩放 (注:这也同时禁用了双指缩放,因此也会带来前面讨论到的可访问性和可用性问题。)

#### **目前的解决方案**

**①指针事件的 polyfill**

> 指针事件的 polyfill 比较多,以下列出比较流行的几个。

- Google 的 Polymer

- 微软的 HandJS

- @Rich-Harris 的 Points

> 为避免 300 毫秒点击延迟,我们主要关心这些 polyfill 是如何在非 IE 浏览器中模拟 CSS touch-action 属性的,这其实是一个不小的挑战。由于浏览器会忽略不被支持的 CSS 属性,唯一能够检测开发者是否声明了 touch-action: none 的方法是使用 JavaScript 去请求并解析所有的样式表。HandJS 也正是这么做的,但不管是从性能上来看还是其他一些复杂的方面,这都会遇到问题。

> Polymer 则是通过判断标签上的 touch-action 属性 (attribute),而非 CSS 代码。下面的代码展示了 Polymer 是如何在链接上模拟 CSS touch-action: none 属性的。

```

Google

```

**②FastClick**

> FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。简而言之,FastClick 在检测到 touchend 事件的时候,会通过 DOM 自定义事件立即触发一个模拟 click 事件,并把浏览器在 300 毫秒之后真正触发的 click 事件阻止掉。

```

window.addEventListener( "load", function() {

FastClick.attach( document.body );

}, false );

```

> attach() 方法虽可在更具体的元素上调用,直接绑定到 上可以确保整个应用都能受益。当 FastClick 检测到当前页面使用了基于 标签或者 touch-action 属性的解决方案时,会静默退出。可以说,这是真正的跨平台方案出来之前一种很好的变通方案。

**③Kendo UI Mobile**

> 最后一点,如果你是 Kendo UI Mobile 的用户,那你完全不必担心上述问题。一个自定义的点击延迟解决方案已经作为 Touch widget 的一部分打包好了。这个 touch widget 是一个跨平台的 API,帮助处理所有平台的用户点击事件,所有的 Kendo UI Mobile 组件都会默认调用它。

### 3.点击穿透问题

**什么是点击穿透?**

> 假如页面上有两个元素A和B。B元素在A元素之上。我们在B元素的touchstart事件上注册了一个回调函数,该回调函数的作用是隐藏B元素。我们发现,当我们点击B元素,B元素被隐藏了,随后,A元素触发了click事件。

> 这是因为在移动端浏览器,事件执行的顺序是**touchstart > touchend > click**。而click事件有300ms的延迟,当touchstart事件把B元素隐藏之后,隔了300ms,浏览器触发了click事件,但是此时B元素不见了,所以该事件被派发到了A元素身上。如果A元素是一个链接,那此时页面就会意外地跳转。

**解决方案**

(1)遮挡

> 由于 click 事件的滞后性,在这段时间内原来点击的元素消失了,于是便“穿透”了。因此我们顺着这个思路就想到,可以给元素的消失做一个fade效果,类似jQuery里的fadeOut,并设置动画duration大于300ms,这样当延迟的 click 触发时,就不会“穿透”到下方的元素了。

> 同样的道理,不用延时动画,我们还可以动态地在触摸位置生成一个透明的元素,这样当上层元素消失而延迟的click来到时,它点击到的是那个透明的元素,也不会“穿透”到底下。在一定的timeout后再将生成的透明元素移除

(2)pointer-events

pointer-events是CSS3中的属性,它有很多取值,有用的主要是auto和none,其他属性值为SVG服务。

|取值 | 含义|

|:---:|:-----:|

auto | 效果和没有定义 pointer-events 属性相同,鼠标不会穿透当前层。

none | 元素不再是鼠标事件的目标,鼠标不再监听当前层而去监听下面的层中的元素。但是如果它的子元素设置了pointer-events为其它值,比如auto,鼠标还是会监听这个子元素的。

- [ ] 因此解决“穿透”的办法就很简单,demo如下

```

$('#closePopup').on('tap', function(e){

$('#popupLayer').hide();

$('#bgMask').hide();

$('#underLayer').css('pointer-events', 'none');

setTimeout(function(){

$('#underLayer').css('pointer-events', 'auto');

}, 400);

});

```

(3)fastclick

```

FastClick.attach(document.body);

```

> 从此所有点击事件都使用click,不会出现“穿透”的问题,并且没有300ms的延迟。

### 4.移动端兼容问题

1. IOS移动端click事件300ms的延迟相应(上面已有解决方案)

2. 一些情况下对非可点击元素(label,span)监听click事件,iso下不会触发!

> css增加cursor:pointer就搞定了

3. h5底部输入框被键盘遮挡问题

> h5页面当输入框在最底部,点击软键盘后输入框会被遮挡。可采用如下方式解决

```

var oHeight = $(document).height(); //浏览器当前的高度

$(window).resize(function(){

if($(document).height() < oHeight){

$("#footer").css("position","static");

}else{

$("#footer").css("position","absolute");

}

});

```

4. 不让 Android 手机识别邮箱

```

 

```

5. 禁止 iOS 识别长串数字为电话

```

```

6. 禁止 iOS 弹出各种操作窗口

```

-webkit-touch-callout:none

```

7. 消除 transition 闪屏

```

-webkit-transform-style: preserve-3d; /*设置内嵌的元素在 3D 空间如何呈现:保留 3D*/

-webkit-backface-visibility: hidden; /*(设置进行转换的元素的背面在面对用户时是否可见:隐藏)*/

```

8. iOS 系统中文输入法输入英文时,字母之间可能会出现一个六分之一空格

```

可以通过正则去掉 this.value = this.value.replace(/\u2006/g, '');

```

9. 禁止ios和android用户选中文字

```

-webkit-user-select:none

```

10. CSS动画页面闪白,动画卡顿

> 解决方法:

- 1.尽可能地使用合成属性transform和opacity来设计CSS3动画,不使用position的left和top来定位

- 2.开启硬件加速

```

-webkit-transform: translate3d(0, 0, 0);

-moz-transform: translate3d(0, 0, 0);

-ms-transform: translate3d(0, 0, 0);

transform: translate3d(0, 0, 0);

```

11. fixed定位缺陷

> - ios下fixed元素容易定位出错,软键盘弹出时,影响fixed元素定位

> - android下fixed表现要比iOS更好,软键盘弹出时,不会影响fixed元素定位

> - ios4下不支持position:fixed

> - 解决方案: 可用iScroll插件解决这个问题

12. localStorage/sessionStorage

> PC端,这两个API在低版本的IE下是没有,所以是需要用try..catch包裹的.

> 在移动端,我刚刚开始是不加的,所测试的手机也没问题.但是现在很多浏览器有无痕模式,这个模式下,localStorage相关的API时禁用的.所以使用时,还是要保证代码的健壮性

13. 在ios和andriod中,audio元素和video元素在无法自动播放

> 应对方案:触屏即播

```

$('html').one('touchstart',function(){

audio.play()

})

```

14. ios下取消input在输入的时候英文首字母的默认大写

```

```

15. 阻止旋转屏幕时自动调整字体大小

```

html, 

body, 

form, 

fieldset, 

p, 

div, 

h1, 

h2, 

h3, 

h4, 

h5, 

h6 {

-webkit-text-size-adjust:none;

}

```

16. Input 的placeholder会出现文本位置偏上的情况

```

input 的placeholder会出现文本位置偏上的情况:PC端设置line-height等于height能够对齐,

而移动端仍然是偏上,解决是设置line-height:normal

```

17. 往返缓存问题

```

点击浏览器的回退,有时候不会自动执行js,特别是在mobilesafari中。这与往返缓存(bfcache)有关系。

解决方法 :window.onunload = function(){};

```

18. 在移动端修改难看的点击的高亮效果,iOS和安卓下都有效

```

* {-webkit-tap-highlight-color:rgba(0,0,0,0);}

```

> 不过这个方法在现在的安卓浏览器下,只能去掉那个橙色的背景色,点击产生的高亮边框还是没有去掉,有待解决!

19. ios滚动不流畅

```

overflow: scroll;

-webkit-overflow-scrolling: touch;/* 解决ios滑动不流畅问题 */

```

20. h5移动端,当input输入框唤起虚拟键盘时,fixed定位的元素带来的布局问题

- 问题1:H5 web 移动端,input输入框唤起键盘时。fixed定位好的元素跟随页面滚动, fixed属性失效,满屏任性横飞。

- 问题2:使用第三方输入法的ios手机,会出现键盘弹出延迟,导致普通布局的输入框(input/textarea等) 位置靠下的元素被键盘挡住

```

// CSS

.scrollWrapper {

position: absolute;

left: 0;

right: 0;

bottom: 0;

top:0;

}

bottomInput {

position: absolute;

bottom:0;

left:0;

right: 0;

}

// HTML

// javascript

// 在输入框获取焦点, 键盘弹起后, 真的是一行代码

var interval = setInterval(function() {

document.body.scrollTop = document.body.scrollHeight

}, 100)

```

### 5.css3动画

```

animation: name duration timing-function delay iteration-count direction fill-mode play-state;

```

**同时要配合** @keyframes

```

@keyframes name {

form {

}

to {

}

}

```

- [x] animation 参数说明

- name

> 与 @keyframes 后 name 一致,动画名称

- duration

> 一个动画持续的事件,要带单位 s/ms

- timing-function

> 动画的速度曲线,又称之为缓动类型。

> 1. liner 动画从头到位速度相同,一般用于平滑的效果

> 1. ease 默认值,逐渐变慢

> 1. ease-in 加速

> 1. ease-out 减速

> 1. ease-in-out 先加速再减速

> 1. cubic-bezier 自定义贝塞尔曲线

> 1. 除此之外还有个重要的值,step-start,可以实现一帧一帧播放的效果,在特殊场景有更好的效果

- delay

> 动画延迟执行的时间,需要单位 s/ms

- iteration-count

> 动画迭代的次数,可以设置具体的数值,默认值1,使用 infinite 关键字可以实现动画不间断播放

- direction

> 动画的前进方向,默认为 normal,代表正向播放,使用值 alternate,可以实现动画完成时的倒带效果

- fill-mode

> 填充模式,指的是动画的每个周期间的状态,通常使用默认值 none [这篇文章有很好的解释](http://www.zhangxinxu.com/wordpress/2013/06/css3-animation-%E7%82%B9%E7%82%B9%E7%82%B9%E7%AD%89%E5%BE%85%E6%8F%90%E7%A4%BA%E6%95%88%E6%9E%9C/)

- play-state

> 控制动画的运行状态,默认为 running,可选值 paused

- [ ] 例子demo

- 外层圆圈

```

.circle {

...

animation: scale 2s ease infinite normal;

@keyframes scale {

0% {

transform: scale(0);

opacity: 0;

}

8% {

transform: scale(.5);

opacity: 1;

}

100% {

transform: scale(2);

opacity: 0;

}

}

```

- 内层圆圈

```

.circle1 {

...

animation: scaleout 1s ease-in-out infinite alternate;

}

@keyframes scaleout {

0% {

transform: scale(1);

}

100% {

transform: scale(2);

}

}

```

```

动画1

正在等待司机接单...

动画2

// css

body {

padding: 100px;

}

span {

display: inline-block;

}

.wrap {

position: relative;

float: left;

width: 200px;

height: 200px;

margin: 100px;

}

.circle {

position: absolute;

width: 200px;

height: 200px;

background: radial-gradient(#fff, #54bfd0);

border-radius: 50%;

-webkit-animation: scale 2s ease infinite normal;

-moz-animation: scale 2s ease infinite normal;

-o-animation: scale 2s ease infinite normal;

animation: scale 2s ease infinite normal;

}

.circle1 {

position: absolute;

top: 0;

right: 0;

bottom: 0;

left: 0;

margin: auto;

width: 100px;

height: 100px;

border-radius: 50%;

/*background: #076d7d;*/

background: radial-gradient(#fff, #076d7d);

-webkit-animation: scaleout 1s ease-in-out infinite alternate;

-moz-animation: scaleout 1s ease-in-out infinite alternate;

-o-animation: scaleout 1s ease-in-out infinite alternate;

animation: scaleout 1s ease-in-out infinite alternate;

}

.text {

position: absolute;

top: 0;

right: 0;

bottom: 0;

left: 0;

margin: auto;

/*width: 150px;

height: 20px;*/

text-align: center;

line-height: 200px;

}

.animation2 {

top: 0;

right: 0;

bottom: 0;

left: 0;

width: 100px;

height: 100px;

margin: auto;

-webkit-animation: animation2 4s linear infinite normal;

-moz-animation: animation2 4s linear infinite normal;

-o-animation: animation2 4s linear infinite normal;

animation: animation2 4s linear infinite normal;

}

.animation20 {

}

@keyframes animation2 {

0% {

/*transform: scale(1);*/

/*opacity: 1;*/

}

100% {

transform: scale(4);

opacity: 0;

}

}

.animation21 {

-webkit-animation-delay: 1s;

-moz-animation-delay: 1s;

-o-animation-delay: 1s;

animation-delay: 1s;

}

.animation22 {

-webkit-animation-delay: 2s;

-moz-animation-delay: 2s;

-o-animation-delay: 2s;

animation-delay: 2s;

}

.animation23 {

-webkit-animation-delay: 3s;

-moz-animation-delay: 3s;

-o-animation-delay: 3s;

animation-delay: 3s;

}

.fixedcirle {

position: absolute;

top: 0;

right: 0;

bottom: 0;

left: 0;

width: 100px;

height: 100px;

margin: auto;

border-radius: 50%;

/*background: radial-gradient(rgba(255, 0, 0, 0), #076d7d);*/

background: #076d7d;

}

@-webkit-keyframes scale {

0% {

-webkit-transform: scale(0);

opacity: 0;

8% {

-webkit-transform: scale(.5);

opacity: 1;

}

100% {

-webkit-transform: scale(2);

opacity: 0;

}

}

@-moz-keyframes scale {

0% {

-moz-transform: scale(0);

opacity: 0;

8% {

-moz-transform: scale(.5);

opacity: 1;

}

100% {

-moz-transform: scale(2);

opacity: 0;

}

}

@-o-keyframes scale {

0% {

-o-transform: scale(0);

opacity: 0;

8% {

-o-transform: scale(.5);

opacity: 1;

}

100% {

-o-transform: scale(2);

opacity: 0;

}

}

@keyframes scale {

0% {

transform: scale(0);

opacity: 0;

8% {

transform: scale(.5);

opacity: 1;

}

100% {

transform: scale(2);

opacity: 0;

}

}

@-webkit-keyframes scaleout {

0% {

-webkit-transform: scale(1);

100% {

-webkit-transform: scale(2);

/*opacity: 0.5;*/

}

}

@-moz-keyframes scaleout {

0% {

-moz-transform: scale(1);

100% {

-moz-transform: scale(2);

/*opacity: 0.5;*/

}

}

@-o-keyframes scaleout {

0% {

-o-transform: scale(1);

100% {

-o-transform: scale(2);

/*opacity: 0.5;*/

}

}

@keyframes scaleout {

0% {

transform: scale(1);

100% {

transform: scale(2);

/*opacity: 0.5;*/

}

}

```

### 6.丢帧问题

> 回流与重绘的知识: 浏览器会解析三个东西:HTML、Javascript、CSS。

> 浏览器首先会根据HTML生成DOM Tree,其次会根据CSS生成CSS Rule Tree,javascript可以通过DOM API与CSS API操作DOM Tree与CSS Rule Tree,从而引起页面变化。

> 浏览器解析结束会通过DOM Tree与CSS Rule Tree形成render tree,只有display不为none的元素才会形成render Tree,render Tree形成后浏览器会调用GUI绘制页面,在此之前做的一件事情便是layout或者说reflow。上面的描述简单而言可以分为以下流程:

> l 生成DOM树

> l 计算CSS样式

> l 构建render tree

> l reflow,定位元素位置大小

> l 绘制页面

> 在这个过程中,**若是javascript动态改变DOM Tree便会引起reflow**

> 页面中的元素改变,只要不影响尺寸,比如只是颜色改变只会引起repaint不会引起回流

> 否则,reflow不可避免,这个时候便需要重新计算形成render Tree

> reflow耗用的系统资源较大,**DOM Tree** 中受到影响的节点皆会reflow,然后影响其子节点最坏的情况是所有节点reflow,该问题引发的现象便是低性能的电脑风扇不停的转,手机变得很热,并且非常耗电,以下操作可能引起reflow

> l 操作dom结构

> l 动画

> l DOM样式修改

> l 获取元素尺寸的API

#### 重新认识Timeline

[详细讲解Timeline](http://www.cnblogs.com/yexiaochai/p/4314260.html)

![Timeline](https://images0.cnblogs.com/blog2015/294743/201503/051323576809111.png)

#### 丢帧

> 浏览器一次的刷新约16ms

> 如果中间有一次的操作比如渲染的时间大于了16ms而导致浏览器没有来得及绘制,那么那次的操作便失效了,这个就是所谓的丢帧。

### 7.移动端性能优化

![优化方向](//upload-images.jianshu.io/upload_images/81969-2ccfb67da09f1099.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

[使用requestAnimationFrame()优化JavaScript动画性能](http://www.webhek.com/post/using-requestanimationframe.html)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容