<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/rss.xsl" type="text/xsl"?>
<rss version="2.0">
  <channel>
    <title>IT瘾html5推荐</title>
    <link>https://itindex.net/tags/html5</link>
    <description>IT社区推荐资讯 - ITIndex.net</description>
    <language>zh</language>
    <copyright>https://itindex.net/</copyright>
    <generator>https://itindex.net/</generator>
    <docs>http://backend.userland.com/rss</docs>
    <image>
      <url>https://itindex.net/images/logo.gif</url>
      <title>IT社区推荐资讯 - ITIndex.net</title>
      <link>https://itindex.net/tags/html5</link>
    </image>
    <item>
      <title>连肝7个晚上，总结了计算机网络的知识点！（共66条）</title>
      <link>https://itindex.net/detail/60776-%E6%99%9A%E4%B8%8A-%E8%AE%A1%E7%AE%97%E6%9C%BA-%E7%BD%91%E7%BB%9C</link>
      <description>&lt;h2&gt;前言&lt;/h2&gt;
 &lt;p&gt;计算机网络知识，是面试常考的内容，在实际工作中也常常会涉及到。&lt;/p&gt;
 &lt;p&gt;最近总结了66条计算机网络相关的知识点，大家一起看一下吧：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200501" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;1.比较http 0.9和http 1.0&lt;/h3&gt;
 &lt;ol&gt;
  &lt;li&gt;http0.9只是一个简单的协议，只有一个GET方法，没有首部，目标用来获取HTML。&lt;/li&gt;
  &lt;li&gt;HTTP1.0协议大量内容：首部，响应码，重定向，错误，条件请求，内容编码等。&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;http0.9流程：&lt;/p&gt;
 &lt;blockquote&gt;客户端，构建请求，通过DNS查询IP地址，三次握手建立TCP连接，客户端发起请求，服务器响应，四次挥手，断开TCP连接。（与服务器只有一个来回）&lt;/blockquote&gt;
 &lt;p&gt;http1.0流程：&lt;/p&gt;
 &lt;blockquote&gt;客户端，构建请求，通过DNS查询IP地址，三次握手建立TCP连接，客户端发起请求，服务器响应，四次挥手，断开TCP连接。（与服务器有两个来回）&lt;/blockquote&gt;
 &lt;p&gt;因为不足缺陷，就有了http1.1。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200503" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;2.关于http1.1以及http2&lt;/h3&gt;
 &lt;p&gt;http1.1中浏览器再也不用为每个请求重新发起TCP连接了，增加内容有：缓存相关首部的扩展，OPTIONS方法，Upgrade首部，Range请求，压缩和传输编码，管道化等。但还是满足不了现在的web发展需求，so，就有了http.2版本。&lt;/p&gt;
 &lt;p&gt;http2解决了（管道化特性可以让客户端一次发送所有的请求，但是有些问题阻碍了管道化的发展，即是某个请求花了很长时间，那么  &lt;strong&gt;队头阻塞&lt;/strong&gt;会影响其他请求。）http中的队头阻塞问题。&lt;/p&gt;
 &lt;p&gt;使用http2会比http1.1在使用TCP时，用户体验的感知多数延迟的效果有了量化的改善，以及提升了TCP连接的利用率（并行的实现机制不依赖与服务器建立多个连接）&lt;/p&gt;
 &lt;p&gt;所以需要学习http2，了解更过的内容来掌握计算机网咯。&lt;/p&gt;
 &lt;p&gt;对于http2，你可以来运行一个http2的服务器，获取并安装一个http2的web服务器，下载并安装一张  &lt;strong&gt;TLS&lt;/strong&gt;证书，让浏览器和服务器通过http2来连接。（从数字证书认证机构申请一张证书）。&lt;/p&gt;
 &lt;p&gt;了解http2的协议，先让我们了解一下web页面的请求，就是用户在浏览器中呈现的效果，发生了些什么呢？&lt;/p&gt;
 &lt;blockquote&gt;资源获取的步骤：&lt;/blockquote&gt;
 &lt;p&gt;把待请求URL放入队列，判断URL是否已在请求队列，否的话就结束，是的话就判断请求域名是否DNS缓存中，没有的话就解析域名，有的话就到指定域名的TCP连接是否开启，没有的话就开启TCP连接，进行HTTPS请求，初始化并完成TLS协议握手，向页面对应的URL发送请求。&lt;/p&gt;
 &lt;blockquote&gt;接收响应以及页面渲染步骤：&lt;/blockquote&gt;
 &lt;p&gt;接收请求，判断是否HTML页面，是就解析HTML，对页面引用资源排优先级，添加引用资源到请求队列。（如果页面上的关键资源已经接收到，就开始渲染页面），判断是否有还要继续接收资源，继续解析渲染，直到结束。&lt;/p&gt;
 &lt;h3&gt;3.HTTP的几种请求方法用途&lt;/h3&gt;
 &lt;p&gt;第一种  &lt;code&gt;GET&lt;/code&gt;方法：发送一个请求来获取服务器上的某一些资源。&lt;/p&gt;
 &lt;p&gt;第二种  &lt;code&gt;POST&lt;/code&gt;方法：向URL指定的资源提交数据或附加新的数据。&lt;/p&gt;
 &lt;p&gt;第三种  &lt;code&gt;PUT&lt;/code&gt;方法：跟POST方法一样，可以向服务器提交数据，但是它们之间也所有不同，PUT指定了资源在服务器的位置，而POST没有哦。&lt;/p&gt;
 &lt;p&gt;第四种  &lt;code&gt;HEAD&lt;/code&gt;方法：指请求页面的首部。&lt;/p&gt;
 &lt;p&gt;第五种  &lt;code&gt;DELETE&lt;/code&gt;方法：删除服务器上的某资源。&lt;/p&gt;
 &lt;p&gt;第六种  &lt;code&gt;OPTIONS&lt;/code&gt;方法：它用于获取当前URL所支持的方法，如果请求成功，在Allow的头包含类似  &lt;code&gt;GET,POST&lt;/code&gt;等的信息。&lt;/p&gt;
 &lt;p&gt;第七种  &lt;code&gt;TARCE&lt;/code&gt;方法：用于激发一个远程的，应用层的请求消息回路。&lt;/p&gt;
 &lt;p&gt;第八种  &lt;code&gt;CONNECT&lt;/code&gt;方法：把请求连接转换到TCP/TP通道。&lt;/p&gt;
 &lt;h3&gt;4.从浏览器地址栏输入url到显示页面的步骤&lt;/h3&gt;
 &lt;p&gt;简单说说，浏览器根据请求的url交给dns域名解析，查找真正的ip地址，向服务器发起请求；服务器交给后台处理后，返回数据，浏览器会接收到文件数据，比如，html,js，css，图像等；然后浏览器会对加载到的资源进行语法解析，建立相应的内部数据结构；载入解析到得资源文件，渲染页面，完成显示页面效果。&lt;/p&gt;
 &lt;p&gt;不够清楚明白码？&lt;/p&gt;
 &lt;p&gt;那就再次详细一下，咳咳，从浏览器接收url，开始进行网络请求线程，发出一个完整的HTTP请求，从服务器端接收请求到对应的后台接收到请求，然后是后台和前台的http交互；其中的缓存问题（http的缓存），浏览器接收到http数据包后的解析流程，css的可视化格式模型，js引擎解析过程等；其他呈现页面效果。&lt;/p&gt;
 &lt;p&gt;：这里就需要你对浏览器内核的理解：其中主要的渲染引擎和JS引擎，这里了解一下你对浏览器内核的理解。&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;渲染引擎，是负责取得网页的内容，整理信息，以及计算网页的显示方式，然后输出到显示器上。&lt;/li&gt;
  &lt;li&gt;JS引擎是用于解析和执行javascript来实现网页的动态效果。&lt;/li&gt;
&lt;/ol&gt;
 &lt;blockquote&gt;浏览器的内核的不同对于网页的语法解释会有不同，所以渲染的效果也不相同。其实最开始渲染引擎和JS引擎是没有区分明确的，不过后来JS引擎越来越独立，so，内核就倾向于渲染引擎。  &lt;p&gt;对于资源请求/获取,资源响应/页面渲染，会给网络带宽和设备资源带来压力，这个时候就会考虑到web的性能优化。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h3&gt;5.web的性能优化&lt;/h3&gt;
 &lt;p&gt;其中里面的  &lt;strong&gt;性能关键：&lt;/strong&gt;&lt;/p&gt;
 &lt;blockquote&gt;什么是数据包  &lt;br /&gt;数据包（IP数据包），指封装在固定结构的一系列字节，它定义了数据包的长度，传输的细节，以及其他与TCP相关的信息。&lt;/blockquote&gt;
 &lt;p&gt;延迟：指IP数据包从一个网络端点到另一个网络端点所花费的时间。（所花费时间在于往返时延，是延迟的时间的两倍）&lt;/p&gt;
 &lt;p&gt;带宽：只要带宽没有饱和，两个网络端点的连接会一次处理尽可能多的数据量（所以带宽可能会成为性能的瓶颈）&lt;/p&gt;
 &lt;p&gt;建立连接时间：在客户端和服务器之间建立连接往返数据（三次握手）&lt;/p&gt;
 &lt;p&gt;TCP三次握手过程：客户端向服务器发起一个SYN包，服务器端返回对应的SYN的ACK响应以及新的SYN包，然后客户端返回对应的ACK。（在客户端和服务器之间建立正常的TCP网络连接时，客户端首先发出一个SYN消息，服务器使用SYN+ACK应答表示接收了这个消息，最后客户端再以ACK消息响应。）&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200502" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;SYN是同步序列编号，是TCP/IP建立连接时使用的握手信息。  &lt;br /&gt;ACK是确认字符，在数据通信中，接收站发给发送站的一种传输类控制字符。表示发来的数据已确认接收无误。在TCP/IP协议中，如果接收方成功的接收到数据，那么会回复一个ACK数据。通过ACK信号有自己固定的格式，长度大小，由接收方回复给发送方。&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt;详解三次握手&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;第一次握手，建立连接时，客户端发送SYN包到服务器，并进入SYN_SENT状态，等待服务器确认，其中SYN就是同步序列编号。&lt;/p&gt;
 &lt;p&gt;第二次握手，服务器收到SYN包，必须确认客户的SYN，同时自己也发送一个SYN包，即是SYN+ACK包，此时服务器进入SYN_RECV状态。&lt;/p&gt;
 &lt;p&gt;第三次握手，客户端收到服务器的SYN+ACK包，向服务器发送确认包ACK，此包发送完毕，客户端和服务器进入ESTABLISHED（TCP连接成功）状态，完成三次握手。&lt;/p&gt;
 &lt;blockquote&gt;完成三次握手，客户端与服务器开始传送数据。&lt;/blockquote&gt;
 &lt;p&gt;TLS协商时间（TLS会造成额外的往返传输）&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;客户端发起https连接，需要进行传输层安全协议协商&lt;/li&gt;
  &lt;li&gt;TLS用来取代安全套接层SSL&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;除了网络，还有  &lt;strong&gt;页面内容本身或服务器性能&lt;/strong&gt;，如首字节时间TTFB，内容下载时间，开始渲染时间，文档加载完成的时间等。&lt;/p&gt;
 &lt;blockquote&gt;那么什么是TTFB，它是指客户端从开始定位到web页面，至接收到主体页面响应的第一字节所耗费的时间。它是测量：从浏览器发起请求至收到其第一字节之间的耗时。  &lt;p&gt;内容下载时间是等同于被请求资源的最后字节到达时间。&lt;/p&gt;
  &lt;p&gt;开始渲染时间，从客户看到空白页面的时长。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;h4&gt;5.1web性能优化技术（减少客户端网络延迟和优化页面渲染性能来提升web性能）&lt;/h4&gt;
 &lt;p&gt;优化技术：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;DNS查询优化&lt;/li&gt;
  &lt;li&gt;客户端缓存&lt;/li&gt;
  &lt;li&gt;优化TCP连接&lt;/li&gt;
  &lt;li&gt;避免重定向&lt;/li&gt;
  &lt;li&gt;网络边缘的缓存&lt;/li&gt;
  &lt;li&gt;条件缓存&lt;/li&gt;
  &lt;li&gt;压缩和代码极简化&lt;/li&gt;
  &lt;li&gt;图片优化&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;6. http1.1&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;改进持久连接和CDN域名的分片机制&lt;/li&gt;
  &lt;li&gt;不成熟的http管道化&lt;/li&gt;
  &lt;li&gt;提供虚拟主机支持&lt;/li&gt;
  &lt;li&gt;对动态生成的内容完美支持&lt;/li&gt;
  &lt;li&gt;引入cookie以及安全机制&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;对于http1的问题，迎来了http2。其中http1的问题：&lt;/p&gt;
 &lt;p&gt;队头阻塞，大多数情况下，浏览器会希望同时获取许多资源，但http1未提供机制来同时请求这些资源，如果仅是使用一个连接，需要发起请求，等待响应，然后才能发起下一个请求。&lt;/p&gt;
 &lt;p&gt;在http1中要给特性为管道化，可以允许一次发送一组请求，但是需要按照发送顺序依次接收响应。所以在请求应答过程中，如发生什么情况，剩下的工作都会被阻塞，这就是“队头阻塞”（阻塞在那次请求应答发生错误），阻碍网络传输和web页面的渲染，指导失去响应。&lt;/p&gt;
 &lt;p&gt;低效的TCP利用，TCP协议作为最可靠的协议之一，其核心是拥塞窗口。&lt;/p&gt;
 &lt;blockquote&gt;拥塞窗口，是卫星通信在因特网中防止通信拥塞的一种措施，它是在发端采用了一种“拥塞避免”算法和“慢速启动”算法相结合的机制。“拥塞窗口”就是“拥塞避免”的窗口，它是一个装在发送端的可滑动窗口，窗口的大小是不超过接收端确认通知的窗口。&lt;/blockquote&gt;
 &lt;p&gt;拥塞窗口指在接收方确认数据包之前，发送方可以发送的TCP包的数据。（如拥塞窗口指定为1的情况，那么发送方就发出1哥数据包之后，只有接收方确认了那个发出的数据包，才能发送下一个）&lt;/p&gt;
 &lt;p&gt;拥塞控制能防止过多的数据注入到网络中，用于避免网络过载，TCP中可以通过  &lt;strong&gt;慢启动&lt;/strong&gt;探索当前连接对应拥塞窗口的合适大小。即发送者发送数据的时候并非一开始注入大量数据到网络中，而是发送一个数据包进行测试，当得到确认回复后，额外发送一个未确认包。&lt;/p&gt;
 &lt;p&gt;这意味着得到一个确认回复，可以发送两个数据包，得到两个确认回复，可以发送四个数据包，以几何形式增长很快到达协议规定的拥塞窗口大小（发包数上限），这时候连接进入  &lt;strong&gt;拥塞避免阶段&lt;/strong&gt;，这种机制需要往返几次才能得知最佳拥塞窗口大小，但往返几次所需的时间成本不可忽略。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;拥塞窗口的大小取决于网络的拥塞程度，并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口。如果再考虑到接收方的接收能力，那么发送窗口还可能小于拥塞窗口。&lt;/li&gt;
  &lt;li&gt;发送方控制拥塞窗口的原则是：只要网络没有出现拥塞，拥塞窗口就再增大一些，以便把更多的分组发送出去。但只要网络出现拥塞，拥塞窗口就减少一些，以减少注入到网络中的分组数。&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;tcp中的慢启动概念，是用来探索当前连接对应拥塞窗口的合适大小。用来弄清楚新连接当前的网络情况。“慢速启动”是在连接建立后，每收到一个来自收端的确认，就控制窗口增加一个段值大小，当窗口值达到“慢速启动”的限值后，慢速启动便停止工作，避免了网络发生拥塞。  &lt;p&gt;TCP传输控制协议的设计思路是，对假设情况很保守情况下，能够公平对待同一网络的不同流量的应用，它的避免拥塞机制被设计城即使在最差的网络情况下也可以起作用。&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;p&gt;臃肿的消息首部，HTTP/1.1能压缩请求内容，但是消息首部却不能压缩。它可能占据请求的绝大部分（也可能是全部）也是比较常见了。（在这里如果能压缩请求首部，把请求变得更小，就能够缓解带宽压力了，降低系统的总负载）&lt;/p&gt;
 &lt;p&gt;受限的优先级设置，即如果浏览器针对指定域名开启多个socket请求，若web页面某些资源会比另外一些资源重要，会加重资源的排队效应，会延迟请求其他的资源，优先级高的资源先获取，优先级低的资源会在资源高的资源处理完成，（在处理过程中，浏览器不会发起新的资源请求）等待高的完成后再发起请求，(这就会让总的页面下载时间延长)。&lt;/p&gt;
 &lt;blockquote&gt;在请求优先级高的资源的时间区间内浏览器并不会发起优先级较低的新请求&lt;/blockquote&gt;
 &lt;p&gt;小结：HTTP1.1慢启动影响资源首次加载速度，TCP建立连接后，会开始请求传输，开始比较慢，然后不断加快，为了防止出现网络拥堵，会让页面的首次渲染时间变长。开始多个tcp，如出现网络下降，无法识别资源的优先级，会出现竞态问题。&lt;/p&gt;
 &lt;h3&gt;7.如何进行网站性能优化&lt;/h3&gt;
 &lt;ol&gt;
  &lt;li&gt;内容方面，减少Http请求（合并文件，css精灵，inline Image)，减少DNS查询（DNS缓存，将资源分布到合适的数量的主机名），减少DOM元素的数量。&lt;/li&gt;
  &lt;li&gt;Cookie方面，可以减少Cookie的大小。&lt;/li&gt;
  &lt;li&gt;css方面，将样式表放到页面顶部；不使用css表达式；使用   &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;不使用   &lt;code&gt;@import&lt;/code&gt;；可将css从外部引入；压缩css。&lt;/li&gt;
  &lt;li&gt;JavaScript方面，将脚本放到页面底部；将JavaScript从外部引入；压缩JavaScript，删除不需要的脚本，减少DOM的访问。&lt;/li&gt;
  &lt;li&gt;图片方面，可优化css精灵，不要再HTML中拉伸图片，优化图片（压缩）。&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;8.http状态码以及含义&lt;/h3&gt;
 &lt;ol&gt;
  &lt;li&gt;对于1xx的状态码，为信息状态码，100 为继续，表示确认，成功返回具体参数信息。&lt;/li&gt;
  &lt;li&gt;对于2xx的状态码，200 表示正常返回信息，201表示请求成功并且服务器创建了新的资源，202表示服务器已接受请求，但尚未处理。&lt;/li&gt;
  &lt;li&gt;对于3xx，重定向，301表示，请求的网页已永久移动到新位置，302表示，临时性重定向，303表示临时性重定向，且总是使用 GET 请求新的 URI。304表示，自从上次请求后，请求的网页未修改过。&lt;/li&gt;
  &lt;li&gt;对于4xx，客户端错误，404，服务器无法理解请求的格式，客户端不应当尝试再次使用相同的内容发起请求，401，请求未授权，403，禁止访问，404，找不到如何与 URI 相匹配的资源。&lt;/li&gt;
  &lt;li&gt;对于5xx，服务器错误，500，最常见的服务器端错误，503，服务器端暂时无法处理请求，可能是过载或维护。&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;9.http-数据压缩&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200504" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;数据压缩，在浏览器中发送请求时会带着  &lt;code&gt;Content-Encoding: gzip&lt;/code&gt;，里面时浏览器支持的压缩格式列表，有多种如，gzip，deflate，br等。这样服务器就可以从中选择一个压缩算法，放进  &lt;code&gt;Content-Encoding&lt;/code&gt;响应头里，再把原数据压缩后发给浏览器。&lt;/p&gt;
 &lt;h3&gt;10.http-分块传输&lt;/h3&gt;
 &lt;p&gt;分块传输，就是将传输的文件分解成多个小块，然后分发给浏览器，浏览器收到后再重新组装复原。&lt;/p&gt;
 &lt;p&gt;每个分开包含两个部分，分块长度和分块数据（长度头和数据块），长度头以CRLF结尾的一行明文，数据块紧跟在长度头后面，也是用CRLF结尾，最后用一个长度为0的块表示结束。&lt;/p&gt;
 &lt;p&gt;在响应报文里用头字段Transfer-Encoding:chunked表示报文里的body部分不是一次性发送过来的，而是分成了许多块逐个发送的。&lt;/p&gt;
 &lt;p&gt;在Transfer-Encoding：chunked和Content-Length中，这两个字段是互斥的。&lt;/p&gt;
 &lt;blockquote&gt;一个响应报文的传输长度要么已知，要么长度未知（chunked）。&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200505" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Content-Length: 299&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200506" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200507" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;11.http-范围请求&lt;/h3&gt;
 &lt;p&gt;断点续传&lt;/p&gt;
 &lt;blockquote&gt;要实现该功能需要制定下载的实体范围，这种制定范围发送请求叫做范围请求。&lt;/blockquote&gt;
 &lt;p&gt;Accept-Ranges：服务器使用http响应头Accept-Ranges标识自身支持范围请求，字段的具体值用于定义范围请求的单位。&lt;/p&gt;
 &lt;p&gt;语法&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Accept-Ranges: bytes,范围请求的单位是 bytes （字节）
Accept-Ranges: none,不支持任何范围请求单位&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;范围请求时用于不需要全部数据，只需要其中的部分请求时，可以使用范围请求，允许客户端在请求头里使用专用字段来表示只获取文件的一部分。&lt;/p&gt;
 &lt;p&gt;Range的格式，请求头Range是HTTP范围请求的专用字段，格式是“bytes=x-y”,以字节为单位的数据范围。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200508" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;“0-”表示从文档起点开始到文档结束的整个文件。&lt;/li&gt;
  &lt;li&gt;“100-”表示从第100哥字节开始到文档末尾。&lt;/li&gt;
  &lt;li&gt;“-10”表示从文档末尾倒数的第10个字节开始。&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;执行范围时会使用头部字段 Range 来指定资源 byte 的范围。
Range格式：
5001-10000字节
Range : byte = 5001-10000
5000之后的
Range : byte = 5001-
0-3000字节，5001-10000字节
Range : byte=-3000,5001-10000&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200509" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;上图表示服务器收到Range字段后，检测范围合法性，范围越界，就会返回状态码416，如你的文件只有1000个字节，但请求范围在20000-3000，就会导致这个状态码的出现。&lt;/p&gt;
 &lt;p&gt;如果成功读取文件，范围正确，返回状态码“206”。服务器要添加一个响应头字段Content-Range,告诉片段的实际偏移量和资源的总大小。&lt;/p&gt;
 &lt;p&gt;最后是发送数据，直接把片段用TCP发给客户端，一个范围请求就算是处理完了。&lt;/p&gt;
 &lt;blockquote&gt;格式是“bytes x-y/length”,与Range头区别在没有“=”&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200510" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Content-Range: bytes 0-4395719/4395720&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200513" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;12.http-多段数据&lt;/h3&gt;
 &lt;p&gt;多端数据，就是在Range头里使用多个“x-y&amp;quot;，一次性获取多个片段数据。使用一种特殊的MIME类型：“multipart/byteranges”，用来表示响应报文包含了多个范围时使用。多重范围请求 响应会在头部 Content-Type 表明 multipart-byteranges。&lt;/p&gt;
 &lt;p&gt;多段数据图：分隔标记boundary来区分不同的分段&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200511" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200512" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200516" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;13.说一说cookies，sessionStorage 和 localStorage 的区别？&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;cookie是网站用来标识用户身份而存储在用户本地终端上的数据&lt;/li&gt;
  &lt;li&gt;cookie数据始终在同源的http请求中携带，即使是不需要的情况，so，会在浏览器和服务器间来回传递&lt;/li&gt;
  &lt;li&gt;sessionStorage和localStorage不会自动把数据发送给服务器，仅仅在本地保存&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;存储的大小&lt;/blockquote&gt;
 &lt;p&gt;cookie的数据大小不能超过4k；sessionStorage和localStorage虽然也有存储大小的限制，但比cookie大得多，可以达到5M或者更大。&lt;/p&gt;
 &lt;blockquote&gt;有限期时间&lt;/blockquote&gt;
 &lt;ol&gt;
  &lt;li&gt;localStorage存储持久数据，浏览器关闭后数据不会丢失，除了主动删除数据&lt;/li&gt;
  &lt;li&gt;sessionStorage数据在当前浏览器窗口关闭后自动删除&lt;/li&gt;
  &lt;li&gt;设置得cookie过期时间之前都有效，就算窗口或者是浏览器关闭&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;14.为什么说利用多个域名来存储网站资源会更有效？&lt;/h3&gt;
 &lt;p&gt;因为CDN缓存更方便；突破浏览器并发限制；节约cookie带宽；节约主域名得连接数，优化页面响应速度；防止不必要得安全性问题。&lt;/p&gt;
 &lt;h3&gt;15.http2.0的内容&lt;/h3&gt;
 &lt;p&gt;http2是超文本传输协议的第二版，相比http1协议的文本传输格式，http2是以二进制的格式进行数据传输的，具有更小的传输体积以及负载。&lt;/p&gt;
 &lt;p&gt;http2.0分层，分帧层（http2多路复用能力的核心部分),数据或http层（包含传统上被认为是 HTTP 及其关联数据的部分）。&lt;/p&gt;
 &lt;p&gt;HTTP2.0：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;多路复用机制，引入了二进制的分帧层机制来实现多路复用。（分帧层是基于帧的二进制协议。这方便了机器解析。请求和响应交织在一起。）&lt;/li&gt;
  &lt;li&gt;可以设置请求的优先级（客户端的分帧层对分割块标上请求的优先级）。&lt;/li&gt;
  &lt;li&gt;头部压缩 请求头压缩，增加传输效率。&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;HTTP/2较HTTP/1.1优化亮点&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;多路复用的流&lt;/li&gt;
  &lt;li&gt;头部压缩&lt;/li&gt;
  &lt;li&gt;资源优先级和依赖设置&lt;/li&gt;
  &lt;li&gt;服务器推送&lt;/li&gt;
  &lt;li&gt;流量控制&lt;/li&gt;
  &lt;li&gt;重置消息&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;多路复用的实现：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200519" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在单个域名下仍可以建立一个TCP管道，使用一个TCP长连接，下载整个资源页面，只需要一次慢启动，并且避免了竞态，浏览器发起请求，分帧层会对每个请求进行分割，将同一个请求的分割块打上相同的id编号，然后通过协议栈将所有的分割体发送给服务器，然后通过服务器的分帧层根据id编号进行请求组装，服务器的分帧层将回应数据分割按同一个回应体进行ID分割回应给客户端，客户端拼装回应。&lt;/p&gt;
 &lt;p&gt;对于http2中的帧（frame），http1不是基于帧（frame）的，是文本分隔的。&lt;/p&gt;
 &lt;p&gt;GET/HTTP/1.1   &lt;code&gt;&amp;lt;crlf&amp;gt;&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200518" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这样，对于http1的请求或者是响应可能有的问题：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;一次只能处理一个请求或者是响应，完成之前是不能停止解析的。&lt;/li&gt;
  &lt;li&gt;无法预判解析需要多少内层。&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;HTTP/1 的请求和响应报文，是由起始行、首部和正文组成，换行符分隔；HTTP/2是将请求和响应数据分割成更小的帧，采用二进制编码，易于解析的。&lt;/p&gt;
 &lt;p&gt;参考图片：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200520" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;帧结构总结  &lt;br /&gt;所有的帧都包含一个9 byte的帧头 + 可边长的正文不同。根据帧的类型不同，正文部分的结构也不一样。&lt;/blockquote&gt;
 &lt;p&gt;帧头：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200517" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;16.http2-幕后&lt;/h3&gt;
 &lt;p&gt;http2作为一个二进制协议，拥有包含轻量型，安全和快速在内的所有优势，保留了原始的http协议语义，对于http2更改了在系统之间传输数据的方式。&lt;/p&gt;
 &lt;blockquote&gt;二进制分帧层（binary framing layer），所有通信都在单个TCP连接上执行，该连接在整个对话期间一直处于打开状态，主要是二进制协议将通信分解为帧的方式，这些帧交织在客户端与服务器之间的双向逻辑流中。&lt;/blockquote&gt;
 &lt;p&gt;HTTP/2 连接的拓扑结构(展示了一个用于建立多个流的连接)&lt;/p&gt;
 &lt;p&gt;在流 1 中，发送了一条请求消息，并返回了相应的响应消息。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200514" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;HTTP/2 帧结构&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200515" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;前9个字节对于每个帧是一致的。解析时只需要读取这些字节，就可以准确地知道在整个帧中期望的字节数。&lt;/p&gt;
 &lt;p&gt;帧首部字段表格：&lt;/p&gt;
 &lt;table&gt;
  &lt;tr&gt;
   &lt;th align="left"&gt;名称&lt;/th&gt;
   &lt;th align="left"&gt;长度&lt;/th&gt;
   &lt;th align="left"&gt;描述&lt;/th&gt;
&lt;/tr&gt;

  &lt;tr&gt;
   &lt;td align="left"&gt;length&lt;/td&gt;
   &lt;td align="left"&gt;3字节&lt;/td&gt;
   &lt;td align="left"&gt;表示帧负载的长度&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;type&lt;/td&gt;
   &lt;td align="left"&gt;1字节&lt;/td&gt;
   &lt;td align="left"&gt;当前帧类型&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Flags&lt;/td&gt;
   &lt;td align="left"&gt;1字节&lt;/td&gt;
   &lt;td align="left"&gt;具体帧类型的标识&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;R&lt;/td&gt;
   &lt;td align="left"&gt;1位&lt;/td&gt;
   &lt;td align="left"&gt;保留位，不要设置，否则会带来严重后果&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Stream Identifier&lt;/td&gt;
   &lt;td align="left"&gt;31位&lt;/td&gt;
   &lt;td align="left"&gt;每个流的唯一ID&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Frame Payload&lt;/td&gt;
   &lt;td align="left"&gt;长度可变&lt;/td&gt;
   &lt;td align="left"&gt;真实的帧内容,长度是在length字段中设置的&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;备注：流Id是用来标识帧所属的流。流看作在连接上的一系列帧，它们构成了单独的 HTTP 请求和响应。&lt;/p&gt;
 &lt;p&gt;对于http1 的请求和响应都分成消息首部和消息体两部分；http2 从上面一张图可以知道，http2的请求和响应分成HEADERS 帧和 DATA 帧。&lt;/p&gt;
 &lt;p&gt;比较一下：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200529" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200528" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;http2的一个重要特性是基于流的流量控制。提供了客户端调整传输速度的能力。其中WINDOW_UPDATE 帧用来指示流量控制信息。&lt;/p&gt;
 &lt;p&gt;有了多路复用，客户端可以一次发出多有资源的请求，不用像http1那样，发出对新对象请求之前，需要等待前一个响应完成。所以浏览器失去了在Http1中的默认资源请求优先级策略。&lt;/p&gt;
 &lt;h3&gt;17.浏览器生成http请求消息&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200530" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200521" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200522" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200523" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200525" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;http的头字段&lt;/p&gt;
 &lt;table&gt;
  &lt;tr&gt;
   &lt;th align="left"&gt;头字段类型&lt;/th&gt;
   &lt;th align="left"&gt;含义&lt;/th&gt;
&lt;/tr&gt;

  &lt;tr&gt;
   &lt;td align="left"&gt;Date&lt;/td&gt;
   &lt;td align="left"&gt;表示请求和响应生成的日期&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Pragma&lt;/td&gt;
   &lt;td align="left"&gt;表示数据是否允许缓存的通信选项&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Cache-Control&lt;/td&gt;
   &lt;td align="left"&gt;控制缓存的相关信息&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Connection&lt;/td&gt;
   &lt;td align="left"&gt;设置发送响应之后TCP连接是否继续保持的通信选项&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Transfer-Encoding&lt;/td&gt;
   &lt;td align="left"&gt;表示消息主体的编码格式&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Via&lt;/td&gt;
   &lt;td align="left"&gt;记录途中经过的代理和网关&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Authorization&lt;/td&gt;
   &lt;td align="left"&gt;身份认证数据&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;From&lt;/td&gt;
   &lt;td align="left"&gt;请求发送者的邮件地址&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Referer&lt;/td&gt;
   &lt;td align="left"&gt;当通过点击超级链接进入下一个页面时，在这里会记录下上一个页面的URI&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;User-Agent&lt;/td&gt;
   &lt;td align="left"&gt;客户端软件的名称和版本号等相关信息&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Accept&lt;/td&gt;
   &lt;td align="left"&gt;客户端可支持的数据类型，以MIME类型来表示&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Accept-Charset&lt;/td&gt;
   &lt;td align="left"&gt;客户端可支持的字符集&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Accept-Language&lt;/td&gt;
   &lt;td align="left"&gt;客户端可支持的语言&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Host&lt;/td&gt;
   &lt;td align="left"&gt;接收请求的服务器ip地址和端口号&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Range&lt;/td&gt;
   &lt;td align="left"&gt;当需要只获取部分数据而不是全部数据时，可通过这个字段指定要获取的数据范围&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Location&lt;/td&gt;
   &lt;td align="left"&gt;表示信息的准确位置&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Server&lt;/td&gt;
   &lt;td align="left"&gt;服务器程序的名称和版本号等相关信息&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Allow&lt;/td&gt;
   &lt;td align="left"&gt;表示指定的URI支持&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Content-Encoding&lt;/td&gt;
   &lt;td align="left"&gt;当消息体经过压缩等编码处理时，表示其编码格式&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Content-Length&lt;/td&gt;
   &lt;td align="left"&gt;表示消息体的长度&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Content-Type&lt;/td&gt;
   &lt;td align="left"&gt;表示消息体的数据类型，以MIME规格定义的数据类型来表示&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Expires&lt;/td&gt;
   &lt;td align="left"&gt;表示消息体的有效期&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Last-Modified&lt;/td&gt;
   &lt;td align="left"&gt;数据的最后更新日期&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Content-Language&lt;/td&gt;
   &lt;td align="left"&gt;表示消息体的语言&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Content-Location&lt;/td&gt;
   &lt;td align="left"&gt;表示消息体在服务器上的位置&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left"&gt;Content-Range&lt;/td&gt;
   &lt;td align="left"&gt;当仅请求部分数据时，表示消息体包含的数据范围&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;HTTP消息示例：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200524" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;HTTP,超文本传送协议。&lt;/li&gt;
  &lt;li&gt;协议，通信操作的规则定义称为协议。&lt;/li&gt;
  &lt;li&gt;URI，统一资源标识符。&lt;/li&gt;
  &lt;li&gt;1 条请求消息中只能写 1 个 URI。如果需要获取多个文件，必须&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;对每个文件单独发送 1 条请求。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200527" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200526" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;IP 的基本思路&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200532" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Ip地址的表示方法&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200531" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;IP地址的结构-子网掩码表示网络号与主机号之间的边界。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200534" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;解析器的调用方法&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200533" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;DNS服务器的基本工作&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200535" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;DNS 服务器之间的查询操作&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200536" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;数据通过类似管道的结构来流动&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200538" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;18.了解网络基础知识&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200537" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;物理层&lt;/li&gt;
  &lt;li&gt;数据链路层&lt;/li&gt;
  &lt;li&gt;网络层&lt;/li&gt;
  &lt;li&gt;传输层&lt;/li&gt;
  &lt;li&gt;会话层&lt;/li&gt;
  &lt;li&gt;表示层&lt;/li&gt;
  &lt;li&gt;应用层&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;计算机网络，可以将规模分WAN,Wide Area Network广域网，和LAN局域网。通过电脑连接交换机再到路由器的连接。&lt;/p&gt;
 &lt;blockquote&gt;你知道计算机与网络都经历了怎么样的一个发展过程吗？&lt;/blockquote&gt;
 &lt;ol&gt;  &lt;li&gt;批处理就是指事先将用户程序和数据装入卡带或磁带，由计算机按照一定的顺序读取，使用户所要执行的这些程序和数据能够一并批量得到处理的方式。&lt;/li&gt;&lt;/ol&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200547" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ol&gt;  &lt;li&gt;分时系统，是指多个终端与同一个计算机连接，允许多个用户同时使用一台计算机的系统。&lt;/li&gt;&lt;/ol&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200539" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ol&gt;  &lt;li&gt;计算机网络&lt;/li&gt;&lt;/ol&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200540" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200541" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;TCP/IP的机制是什么，TCP/IP通信协议的统称，学习这个有人一定不了解什么是协议。&lt;/blockquote&gt;
 &lt;p&gt;但我们在接触到程序时，常常听到协议如IP，TCP，HTTP等协议。记住TCP/IP就是IP,TCP,HTTP等协议的集合。协议就是计算机与计算机之间通过网络实现通信时需要达成的一种的“约定”。这些协议就是让不同厂商的设备，不同的CPU和不同的操作系统组成的计算机之间进行通信。&lt;/p&gt;
 &lt;p&gt;就是两台计算机之间都能支持相同的协议，并遵循才能实现相互通信。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200542" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;分组交换协议&lt;/blockquote&gt;
 &lt;p&gt;分组交换就是将大数据分割成一个一个叫做包的较小单位进行传输的方法。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200543" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;分层模块&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200545" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;了解OSI参考模型&lt;/blockquote&gt;
 &lt;p&gt;OSI将分为易于理解的7层：&lt;/p&gt;
 &lt;p&gt;1.物理层，2.数据链路层，3.网络层，4.传输层，5.会话层，6.表示层，7.应用层。&lt;/p&gt;
 &lt;p&gt;应用层：是对特定应用的协议。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200544" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;表示层：设备固有数据格式和网络标准数据格式的转换。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200555" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;会话层：通信管理。负责建立和断开通信连接。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200546" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;传输层：管理两个节点之间的数据传输。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200548" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;网络层：地址管理与路由选择。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200556" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;数据链路层：互连设备之间传送和识别数据帧。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200553" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;物理层：以“0”，“1”代表电压的高低，灯光的闪灭。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200550" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;如何模块化通信传输&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200549" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;网络构成要素&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200551" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;网卡：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200552" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;什么是网关，它是OSI参考模型中负责将从传输层到应用层的数据进行转换和转发的设备。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200554" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;代理服务：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200565" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;19.有哪些渲染优化呢？&lt;/h3&gt;
 &lt;p&gt;第一，我们可以禁止使用iframe，第二，可以禁止使用gif图片来实现loading效果，降低CPU的消耗，来提升渲染性能，第三，使用CSS3代码来代替JS动画。&lt;/p&gt;
 &lt;p&gt;对于一些小图标，可以使用base64位编码，以减少网络请求，但不建议大图使用，因为比较耗费CPU，小图标优势在于，可以减少HTTP请求，避免文件跨域，修改及时生效。&lt;/p&gt;
 &lt;p&gt;页面头部的style和script会阻塞页面，在Renderer进程中的JS线程和渲染线程是互斥的。&lt;/p&gt;
 &lt;h3&gt;20.学习TCP和IP的基础知识&lt;/h3&gt;
 &lt;p&gt;TCP/IP协议族市一组协议的集合，也称为互联网协议族。&lt;/p&gt;
 &lt;p&gt;20世纪60年代后半叶，应DoD要求，美国开始进行通信技术相关的演技，ARPANET的诞生，开发分组交互技术，在1975年，TCP/IP的诞生。1983年，ARPANET决定正式启用TCP/IP为通信协议。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200557" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;TCP/IP与OSI参考模型&lt;/blockquote&gt;
 &lt;p&gt;对于OSI七层模型太细了，而互联网协议族TCP/IP模型划分为四层。&lt;/p&gt;
 &lt;p&gt;TCP/IP模型（应用层，传输层，互联网层，网络接口层）-应用层，传输层，网络层，链路层。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200559" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;传输层就是可以让应用程序之间实现通信。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200558" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在其中TCP是一种面向有连接的传输层协议，保证两端通信主机之间的通信可达。UDP是一种面向无连接的传输层协议，so，UDP用于分组数据较少或者多播，广播通信以及视频通信等领域。&lt;/p&gt;
 &lt;p&gt;应用层&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200561" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;21.面试题：TCP/IP市如何在媒介上进行传输的呢？&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200560" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;在不同层次的协议✍&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200563" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;数据包首部：&lt;/p&gt;
 &lt;p&gt;以太网包首部：IP包首部，TCP包首部，数据&lt;/p&gt;
 &lt;p&gt;IP包首部：TCP包首部，数据&lt;/p&gt;
 &lt;p&gt;TCP包首部：数据&lt;/p&gt;
 &lt;blockquote&gt;每个分层中，都会对所发送的数据附加一个首部，它包含了该层中必要的信息。（发送的目标地址，协议相关的信息等）&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;包是全能性术语&lt;/li&gt;
  &lt;li&gt;帧是数据链路层中包的单位&lt;/li&gt;
  &lt;li&gt;数据包，IP和UDP等网络层以上的分层中包的单位&lt;/li&gt;
  &lt;li&gt;段，表示TCP数据流中的信息&lt;/li&gt;
  &lt;li&gt;消息，应用协议中数据的单位&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200562" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;数据包的首部，明确表明了协议应该如何读取数据。掌握数据包首部，通常，为协议提供的信息为包首部，所要发送的内容为数据。&lt;/blockquote&gt;
 &lt;p&gt;发送数据包，TCP/IP通信流程：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;应用程序处理，发送通信开始TCP/IP通信，应用程序会进行编码处理，编码相当于OSI中的表示层功能。&lt;/li&gt;
  &lt;li&gt;TCP模块的处理，TCP负责建立连接，发送数据以及断开连接，TCP提供将应用层发来的数据顺利发送至对端的可靠传输。在应用层数据的前端附加一个TCP首部，它包含源端口号和目标端口号，序号以及校验和（用来判断数据是否被破坏）然后附加一个TCP首部的包再发给IP。&lt;/li&gt;
  &lt;li&gt;IP模块的处理，在TCP首部的前端加上自己的IP首部，它包含接收端IP地址和发送端IP地址。若不知道接收端的MAC地址，可以用ARP查找，只要知道对端MAC地址，就可以将MAC以及IP地址交给以太网的驱动程序，来实现数据传输。&lt;/li&gt;
  &lt;li&gt;网络接口的处理，从IP传过来的IP包，然后附加上以太网首部并进行发送处理，以太网首部包含接收端的MAC地址，发送端的MAC的地址，以及标志以太网类型的以太网数据的协议。&lt;/li&gt;
&lt;/ol&gt;
 &lt;blockquote&gt;数据包，  &lt;strong&gt;经过以太网的数据链路时&lt;/strong&gt;，大致上附加了以太网包首部，IP包首部，TCP包首部或者UDP包，以及应用自己的包首部和数据，最后包追加了包尾。&lt;/blockquote&gt;
 &lt;p&gt;分层中包的结构&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200573" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;数据包接收流程&lt;/blockquote&gt;
 &lt;ol&gt;
  &lt;li&gt;网络接口的处理，主机收到以太网包后，从以太网的包首部找到MAC地址判断是否为发给自己的，若不是就丢弃，如果是，就查找以太网包首部中的类型域从而确定以太网协议所传送过来的数据类型。&lt;/li&gt;
  &lt;li&gt;通过IP模块处理，然后TCP模块处理（需要判断是否被破坏），检查是否按照序号接收数据。当数据接收完毕后，会发送“确认回执”给发送端。注意，这里的回执信息未能达到发送端，那么发送端会认为没有收到而一直反复发送。&lt;/li&gt;
  &lt;li&gt;应用程序的处理，接收端应用程序会直接接收发送端发送的数据信息。&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;22.了解一下http-http3.0&lt;/h3&gt;
 &lt;p&gt;在http2.0中，TCP管道传输途中也会导致丢包问题，造成队头阻塞（在http2.0中的TCP建立连接三次握手，和HTTPS的TSL连接也会耗费较多时间）&lt;/p&gt;
 &lt;p&gt;其实多路复用技术可以只通过一个TCP连接就可以传输所有的请求数据。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200564" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;http3中弄了一个基于UDP协议的QUIC协议，QUIC虽说基于UDP，但是在基础上添加了很多功能。QUIC（快速UDP网络连接）是一种实验性的网络传输协议，由Google开发，该协议旨在使网页传输更快。&lt;/p&gt;
 &lt;p&gt;对于在http中的缺点就是延迟，浏览器的阻塞，在对同一域名，同时只能连接4个，超过了浏览器的最大连接限数时，后面的请求就会被阻塞；DNS的查询就是将域名解析为IP，来向目标服务器的IP建立连接，其中通过DNS缓存可以达到减少时间的作用；建立连接，HTTP是基于tcp协议的，三次握手，每次连接都无法复用，so，会每次请求都要三次握手和慢启动，都会影响导致延迟。（慢启动对大量小文件请求影响较大）&lt;/p&gt;
 &lt;p&gt;http处于计算机网络中的应用层，建立在TCP协议之上。（掌握了解tcp建立连接的3次握手和断开连接的4次挥手和每次建立连接带来的RTT延迟时间）。&lt;/p&gt;
 &lt;p&gt;相对于HTTP1.0使用了header里的if-modified-since,expires来做缓存判断，在HTTP1.1中引入了entity tag,if-unmodified-since,if-match,if-none-match等更多可供选择的缓存头来控制缓存策略。&lt;/p&gt;
 &lt;p&gt;http1.0传输数据时，每次都要重新建立连接，增加延迟，http1.1加入了keep-alive可以复用部分连接，但在域名分片等情况下仍要连接夺冠时连接，耗费资源，以及给服务器带来性能压力。&lt;/p&gt;
 &lt;p&gt;http1.1尝试使用pipeling来解决问题，就是浏览器可以一次性发出多个请求，在同一个域名下，同一条TCP连接，但对于pipeling要求返回是按照顺序的，即（如果前面有个请求很耗时的话，后面的请求即使服务器已经处理完，任会等待前面的请求处理完才开始按序返回。）&lt;/p&gt;
 &lt;p&gt;在http1.x中，Header携带内容过大，增加了传输的成本，在传输的内容都是明文，在一定程度上无法保证其数据的安全性。（在http1.x问题的出现，有了SPDY协议，用于解决http/1.1效率不高的问题，降低延迟，压缩Header等）&lt;/p&gt;
 &lt;blockquote&gt;HTTP2主要解决用户和网站只用一个连接（同域名下所有通信都只用单个连接完成，单个连接可以承载任意数量的双向数据流，数据流是以消息的形式发送，消息由一个或多个帧组成）。&lt;/blockquote&gt;
 &lt;p&gt;so，http采用二进制格式传输数据，不像http1.x的文本格式。（二进制：http2将请求和响应数据分割成帧，并且它们采用二进制的编码），对于HTTP2的概念：（流，消息，帧）&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;流，它是连接中的一个虚拟信道；&lt;/li&gt;
  &lt;li&gt;消息，它是HTTP消息，请求，以及响应；&lt;/li&gt;
  &lt;li&gt;帧，它是HTTP2.0通信的最小单位。&lt;/li&gt;
&lt;/ol&gt;
 &lt;blockquote&gt;多个帧可以乱序发送，可根据帧首部的标识流进行重新组装。&lt;/blockquote&gt;
 &lt;p&gt;对于http2,同一域名下只需要使用一个TCP连接，那么当出现丢包时，会导致整个TCP都要开始等待重传。对于http1.1来说，可以开启多个TCP连接，出现这种情况指挥影响一个连接（或者部分），其余的TCP连接正常传输。&lt;/p&gt;
 &lt;p&gt;HTTP/2 对首部采取了压缩策略，为了减少资源消耗并提升性能。（因为在http1中，在header携带cookie下，可能每次都要重复传输数据）&lt;/p&gt;
 &lt;p&gt;so，有了QUIC协议，整合了TCP，TLS，和HTTP/2的优点，并加以优化。那么QUIC是啥，它是用来替代TCP，SSL/TLS的传输层协议，在传输层之上还有应用层。&lt;/p&gt;
 &lt;blockquote&gt;注意，它是一个基于UDP协议的QUIC协议，使用在http3上。&lt;/blockquote&gt;
 &lt;p&gt;  &lt;strong&gt;QUIC 新功能&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200567" title=""&gt;&lt;/img&gt;  &lt;br /&gt;HTTPS 的一次完全握手的连接过程&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200566" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;QUIC可以解决传输单个数据流可以保证有序的交付，并且不会影响其他的数据流。（解决http2问题）&lt;/p&gt;
 &lt;p&gt;表示在QUIC连接中，一个连接上的多个stream，如其中stream1,stream2,stream3,stream4，其中stream2丢失（quic packet)，其余UDP到达，应用层直接读取。--- 无需等待，不存在TCP队头阻塞，丢失的包需要重新传即可。&lt;/p&gt;
 &lt;p&gt;补充：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;TCP是基于IP和端口去识别连接的；&lt;/li&gt;
  &lt;li&gt;QUIC是通过ID的方式去识别连接的&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;对于QUIC的包都是经过认证的，除了个别，so，这样，通过加密认证的报文，就可以降低安全风险。&lt;/p&gt;
 &lt;blockquote&gt;HTTP2-TLS,TCP,IP&lt;/blockquote&gt;
 &lt;p&gt;小结QUIC特点：（基于UDP）--- http3-QUIC,UDP,IP&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;多路数据流&lt;/li&gt;
  &lt;li&gt;TLS&lt;/li&gt;
  &lt;li&gt;有序交付&lt;/li&gt;
  &lt;li&gt;快速握手&lt;/li&gt;
  &lt;li&gt;可靠性&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;23.网络中的UDP&lt;/h3&gt;
 &lt;p&gt;UPD面向报文的协议，就是UDP只是报文的搬运工，不会对报文进行任何拆分和拼接操作，在发送端，应用层将数据传给传输层的UDP协议，UDP会给数据加一个UDP头标识下是UUDP协议，然后传给网络层。&lt;/p&gt;
 &lt;p&gt;接收端，网络层将数据传给传输层，UDP只去除IP报文头就传给应用层，不会任何拼接操作。&lt;/p&gt;
 &lt;p&gt;UDP是无连接，通信不需要建立和断开连接，UDP是不可靠的，不关心数据的安全等问题，UDP是没有拥塞控制，在网络条件不好的情况下可能会导致丢包。&lt;/p&gt;
 &lt;blockquote&gt;传输：UDP 支持一对一，一对多，多对多，多对一的的传输方式， UDP 提供了单播，多播，广播的功能。&lt;/blockquote&gt;
 &lt;h3&gt;24.网络中的TCP&lt;/h3&gt;
 &lt;p&gt;UDP没有TCP那么复杂，UDP头部开销小，但是TCP头部比UDP头部复杂得多，UDP头部只有8字节，相比TCP的至少20字节要少很多。&lt;/p&gt;
 &lt;blockquote&gt;Sequence number&lt;/blockquote&gt;
 &lt;p&gt;这个序号保证了TCP传输的报文都是有序的，对端可以通过序号顺序的拼接报文&lt;/p&gt;
 &lt;blockquote&gt;Window Size&lt;/blockquote&gt;
 &lt;p&gt;表示窗口大小，还能接收多少字节的数据&lt;/p&gt;
 &lt;blockquote&gt;Acknowledgement Number&lt;/blockquote&gt;
 &lt;p&gt;表示上一个序号的数据已经接收到，接收端期望接收的下一个字节的编号是多少&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;标识符&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;当ACK=1，表示确认号字段有效&lt;/p&gt;
 &lt;p&gt;当SYN=1，ACK=0时，表示当前报文段是一个连接请求报文&lt;/p&gt;
 &lt;p&gt;当SYN=1，ACK=1时，表示当前报文段是一个同意建立连接的应答报文&lt;/p&gt;
 &lt;p&gt;当FIN=1，表示此报文段是一个释放连接的请求报文&lt;/p&gt;
 &lt;blockquote&gt;性能指标 RTT&lt;/blockquote&gt;
 &lt;p&gt;表示发送端发送数据到接收到对端数据所需的往返时间&lt;/p&gt;
 &lt;blockquote&gt;小结&lt;/blockquote&gt;
 &lt;ol&gt;
  &lt;li&gt;TCP（Transmission Control Protocol，传输控制协议）是基于连接的协议&lt;/li&gt;
  &lt;li&gt;UDP（User Data Protocol，用户数据报协议）是面向非连接的协议。&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;25.建立连接三次握手&lt;/h3&gt;
 &lt;p&gt;建立连接开始时，两端都是CLOSED状态，通信开始前，双方都会创建 TCB，后进入 LISTEN 状态，开始等待客户端发送数据。&lt;/p&gt;
 &lt;p&gt;第一次握手&lt;/p&gt;
 &lt;blockquote&gt;客户端向服务器端发送连接请求报文段，请求发送后，客户端进入SYN-SENT 状态。&lt;/blockquote&gt;
 &lt;p&gt;第二次握手&lt;/p&gt;
 &lt;blockquote&gt;服务端收到连接请求报文段后，发送完成后便进入 SYN-RECEIVED 状态。&lt;/blockquote&gt;
 &lt;p&gt;第三次握手&lt;/p&gt;
 &lt;blockquote&gt;客户端收到连接同意的应答后，要向服务端发送一个确认报文。客户端发完这个报文段后便进入ESTABLISHED 状态，服务端收到这个应答后也进入 ESTABLISHED状态，此时连接建立成功。&lt;/blockquote&gt;
 &lt;p&gt;有人问了，两次握手就可以建立连接了，为啥要第三次呢？&lt;/p&gt;
 &lt;blockquote&gt;因为防止失效的连接请求报文段被服务器端接收，从而导致错误。&lt;/blockquote&gt;
 &lt;h3&gt;26.http请求码有哪些？&lt;/h3&gt;
 &lt;p&gt;100为继续，一般发送post请求时，已经发送了http header之后服务端将返回此信息，表示确认，之后发送具体参数信息；201，请求成功并且服务器创建了新的资源；202，服务器已接受请求，但未处理。&lt;/p&gt;
 &lt;p&gt;301，请求的网页已经永久移动到新的位置；302，临时性重定向；303，临时性重定向，且总是使用GET请求新的URI；304，自从上次请求后，请求的网页未修改过。&lt;/p&gt;
 &lt;p&gt;404，服务器无法理解请求；401，请求未授权；403，禁止访问。&lt;/p&gt;
 &lt;h3&gt;27.面试时，简单说说TCP传输的三次握手四次挥手&lt;/h3&gt;
 &lt;p&gt;传输，为了准确无误地把数据传输给目标，TCP协议采用了三次握手策略，用TCP协议把数据包送出去后，会向对方确认是否成功达到，发送端发送一个带SYN标志的数据包给到对方，接收端收到后，会回传一个带有SYN/ACK标志的数据包表示传送到达的确认信息，然后发送端也再次回传一个带有ACK标志的数据包，表示“握手”结束了。&lt;/p&gt;
 &lt;p&gt;握手过程中使用的标志：SYN和ACK&lt;/p&gt;
 &lt;p&gt;断开一个TCP连接需要四次挥手：&lt;/p&gt;
 &lt;blockquote&gt;第一次挥手&lt;/blockquote&gt;
 &lt;p&gt;主动关闭的一方，发送一个FIN(上述讲过---当FIN=1，表示此报文段是一个释放连接的请求报文)，传送数据，用来告诉对方（被动关闭方），说不会再给你发送数据了。---主动关闭的一方可以接受数据。&lt;/p&gt;
 &lt;blockquote&gt;第二次挥手&lt;/blockquote&gt;
 &lt;p&gt;被动关闭方 收到 FIN 包，发送 ACK 给对方，确认序号。&lt;/p&gt;
 &lt;blockquote&gt;第三次挥手&lt;/blockquote&gt;
 &lt;p&gt;被动关闭方 发送一个 FIN，关闭方，说我不会再给你发数据了。（你不给我发送数据，我也不给你发送数据了）&lt;/p&gt;
 &lt;blockquote&gt;第四次挥手&lt;/blockquote&gt;
 &lt;p&gt;主动关闭一方收到 FIN ，发送要给 ACK ，用来确认序号&lt;/p&gt;
 &lt;h3&gt;28.常说的HTTPS&lt;/h3&gt;
 &lt;p&gt;其实HTTP协议时承载于TCP协议之上的，再HTTP和TCP之间添加一个安全协议层，SSL或者TSL（ssl/tls协议传输，包含证书，卸载，流量转发，负载均衡，页面适配，浏览器适配，refer传递等），则就是常说的HTTPS。&lt;/p&gt;
 &lt;h3&gt;29.GET和POST的区别，何时使用POST？&lt;/h3&gt;
 &lt;ol&gt;
  &lt;li&gt;GET是用于信息获取，使用URL传递参数，发送信息的数量有限；&lt;/li&gt;
  &lt;li&gt;POST是用于修改服务器上的资源；&lt;/li&gt;
  &lt;li&gt;一般使用POST，当无法使用缓存文件，向服务器发送大量的数据，发送未知的字符&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;30.面试问，HTTP协议的主要特点&lt;/h3&gt;
 &lt;ol&gt;
  &lt;li&gt;简单快速&lt;/li&gt;
  &lt;li&gt;灵活&lt;/li&gt;
  &lt;li&gt;无连接&lt;/li&gt;
  &lt;li&gt;无状态&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;31.面试问，说说HTTP报文的组成部分&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200569" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;HTTP报文的组成部分包含：请求报文和响应报文&lt;/p&gt;
 &lt;p&gt;请求报文： 有请求行，请求头， 空行，请求体&lt;/p&gt;
 &lt;p&gt;响应报文： 有状态行，响应头，空行，响应体&lt;/p&gt;
 &lt;blockquote&gt;请求报文包含：&lt;/blockquote&gt;
 &lt;p&gt;1.请求方法，2.请求URL，3.HTTP协议以及版本，4.报文头，5.报文体&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;请求行，有请求方法，请求URL，http协议以及版本；&lt;/li&gt;
  &lt;li&gt;请求头，一堆键值对&lt;/li&gt;
  &lt;li&gt;空行，当服务器在解析请求头的时候，遇到了空行，表明后面的内容是请求体&lt;/li&gt;
  &lt;li&gt;请求体，请求数据&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;响应报文包含：&lt;/blockquote&gt;
 &lt;p&gt;1.报文协议以及版本，2，状态码以及状态描述，3，响应头，4，响应体&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;状态行：http协议和版本，状态码以及状态描述&lt;/li&gt;
  &lt;li&gt;响应头&lt;/li&gt;
  &lt;li&gt;空行&lt;/li&gt;
  &lt;li&gt;响应体&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;32.面试时问，知道哪些HTTP方法&lt;/h3&gt;
 &lt;ol&gt;
  &lt;li&gt;GET方法获取资源&lt;/li&gt;
  &lt;li&gt;POST方法传输资源&lt;/li&gt;
  &lt;li&gt;PUT方法更新资源&lt;/li&gt;
  &lt;li&gt;DELETE方法删除资源&lt;/li&gt;
  &lt;li&gt;HEAD方法获得报文首部&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;33.持久链接&lt;/h3&gt;
 &lt;p&gt;在http1.0中，客户端每隔很短时间会对服务器发出请求，查看是否有新的数据，只要轮询足够快，就可以造成交互实时进行，但这个做法，会对两端造成大量的性能浪费。&lt;/p&gt;
 &lt;p&gt;对于http1.1中的长连接，使用connection:keep-alive进行长连接，客户端只请求一次，但是服务器会将继续保持连接，再次请求时，避免了重新建立连接。&lt;/p&gt;
 &lt;p&gt;注意，keep-alive不会永久保持连接，只有保持一个时间段。&lt;/p&gt;
 &lt;h3&gt;34.安全问题：CSRF和XSS&lt;/h3&gt;
 &lt;p&gt;CSRF的基本概念，攻击原理，防御措施&lt;/p&gt;
 &lt;p&gt;CSRF（Cross-site request forgery）：跨站请求伪造&lt;/p&gt;
 &lt;p&gt;理解CSRF攻击：攻击者盗用了你的身份，以你的名义发送恶意请求。&lt;/p&gt;
 &lt;blockquote&gt;以你名义发送邮件，发消息，盗取你的账号，甚至于购买商品，虚拟货币转账……造成的问题包括：个人隐私泄露以及财产安全。&lt;/blockquote&gt;
 &lt;p&gt;CSRF的原理:(要完成一次CSRF攻击)&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;登录受信任网站A，并在本地生成Cookie。&lt;/li&gt;
  &lt;li&gt;在不登出A的情况下，访问危险网站B。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200568" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200570" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;XSS的基本概念,跨域脚本攻击。&lt;/p&gt;
 &lt;p&gt;xss是一种发生在web前端的漏洞，所以其危害的对象也主要是前端用户。&lt;/p&gt;
 &lt;p&gt;跨域脚本攻击是，恶意攻击者往web页面里插入恶意的script代码，在浏览器中运行script代码，达到恶意攻击用户的目的。&lt;/p&gt;
 &lt;p&gt;so，实现xss攻击具备2个条件，第一需要向web页面注入恶意的代码，第二，这些恶意代码被浏览器成功的执行。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200571" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200572" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;CSRF和XSS的区别：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;CSRF需要登录，获取COOKIE，利用网站本身的漏洞，去请求网站的api&lt;/li&gt;
  &lt;li&gt;XSS,不需要登录，向网站注入JS代码，执行JS里的代码，篡改网站的内容&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;35.从一个HTTP请求来看网络分层原理&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200574" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200575" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;一个HTTP请求的分层解析流程：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200585" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;TCP，它是面向连接的，可靠的，基于字节流的传输层通信协议。&lt;/p&gt;
 &lt;p&gt;特点：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;基于连接，数据传输之前需要建立连接&lt;/li&gt;
  &lt;li&gt;全双工的，双向传输&lt;/li&gt;
  &lt;li&gt;字节流，不限制数据大小，打包成报文段，保证有序接收，重复报文自动丢弃&lt;/li&gt;
  &lt;li&gt;流量缓冲，解决双方处理能力的不匹配&lt;/li&gt;
  &lt;li&gt;可靠的传输服务，保证可达，丢包时通过重发机制实现可靠性&lt;/li&gt;
  &lt;li&gt;拥塞控制，防止网络出现恶性拥塞&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;TCP连接，源地址，源端口，目的地址，目的端口&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;从TCP-IP协议底层&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200581" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200576" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;滑动窗口协议与累计确认（延时ACK）&lt;/blockquote&gt;
 &lt;p&gt;滑动窗口大小同通过tcp三次握手和对端协商，且受网络状况影响&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200583" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;36.HTTPS安全加密通道原理分析&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200584" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;什么是HTTPS协议，由于HTTP天生“明文”的特点，整个传输过程完全透明，任何人都能够在链路中截获，修改或者伪造请求、响应报文，数据不具有可信性。&lt;/p&gt;
 &lt;p&gt;使用HTTPS时，所有的HTTP请求和响应发送到网络前，都要进行加密。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200579" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;https = http + ssl/tls

对称加密：加密 解密使用同一密钥

非对称加密：公钥-随意分发，私钥-服务器自己保持

公钥加密的数据，只能通过私钥解密
私钥加密的数据，只能公钥能解密&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;加密算法：&lt;/p&gt;
 &lt;p&gt;对称密钥加密算法，编，解码使用相同密钥的算法&lt;/p&gt;
 &lt;p&gt;非对称密钥加密算法，一个公钥，一个私钥，两个密钥是不同的，公钥可以公开给如何人使用，私钥是严格保密的。&lt;/p&gt;
 &lt;p&gt;加密通道的建立：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200582" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;数字证书的申请和验证&lt;/blockquote&gt;
 &lt;p&gt;如何申请：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;生成自己的公钥和私钥，服务器自己保留私钥&lt;/li&gt;
  &lt;li&gt;向CA机构提交公钥，公司，域名信息等待认证&lt;/li&gt;
  &lt;li&gt;CA机构通过线上，线下多种途径验证你提交信息的真实性，合法性&lt;/li&gt;
  &lt;li&gt;信息审核通过，CA机构则会向你签发认证的数字证书，包含了公钥，组织信息，CA信息，有效时间，证书序列号，同时生成了一个签名&lt;/li&gt;
  &lt;li&gt;签名步骤：hash(用于申请证书所提交的明文信息)= 信息摘要&lt;/li&gt;
  &lt;li&gt;CA再使用CA机构的私钥对信息摘要进行加密，密文就是证书的数字签名&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200578" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;37.https的对称加密，非对称加密，混合加密，CA认证&lt;/h3&gt;
 &lt;p&gt;HTTPS ，超文本传输安全协议，目标是安全的HTTP通道，应用是安全数据传输。HTTP协议虽然使用广，但是存在不小的安全缺陷，主要是数据的  &lt;strong&gt;明文传送&lt;/strong&gt;和  &lt;strong&gt;消息完整性&lt;/strong&gt;检测的缺乏。&lt;/p&gt;
 &lt;p&gt;HTTPS协议是由HTTP加上TLS/SSL协议构建的可进行加密传输，身份认证的网络协议。&lt;/p&gt;
 &lt;p&gt;通过， 数字证书，加密算法，非对称密钥 等技术完成互联网数据传输加密，实现互联网传输安全保护。&lt;/p&gt;
 &lt;p&gt;HTTPS主要特性：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;数据保密性&lt;/li&gt;
  &lt;li&gt;数据完整性&lt;/li&gt;
  &lt;li&gt;身份校验安全性&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;客户端和服务器端在传输数据之前，会通过基于证书对双方进行身份认证。客户端发起SSL握手消息给服务端要求连接，服务端将证书发送给客户端。客户端检查服务器端证书，确认是否由自己信任的证书签发机构签发，如果不是，将是否继续通讯的决定权交给用户选择，如果检查无误或者用户选择继续，则客户端认可服务端的身份。&lt;/p&gt;
 &lt;p&gt;服务端要求客户端发送证书，并检查是否通过验证，失败则关闭连接，认证成功，从客户端证书中获得客户端的公钥。&lt;/p&gt;
 &lt;blockquote&gt;HTTP原理&lt;/blockquote&gt;
 &lt;p&gt;客户端的浏览器首先要通过网络与服务器建立连接，该连接时通过TCP来完成的，一般TCP连接的端口号是80，建立连接后，客户端发送一个请求给服务器端；服务器端接收到请求后，给予相应的响应信息。&lt;/p&gt;
 &lt;blockquote&gt;HTTPS原理&lt;/blockquote&gt;
 &lt;p&gt;客户端将它所支持的算法列表和一个用作产生密钥的随机数发送给服务器，服务器从算法列表中选择一种加密算法，并将它和一份包含服务器公用密钥的证书发送给客户端，该证书还包含了用于认证目的的服务器标识，服务器同时还提供了一个用作产生密钥的随机数。&lt;/p&gt;
 &lt;p&gt;客户端对服务器的证书进行验证，并抽取服务器的公用密钥，再产生一个称作pre_master_secret的随机密码串，并使用服务器的公用密钥对其进行加密，并将加密后的信息发送给服务器。&lt;/p&gt;
 &lt;p&gt;客户端与服务器端根据pre_master_secret以及客户端与服务器的随机数独立计算出加密和MAC密钥。&lt;/p&gt;
 &lt;blockquote&gt;混合加密&lt;/blockquote&gt;
 &lt;p&gt;在传输数据中使用对称加密，但对称加密的密钥采用非对称加密来传输，混合加密比较安全，但无法知道数据是否被篡改&lt;/p&gt;
 &lt;blockquote&gt;CA认证&lt;/blockquote&gt;
 &lt;p&gt;CA认证, 即是电子认证服务，指电子签名相关各方提供真实性，可靠性验证的活动。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200577" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;特性：参阅百度百科—简介，  &lt;a href="https://baike.baidu.com/item/CA%E8%AE%A4%E8%AF%81/6471579?fr=aladdin#1" rel="nofollow noreferrer"&gt;点击进入&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200580" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;38.https对比http&lt;/h3&gt;
 &lt;p&gt;http传输方式：明文传输，网站或相关服务与用户之间的数据交互无加密，容易被监听，篡改。&lt;/p&gt;
 &lt;p&gt;https传输方式：在HTTP加入了SSL层，用于数据传输加密。&lt;/p&gt;
 &lt;p&gt;http身份认证：无任何身份认证，用户无法通过http辨认出网站的真实身份。&lt;/p&gt;
 &lt;p&gt;https身份认证：经过CA多重认证，包含域名管理权限认证等。&lt;/p&gt;
 &lt;p&gt;http成本：无任何使用成本，所有网站默认是http模式。&lt;/p&gt;
 &lt;p&gt;https需要成本，需要申请SSL证书来实现https。&lt;/p&gt;
 &lt;p&gt;http连接端口：80端口。&lt;/p&gt;
 &lt;p&gt;https连接端口：443端口。&lt;/p&gt;
 &lt;h3&gt;39.证书如何安全传输，被掉包了怎么办？&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200586" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;40.http3中QUIC&lt;/h3&gt;
 &lt;p&gt;QUIC是谷歌制定的一种基于UDP的低时延的互联网传输层协议。&lt;/p&gt;
 &lt;p&gt;1、避免前序包阻塞；2、零RTT建连；3、FEC前向纠错&lt;/p&gt;
 &lt;blockquote&gt;HTTP 的历史&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200588" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;HTTP/2 和 HTTP/3 建立连接的差别&lt;/p&gt;
 &lt;p&gt;TCP/建立连接与QUIC建立连接&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200587" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;队头阻塞/多路复用&lt;/p&gt;
 &lt;p&gt;HTTP/1.1 提出了 Pipelining 技术，允许一个 TCP 连接同时发送多个请求&lt;/p&gt;
 &lt;p&gt;请求与响应，与，Pipelining&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200590" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;http/1.1队头阻塞&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200589" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;HTTP/2 的多路复用解决了队头阻塞问题&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200595" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200593" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;拥塞控制：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;慢启动&lt;/li&gt;
  &lt;li&gt;拥塞避免&lt;/li&gt;
  &lt;li&gt;快速重传&lt;/li&gt;
  &lt;li&gt;快速恢复&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;41.HTTP 协议入门&lt;/h3&gt;
 &lt;p&gt;HTTP 基于TCP/IP 协议的应用层协议，不涉及数据包packet传输，主要客户端和服务器之间的通信格式，默认使用80端口。TCP连接建立后，客户端向服务器请求网页，协议规定，服务器只能回应HTML格式的字符串，不能回应别的格式。&lt;/p&gt;
 &lt;p&gt;http1.0可以传输文字，传输图像，视频，二进制文件；除了GET方法，还有POST，HEAD等；每次通信都需要 头信息HTTP header，状态码，多字符集支持，缓存，权限等。&lt;/p&gt;
 &lt;p&gt;字段：ontent-Type 字段&lt;/p&gt;
 &lt;p&gt;头信息必须是 ASCII 码，后面的数据可以是任何格式，字段值：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;text/plain
text/html
text/css
image/jpeg
image/png
image/svg+xml
audio/mp4
video/mp4
application/javascript
application/pdf
application/zip
application/atom+xml&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;客户端请求的时候，使用Accept字段，表示可以接受哪些数据格式。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Accept: */*&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;Content-Encoding字段,表示数据的压缩方式&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Content-Encoding: gzip
Content-Encoding: compress
Content-Encoding: deflate&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;客户端在请求时，用Accept-Encoding字段说明接受哪些压缩方法。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Accept-Encoding: gzip, deflate&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;http1.0就是每个TCP连接只能发送一个请求，发送完毕后就关闭，so，为解决问题，用了一个非标准Connection字段，Connection:keep-alive。&lt;/p&gt;
 &lt;p&gt;HTTP/1.1引入了持久连接（persistent connection），TCP连接默认不关闭，可以被多个请求复用，不用声明Connection: keep-alive。&lt;/p&gt;
 &lt;p&gt;也不是永久性不关闭的，只要有一段时间没有活动，就会关闭TCP连接，一般对于同一个域名，大多数浏览器允许同时建立6个持久连接。&lt;/p&gt;
 &lt;p&gt;1.1 版引入了管道机制（pipelining），同一个TCP连接里，可以同时发送多个请求。但是还是按照顺序，一个请求回应后，再回应另一个请求。（但也减少不小的消耗时间）。&lt;/p&gt;
 &lt;p&gt;使用  &lt;strong&gt;分块传输编码&lt;/strong&gt;，只要请求或回应的头信息  &lt;strong&gt;有Transfer-Encoding字段&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Transfer-Encoding: chunked&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;什么是多工？双向，实时的通信就叫 多工。&lt;/p&gt;
 &lt;p&gt;HTTP2 复用TCP连接，在一个连接里，两端都可以同时发送多个请求或响应，而且不用按照顺序一一对应，避免了“队头堵塞”。&lt;/p&gt;
 &lt;p&gt;http2引入了头信息压缩机，头信息使用gzip或compress压缩后再发送，客户端和服务器同时维护一张头信息表，所有字段存在这个表里，生成一个索引号，以后就只发送索引号，这样就提高速度了。&lt;/p&gt;
 &lt;p&gt;HTTP/2允许服务器未经请求，主动向客户端发送资源（服务器推送）&lt;/p&gt;
 &lt;h3&gt;42.什么是cookie呢&lt;/h3&gt;
 &lt;p&gt;cookie是某网站为了辨别用户身份，进行session跟踪而存储在用户本地终端的数据（通常经过加密），由用户客户端计算机暂时或永久保存的信息。&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;存储在用户本地终端上的数据&lt;/li&gt;
  &lt;li&gt;用来辨别用户身份&lt;/li&gt;
  &lt;li&gt;保存在用户本地终端   &lt;p&gt;cookie是一些数据，存储在你电脑上的文本文件中，当web服务器向浏览器发送web页面时，在连接关闭后，服务端不会记录用户的信息，cookie的作用就是解决如何记录客户端的用户信息。&lt;/p&gt;
   &lt;p&gt;场景：当用户访问web页面，用户信息记录在cookie中，当用户下一次访问页面后，可以在cookie中读取用户访问记录。&lt;/p&gt;
   &lt;p&gt;cookie是以键值对形式存储的，当浏览器从服务器上请求web页面，该页面的cookie会被添加到请求中，服务端通过这种方式用来获取用户信息。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
 &lt;blockquote&gt;可以使用JavaScript来创建，读取，修改，删除cookie&lt;/blockquote&gt;
 &lt;p&gt;使用document.cookie属性来创建，读取以及删除cookie&lt;/p&gt;
 &lt;p&gt;创建：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;document.cookie = &amp;quot;username = dadaqianduan&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;给cookie添加一个过期时间：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;document.cookie = &amp;quot;username = dadaqianduan; expires=xxxxxx&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;默认情况下，cookie属于当前页面：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;document.cookie = &amp;quot;username = dadaqianduan; expires= ; path=/&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;读取cookie&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;var x = document.cookie;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;修改cookie&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;document.cookie = &amp;quot;username = dada; expires=xxx; path=/&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;删除cookie， 把设置时间的expires 参数改为以前的时间即可。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;document.cookie = &amp;quot;username = ; expires= xxx&amp;quot;;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;为什么会有cookie呢？因为http请求时无协议的，http1.x，无状态协议，客户端同一个请求发送多次，服务端并不能识别是不是同一个客户端发送，为了解决无状态，就有了cookie。&lt;/p&gt;
 &lt;p&gt;cookies是服务器暂存放在你的电脑里的资料，以.txt格式的文本文件，好让服务器用来辨认你的计算机，当你在浏览网站时，web服务器会发送一个小小的资料放在你的计算机上。&lt;/p&gt;
 &lt;p&gt;当你下一次访问同一个网站，web浏览器会先看看有没有它上次留下来的cookies资料，有的话就输出特定的内容给你。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200594" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200596" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200597" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;cookie原理&lt;/blockquote&gt;
 &lt;p&gt;浏览器第一次请求服务器，服务器响应请求中携带cookie，给浏览器，浏览器第二次请求，携带cookie，给服务器，服务器根据cookie辨别用户，也可以修改cookie内容。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200591" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200600" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200592" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200601" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;domain时.baidu.com的cookie绑定到了域名商。跨域的域名不能写入在cookies文件里&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200602" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;cookie的属性有哪些&lt;/blockquote&gt;
 &lt;p&gt;Name, Value, Domain, Path, Expires/Max-Age, Size, HttpOnly, Secure, SameSite&lt;/p&gt;
 &lt;p&gt;掌握面试中的HttpOnly,这个属性设置为true，就不能通过js脚本获取cookie的指，能有效防止xss的攻击。&lt;/p&gt;
 &lt;p&gt;Cookie中的HttpOnly和Secure中：&lt;/p&gt;
 &lt;p&gt;标记为Secure的Cookie只能被https协议加密过的请求发送给服务端。但也无法保证其安全保障。&lt;/p&gt;
 &lt;p&gt;如果cookie中设置了HttpOnly属性，通过js脚本将无法读取到cookie信息，有效防止xss的攻击，窃取cookie内容，增加了cookie的安全性，但是重要信息还是不要存储在cookie中。&lt;/p&gt;
 &lt;p&gt;因为xss为跨站脚本攻击，是web程序常见的漏洞，属于被动式且用于客户端的攻击方式&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;SameSite&lt;/p&gt;
 &lt;blockquote&gt;SameSite Cookie允许服务器要求某个cookie在跨站请求时不会被发送，从而可以阻止跨站请求伪造攻击（CSRF）。&lt;/blockquote&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Set-Cookie: key=value; SameSite=Strict&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;SameSite有三个值：&lt;/p&gt;
 &lt;p&gt;None: 浏览器在同站请求，跨站请求下继续发送cookies，不区分大小写。（所有三方的请求都会携带cookie)&lt;/p&gt;
 &lt;p&gt;Strict: 浏览器将只在访问相同站点时发送cookie。（所有三方的链接都不会携带cookie)&lt;/p&gt;
 &lt;p&gt;Lax: Same-site cookies 将会为一些跨站子请求保留，如图片加载或者frames的调用，但只有当用户从外部站点导航到URL时才会发送。(只有同步且是get请求才可携带cookie)&lt;/p&gt;
 &lt;blockquote&gt;在https协议中，才能通过js去设置secure类型的cookie,在http协议的网页中是无法设置secure类型cookie的。默认情况，https协议还是http协议的请求，cookie都会被发送到服务端。&lt;/blockquote&gt;
 &lt;h3&gt;43.什么是token呢？&lt;/h3&gt;
 &lt;p&gt;token的出现，是在客户端频繁向服务端请求数据，服务端频繁的去数据库查询用户名和密码并进行对比，判断用户名和密码正确与否，并作出相应提示。token是服务端生成的一串字符串，以作客户端进行请求的一个令牌，第一登录时，服务器生成一个token，将此token返回给客户端，客户端带上这个token，无需再次带上用户名和密码了。&lt;/p&gt;
 &lt;p&gt;token的出现减轻了服务器的压力，减少频繁地数据库查询。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200599" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;token的优点&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;无状态，可扩展&lt;/li&gt;
  &lt;li&gt;安全性&lt;/li&gt;
  &lt;li&gt;多平台跨域&lt;/li&gt;
  &lt;li&gt;基于标准&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200598" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200606" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200605" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200607" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;基于Token的身份验证的过程&lt;/blockquote&gt;
 &lt;p&gt;浏览器，输入userName, Password，到mysql，校验成功 生成token，将token返回给客户端，当客户端发起请求时，每次访问api都携带token到服务器端，经过过滤器，校验token，校验成功后返回请求数据，校验失败后返回错误码。&lt;/p&gt;
 &lt;h3&gt;44.cookie,session,token&lt;/h3&gt;
 &lt;p&gt;cookie，记录访问过的网站或正在访问的网站，对于HTTP 协议是无状态的，服务器不知道浏览器上一次访问做了什么，也无法对用户会话进行跟踪连接，所以，cookie是由服务器发送到客户端浏览器的一段文本文件，包含了网站访问活动信息。Cookie 存放在客户端，用来保存客户端会话信息；由于存储在客户端，它的安全性不能完全保证。&lt;/p&gt;
 &lt;p&gt;session表示是c/s架构中服务器和客户端一次会话的过程，用来保存认证用户信息。session是一种HTTP存储机制，提供持久机制。Session存放在服务器端，用户验证客户端信息。由于存储在服务器，安全性有一定的保证。&lt;/p&gt;
 &lt;p&gt;token是一种认证方式(是“令牌”的意思，主要是用于身份的验证方式。)&lt;/p&gt;
 &lt;h3&gt;45.跨域&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200604" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;网页的URL的协议、域名、端口有一个不同，就算是跨域了&lt;/p&gt;
 &lt;blockquote&gt;跨域：JSONP&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200603" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200610" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;46.思维导图http小结&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200611" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200609" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200612" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200608" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200616" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200615" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200618" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;47.http中的字段&lt;/h3&gt;
 &lt;ol&gt;
  &lt;li&gt;accept，数据格式，请求accept，响应，content-type，表示收到的数据格式&lt;/li&gt;
  &lt;li&gt;accept，压缩方式，请求accept-encoding，响应，content-encoding，采用什么样的压缩方式&lt;/li&gt;
  &lt;li&gt;accept，支持语言，请求accept-language，响应content-language&lt;/li&gt;
  &lt;li&gt;accept，字符集，请求accept-charset，响应content-type，指定字符集&lt;/li&gt;
  &lt;li&gt;accept，范围请求，请求if-range和range，响应accept-anges和content-range&lt;/li&gt;
  &lt;li&gt;cookie，请求时传递给服务端的cookie信息&lt;/li&gt;
  &lt;li&gt;set-cookie，响应报文首部设置要传递给客户端的cookie信息&lt;/li&gt;
  &lt;li&gt;allow，支持什么HTTP方法&lt;/li&gt;
  &lt;li&gt;last-modified，资源的最后修改时间&lt;/li&gt;
  &lt;li&gt;expires,设置资源缓存的失败日期&lt;/li&gt;
  &lt;li&gt;content-language，实体的资源语言&lt;/li&gt;
  &lt;li&gt;content-encoding，实体的编码格式&lt;/li&gt;
  &lt;li&gt;content-length，实体主体部分的大小单位是字节&lt;/li&gt;
  &lt;li&gt;content-range，返回的实体的哪些范围&lt;/li&gt;
  &lt;li&gt;content-type，哪些类型&lt;/li&gt;
  &lt;li&gt;accept-ranges，处理的范围请求&lt;/li&gt;
  &lt;li&gt;age，告诉客户端服务器在多久前创建了响应&lt;/li&gt;
  &lt;li&gt;vary，代理服务器的缓存信息&lt;/li&gt;
  &lt;li&gt;location，用于指定重定向后的URI&lt;/li&gt;
  &lt;li&gt;If-Match，值是资源的唯一标识&lt;/li&gt;
  &lt;li&gt;User-Agent，将创建请求的浏览器和用户代理名称等信息传递给服务器&lt;/li&gt;
  &lt;li&gt;Transfer-Encoding，传输报文的主体编码方式&lt;/li&gt;
  &lt;li&gt;connection，管理持久连接，keep-alive , close&lt;/li&gt;
  &lt;li&gt;Cache-Control，控制浏览器的强缓存&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;48.如果面试问HTTP报文结构是什么，你能回答上来不？&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200617" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;对于 TCP 而言&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;起始行 + 头部 + 空行 + 实体&lt;/code&gt;&lt;/pre&gt;
 &lt;ol&gt;  &lt;li&gt;请求报文&lt;/li&gt;&lt;/ol&gt;
 &lt;pre&gt;  &lt;code&gt;GET /home HTTP/1.1&lt;/code&gt;&lt;/pre&gt;
 &lt;ol&gt;  &lt;li&gt;响应报文&lt;/li&gt;&lt;/ol&gt;
 &lt;pre&gt;  &lt;code&gt;HTTP/1.1 200 OK&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200619" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200621" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;空行是用来分开头部和实体。&lt;/blockquote&gt;
 &lt;h3&gt;49.如果面试问HTTP请求方法有哪些，你能回答上来不？&lt;/h3&gt;
 &lt;ol&gt;
  &lt;li&gt;GET方法，用来获取资源&lt;/li&gt;
  &lt;li&gt;POST方法，用来提交数据&lt;/li&gt;
  &lt;li&gt;PUT方法，用来修改数据&lt;/li&gt;
  &lt;li&gt;DELETE方法，用来删除资源&lt;/li&gt;
  &lt;li&gt;OPTIONS方法，用来跨域请求&lt;/li&gt;
  &lt;li&gt;HEAD方法，用来获取资源的元信息&lt;/li&gt;
  &lt;li&gt;CONNECT方法，用来建立连接，用于代理服务器&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;50.如果面试问，你对URI是如何理解的，你能回答上来不？&lt;/h3&gt;
 &lt;p&gt;URL统一资源定位符，URI，统一资源标识符。URI用于区分网络上不同的资源。&lt;/p&gt;
 &lt;p&gt;URI包含了URN和URL。&lt;/p&gt;
 &lt;p&gt;URL的结构：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200613" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;协议名，登录主机的用户信息，主机名和端口，请求路径，查询参数，URI上定位资源内的一个锚点。&lt;/blockquote&gt;
 &lt;h3&gt;51.如果面试问，你对HTTP状态码的了解有多少，你能回答上来不？&lt;/h3&gt;
 &lt;p&gt;了解一些特定的HTTP状态码：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200614" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200623" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;52.如果面试问，说说HTTP特点以及缺点，你能回答上来不？&lt;/h3&gt;
 &lt;p&gt;特点是：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;灵活可扩展&lt;/li&gt;
  &lt;li&gt;可靠传输&lt;/li&gt;
  &lt;li&gt;无状态等&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;缺点是：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;无状态&lt;/li&gt;
  &lt;li&gt;明文传输&lt;/li&gt;
  &lt;li&gt;队头阻塞问题&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;53.如果面试问，说说你对Accept字段的理解，你能回答上来不？&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200620" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200622" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;数据格式&lt;/li&gt;
  &lt;li&gt;压缩方式&lt;/li&gt;
  &lt;li&gt;支持语言&lt;/li&gt;
  &lt;li&gt;字符集&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;54.如果面试问，什么是队头阻塞问题，你能回答上来不？&lt;/h3&gt;
 &lt;p&gt;TCP中是报文，HTTP是请求。&lt;/p&gt;
 &lt;p&gt;对于解决HTTP的队头阻塞问题是：并发连接和域名分片。&lt;/p&gt;
 &lt;h3&gt;55.如果面试问，说说你对HTTP代理的理解，你能回答上来不？&lt;/h3&gt;
 &lt;p&gt;代理服务器功能：1，负载均衡，2，保障安全（利用心跳机制监控服务器，一旦发现故障机就将其踢出集群。），3，缓存代理。&lt;/p&gt;
 &lt;p&gt;理解代理缓存：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;由一个代理服务器下载的页面存储；&lt;/li&gt;
  &lt;li&gt;一个代理服务器为多个用户提供一条通道；&lt;/li&gt;
  &lt;li&gt;缓冲的代理允许一个代理服务器减少对同一个网站的同样页面的请求次数&lt;/li&gt;
  &lt;li&gt;一旦代理服务器的一个用户请求了某个页面，代理服务器就保存该页面以服务于它的其他用户的同样的请求&lt;/li&gt;
  &lt;li&gt;代理缓存，这种处理减少了用户等待页面显示的时间&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200625" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;缓存的作用：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200629" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;代理服务器或客户端本地磁盘内保存的资源副本，利用缓存可减少对源服务器的访问，可以节省通信流量和通信时间。&lt;/blockquote&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Cache-Control: max-age=300；&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;表示时间间隔，再次请求的时间间隔300s内，就在缓存中获取，否则就在服务器中&lt;/p&gt;
 &lt;p&gt;Cache-Control:&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;public 表示响应可被任何中间节点缓存&lt;/li&gt;
  &lt;li&gt;private 表示中间节点不允许缓存&lt;/li&gt;
  &lt;li&gt;no-cache 表示不使用Cache-Control的缓存控制方式做前置验证&lt;/li&gt;
  &lt;li&gt;no-store 表示真正的不缓存任何东西&lt;/li&gt;
  &lt;li&gt;max-age 表示当前资源的有效时间&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;强缓存：浏览器直接从本地存储中获取数据，不与服务器进行交互&lt;/p&gt;
 &lt;p&gt;协商缓存：浏览器发送请求到服务器，浏览器判断是否可使用本地缓存&lt;/p&gt;
 &lt;p&gt;学习了解强缓存：&lt;/p&gt;
 &lt;p&gt;强缓存主要学习expires和cache-control&lt;/p&gt;
 &lt;p&gt;cache-control该字段：max-age，s-maxage，public，private，no-cache，no-store。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;cache-control: public, max-age=3600, s-maxage=3600 &lt;/code&gt;&lt;/pre&gt;
 &lt;ul&gt;
  &lt;li&gt;表示资源过了多少秒之后变为无效&lt;/li&gt;
  &lt;li&gt;s-maxage 的优先级高于 max-age&lt;/li&gt;
  &lt;li&gt;在代理服务器中，只有 s-maxage 起作用&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;public 和 private&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;public 表示该资源可以被所有客户端和代理服务器缓存&lt;/li&gt;
  &lt;li&gt;private 表示该资源仅能客户端缓存&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;当浏览器去请求某个文件的时候，服务端就在response header里做了缓存的配置：&lt;/p&gt;
 &lt;blockquote&gt;表现为：respone header 的cache-control&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200626" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200624" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;学习了解✍协商缓存：&lt;/p&gt;
 &lt;p&gt;response header里面的设置&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;etag: &amp;apos;xxxx-xxx
last-modified: xx, 24 Dec xxx xxx:xx:xx GMT&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200628" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200627" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200637" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;56.如果面试问，HTTP/2，你能回答上来不？&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200630" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;HTTP/2采用哈夫曼编码来压缩整数和字符串，可以达到50%~90%的高压缩率。&lt;/p&gt;
 &lt;p&gt;服务器推送&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200636" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200635" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;57.B/S 结构定义&lt;/h3&gt;
 &lt;p&gt;浏览器-服务器结构，B/S结构，客户端不需要安装专门的软件，只需要浏览器即可，浏览器通过web服务器与数据库进行交互，可以方便的在不同平台下工作。&lt;/p&gt;
 &lt;p&gt;B/S结构简化了客户端的工作，它是随着Internet技术兴起而产生的，对C/S技术的改进，但该结构下服务器端的工作较重，对服务器的性能要求更高。&lt;/p&gt;
 &lt;h3&gt;58.URI统一资源标识符&lt;/h3&gt;
 &lt;p&gt;统一资源标识符是一个用于标识某一互联网资源名称的字符串。该标识允许用户对网络中的资源通过特定的协议进行交互操作。URI常见形式为统一资源定位符（URL），URN为统一资源名称。用于在特定的命令空间资源的标识，以补充网址。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200638" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;59.HTTP 协议&lt;/h3&gt;
 &lt;p&gt;HTTP超文本传输协议是互联网上应用最为广泛的一种网络协议。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由统一资源标识符来标识&lt;/p&gt;
 &lt;p&gt;HTTP 协议主要特点&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200634" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;60.数据链路-数据链路层&lt;/h3&gt;
 &lt;blockquote&gt;数据链路层：以太网，无线LAN，PPP。。。(无线，光纤。。。)&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;数据链路的知识对了解TCP/IP与网络起到重要的作用&lt;/li&gt;
  &lt;li&gt;数据链路层的协议定义了通过通信媒介互连的设备传输的规范&lt;/li&gt;
  &lt;li&gt;物理层面是将实际的通信媒介如电压的高低，电波的强弱等信号与二进制01进行转换&lt;/li&gt;
  &lt;li&gt;数据链路层处理的数据是一种集合为“帧”的块&lt;/li&gt;
  &lt;li&gt;WLAN，无线局域网&lt;/li&gt;
  &lt;li&gt;PPP，点对点协议，即是1对1连接计算机的协议&lt;/li&gt;
  &lt;li&gt;ATM，异步传输方式&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;数据链路是让互联网计算机之间相互通信的一种协议，通信手段&lt;/blockquote&gt;
 &lt;ul&gt;  &lt;li&gt;MAC地址用于识别数据链路中互连的节点&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200631" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;无线通信是使用电磁波，红外线，激光等方式进行传播数据。一般在办公室的局域网范围内组成的较高速的连接称为无线局域网。&lt;/li&gt;
  &lt;li&gt;IP-x-x-x，在IP网络上建立x-x-x,网络服务商提供一种在IP网络商使用MPLS技术构建x-x-x的服务。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;61.TCP和UDP的区别&lt;/h3&gt;
 &lt;p&gt;TCP是一个  &lt;strong&gt;面向连接，可靠，基于字节流&lt;/strong&gt;的传输层协议。&lt;/p&gt;
 &lt;p&gt;UDP是一个  &lt;strong&gt;面向无连接&lt;/strong&gt;的传输层协议。&lt;/p&gt;
 &lt;p&gt;TCP是面向连接的，客户端和服务器端的连接，双方互相通信之前，TCP需要三次握手建立连接，而UDP没有建立连接的过程&lt;/p&gt;
 &lt;p&gt;tcp是面向字节流，udp是面向报文的。UDP的数据传输是基于数据报的，TCP继承了IP层的特性，TCP为了维护状态，将一个个IP包变成了字节流。&lt;/p&gt;
 &lt;p&gt;TCP报文格式图：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200632" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200642" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200633" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;序号：Seq序号，占32位，标识从TCP源端口向目的端口发送的字节流，发起方发送数据时，对此进行标记&lt;/li&gt;
  &lt;li&gt;确认序号：Ack序号，占32位，只有ACK标志位为1时，确认序号字段才有效，Ack=Seq+1&lt;/li&gt;
  &lt;li&gt;标志位：共6个，即URG、ACK、PSH、RST、SYN、FIN等&lt;/li&gt;
&lt;/ul&gt;
 &lt;ol&gt;
  &lt;li&gt;URG，紧急指有效&lt;/li&gt;
  &lt;li&gt;ACK，确认序号有效&lt;/li&gt;
  &lt;li&gt;RST，重置连接&lt;/li&gt;
  &lt;li&gt;SYN，发起一个新连接&lt;/li&gt;
  &lt;li&gt;FIN，释放一个连接&lt;/li&gt;
  &lt;li&gt;PSH，接收方应该尽快将这个报文交给应用层&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200639" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;62.三次握手建立连接&lt;/h3&gt;
 &lt;p&gt;TCP 的三次握手的过程:&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200640" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200641" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200646" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;有图可知都处于closed状态，服务器开始监听某个端口进入listen状态，客户端发起请求，发送SYN,seq=x，然后状态变为syn-sent状态。&lt;/p&gt;
 &lt;p&gt;服务器端接收到返回syn和ack,seq=x,ack =x+1,然后状态变成syn-rcvd状态。&lt;/p&gt;
 &lt;p&gt;客户端收到后，发送ack,seq=x+1,ack=y+1给服务器端，状态变为established，服务器收到后，状态变成established。&lt;/p&gt;
 &lt;p&gt;在连接过程中，需要对端确认的，需要消耗TCP报文的序列号。SYN消耗一个序列号而ACK不需要。&lt;/p&gt;
 &lt;p&gt;对于连接四次握手多余，二次握手，会带来资源的浪费，当遇到丢包，重传，连接关闭后，丢包到达服务端，就默认建立连接，可客户端以及关闭，所以三次握手就可以了。&lt;/p&gt;
 &lt;h3&gt;63.四次挥手断开连接&lt;/h3&gt;
 &lt;p&gt;TCP 四次挥手的过程&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200644" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200649" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200648" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200645" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;三次挥手，当服务器将ack和fin合并为一次挥手，会导致长时间的延迟，以至于客户端误认为fin没有到达客户端，让客户端不断重发fin。&lt;/p&gt;
 &lt;h3&gt;64.TCP 滑动窗口&lt;/h3&gt;
 &lt;p&gt;TCP 滑动窗口:&lt;/p&gt;
 &lt;ol&gt;  &lt;li&gt;发送窗口&lt;/li&gt;&lt;/ol&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200647" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ol&gt;  &lt;li&gt;接收窗口&lt;/li&gt;&lt;/ol&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200643" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;65.TCP 的拥塞控制？&lt;/h3&gt;
 &lt;p&gt;TCP连接，拥塞控制：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;拥塞窗口（Congestion Window，cwnd）&lt;/li&gt;
  &lt;li&gt;慢启动阈值（Slow Start Threshold，ssthresh）&lt;/li&gt;
&lt;/ol&gt;
 &lt;blockquote&gt;TCP/IP协议四层&lt;/blockquote&gt;
 &lt;ol&gt;
  &lt;li&gt;应用层决定了向用户提供应用服务时通信的活动。&lt;/li&gt;
  &lt;li&gt;传输层对上层应用层，提供处于网络连接中两台计算机之间的数据传输。&lt;/li&gt;
  &lt;li&gt;网络层用来处理在网络上流动的数据包。&lt;/li&gt;
  &lt;li&gt;链路层，用来处理连接网络的硬件部分。&lt;/li&gt;
&lt;/ol&gt;
 &lt;ul&gt;
  &lt;li&gt;HTTP协议的职责，生成对目标web服务器的HTTP请求报文&lt;/li&gt;
  &lt;li&gt;tcp协议的职责，为了方便通信，将HTTP请求报文分割成报文段&lt;/li&gt;
  &lt;li&gt;IP协议的职责，搜索对方的地址，一边中转一边传送&lt;/li&gt;
  &lt;li&gt;TCP协议的职责，从对方那里接收到的报文段，重组到达的报文段，按序号以原来的顺序重组请求报文&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;66.了解一下DNS&lt;/h3&gt;
 &lt;p&gt;DNS是域名解析系统，它的作用非常简单，就是根据域名查出对应的IP地址。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;从根域名服务器查到顶级域名服务器的NS记录和A记录，IP地址&lt;/li&gt;
  &lt;li&gt;从顶级域名服务器查到次级域名服务器的NS记录和A记录，IP地址&lt;/li&gt;
  &lt;li&gt;从次级域名服务器查出主机名的IP地址&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200651" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000023200650" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;参考文献&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="https://www.cnblogs.com/cangqinglang/p/12315703.html" rel="nofollow noreferrer"&gt;详解浏览器分段请求基础——Range，助你了解断点续传基础&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://segmentfault.com/a/1190000016975064"&gt;HTTP/2协议“多路复用”实现原理&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://blog.csdn.net/u013237862/article/details/70158334" rel="nofollow noreferrer"&gt;协议学习——HTTP2帧结构总结&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://www.ibm.com/developerworks/cn/web/wa-http2-under-the-hood/index.html" rel="nofollow noreferrer"&gt;HTTP/2 幕后原理&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://juejin.im/post/5e527c58e51d4526c654bf41" rel="nofollow noreferrer"&gt;(建议收藏)TCP协议灵魂之问，巩固你的网路底层基础&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://baike.baidu.com/item/https/285356?fr=aladdin" rel="nofollow noreferrer"&gt;https&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.ruanyifeng.com/blog/2016/08/http.html" rel="nofollow noreferrer"&gt;HTTP 协议入门&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies" rel="nofollow noreferrer"&gt;HTTP cookies&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://juejin.im/post/5ecbe211e51d45786672ab61" rel="nofollow noreferrer"&gt;【2】ShutdownHTTP系列-HTTP报文篇&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;《网络是怎样连接的》&lt;/li&gt;
  &lt;li&gt;《图解TCP/IP》&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://juejin.im/post/5e76bd516fb9a07cce750746" rel="nofollow noreferrer"&gt;（建议精读）HTTP灵魂之问，巩固你的 HTTP 知识体系&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;点关注，不迷路&lt;/h3&gt;
 &lt;p&gt;愿你遇到那个心疼你付出的人~&lt;/p&gt;
 &lt;p&gt;囊括前端Vue、JavaScript、数据结构与算法、实战演练、Node全栈一线技术，紧跟业界发展步伐，一个热爱前端的达达程序员。&lt;/p&gt;
 &lt;p&gt;好了各位，以上就是这篇文章的全部内容，能看到这里的人都是人才。我后面会不断更新网络技术相关的文章，如果觉得文章对你有用，欢迎给个“赞”，也欢迎分享，感谢大家 ！！&lt;/p&gt;
 &lt;p&gt;喜欢本文的朋友们，欢迎长按下图关注公众号达达前端，收看更多精彩内容&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000022902508" title=""&gt;&lt;/img&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>前端 html5 html</category>
      <guid isPermaLink="true">https://itindex.net/detail/60776-%E6%99%9A%E4%B8%8A-%E8%AE%A1%E7%AE%97%E6%9C%BA-%E7%BD%91%E7%BB%9C</guid>
      <pubDate>Mon, 13 Jul 2020 10:50:50 CST</pubDate>
    </item>
    <item>
      <title>为什么我们要熟悉这些通信协议？ 【精读】</title>
      <link>https://itindex.net/detail/59874-%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE-%E7%B2%BE%E8%AF%BB</link>
      <description>&lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVD?w=1198&amp;h=868" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h1&gt;前端的最重要的基础知识点是什么？&lt;/h1&gt;
 &lt;ul&gt;
  &lt;li&gt;原生   &lt;code&gt;javaScript&lt;/code&gt;，   &lt;code&gt;HTML&lt;/code&gt;,   &lt;code&gt;CSS&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;Dom&lt;/code&gt;操作&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;EventLoop&lt;/code&gt;和渲染机制&lt;/li&gt;
  &lt;li&gt;各类工程化的工具原理以及使用，根据需求定制编写插件和包。（webpack的plugin和babel的预设包）&lt;/li&gt;
  &lt;li&gt;数据结构和算法（特别是   &lt;code&gt;IM&lt;/code&gt;以及超大型高并发网站应用等，例如   &lt;code&gt;B站&lt;/code&gt;）&lt;/li&gt;
  &lt;li&gt;最后便是通信协议&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;在使用某个技术的时候，一定要去追寻原理和底层的实现，长此以往坚持，只要自身底层的基础扎实，无论技术怎么变化，学习起来都不会太累，总的来说就是拒绝5分钟技术&lt;/blockquote&gt;
 &lt;h2&gt;从输入一个  &lt;code&gt;url&lt;/code&gt;地址，到显示页面发生了什么出发：&lt;/h2&gt;
 &lt;ul&gt;
  &lt;li&gt;1.浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;&lt;/li&gt;
  &lt;li&gt;2.建立TCP连接（三次握手）;&lt;/li&gt;
  &lt;li&gt;3.浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求，该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;&lt;/li&gt;
  &lt;li&gt;4.服务器对浏览器请求作出响应，并把对应的 html 文本发送给浏览器;&lt;/li&gt;
  &lt;li&gt;5.浏览器将该 html 文本并显示内容;&lt;/li&gt;
  &lt;li&gt;6.释放 TCP连接（四次挥手）;&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;目前常见的通信协议都是建立在  &lt;code&gt;TCP&lt;/code&gt;链接之上&lt;/h2&gt;
 &lt;h3&gt;那么什么是  &lt;code&gt;TCP&lt;/code&gt;呢&lt;/h3&gt;
 &lt;h4&gt;TCP是因特网中的传输层协议，使用三次握手协议建立连接。当主动方发出SYN连接请求后，等待对方回答&lt;/h4&gt;
 &lt;blockquote&gt;TCP三次握手的过程如下：&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;客户端发送   &lt;code&gt;SYN&lt;/code&gt;报文给服务器端，进入   &lt;code&gt;SYN_SEND&lt;/code&gt;状态。&lt;/li&gt;
  &lt;li&gt;服务器端收到   &lt;code&gt;SYN&lt;/code&gt;报文，回应一个   &lt;code&gt;SYN&lt;/code&gt;（SEQ=y）ACK（ACK=x+1）报文，进入SYN_RECV状态。&lt;/li&gt;
  &lt;li&gt;客户端收到服务器端的SYN报文，回应一个ACK（ACK=y+1）报文，进入Established状态。&lt;/li&gt;
  &lt;li&gt;三次握手完成，TCP客户端和服务器端成功地建立连接，可以开始传输数据了。&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;如图所示：&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVC?w=1082&amp;h=914" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;
  &lt;code&gt;TCP&lt;/code&gt;的四次挥手：&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;建立一个连接需要三次握手，而终止一个连接要经过四次握手，这是由TCP的半关闭（half-close）造成的。具体过程如下图所示。&lt;/li&gt;
  &lt;li&gt;某个应用进程首先调用close，称该端执行“主动关闭”（active close）。该端的TCP于是发送一个FIN分节，表示数据发送完毕。&lt;/li&gt;
  &lt;li&gt;接收到这个FIN的对端执行 “被动关闭”（passive close），这个FIN由TCP确认。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;注意：FIN的接收也作为一个文件结束符（end-of-file）传递给接收端应用进程，放在已排队等候该应用进程接收的任何其他数据之后，因为，FIN的接收意味着接收端应用进程在相应连接上再无额外数据可接收。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;一段时间后，接收到这个文件结束符的应用进程将调用close关闭它的套接字。这导致它的TCP也发送一个FIN。&lt;/li&gt;
  &lt;li&gt;接收这个最终FIN的原发送端TCP（即执行主动关闭的那一端）确认这个FIN。 [3]&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;既然每个方向都需要一个FIN和一个ACK，因此通常需要4个分节。&lt;/p&gt;
 &lt;blockquote&gt;特别提示：   &lt;code&gt;SYN&lt;/code&gt;报文用来通知，  &lt;code&gt;FIN&lt;/code&gt;报文是用来同步的&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVz?w=1742&amp;h=1194" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;以上就是面试官常问的三次握手，四次挥手，但是这不仅仅面试题，上面仅仅答到了一点皮毛，学习这些是为了让我们后续方便了解他的优缺点。&lt;/blockquote&gt;
 &lt;h2&gt;在  &lt;code&gt;TCP&lt;/code&gt;连接建立后，我们可以有多种协议的方式通信交换数据：&lt;/h2&gt;
 &lt;h3&gt;最古老的方式一：  &lt;code&gt;http 1.0&lt;/code&gt;
&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;早先1.0的HTTP版本，是一种无状态、无连接的应用层协议。&lt;/li&gt;
  &lt;li&gt;HTTP1.0规定浏览器和服务器保持短暂的连接，浏览器的每次请求都需要与服务器建立一个TCP连接，服务器处理完成后立即断开TCP连接（无连接），服务器不跟踪每个客户端也不记录过去的请求（无状态）。&lt;/li&gt;
  &lt;li&gt;这种无状态性可以借助cookie/session机制来做身份认证和状态记录。而下面两个问题就比较麻烦了。&lt;/li&gt;
  &lt;li&gt;首先，无连接的特性导致最大的性能缺陷就是无法复用连接。每次发送请求的时候，都需要进行一次TCP的连接，而TCP的连接释放过程又是比较费事的。这种无连接的特性会使得网络的利用率非常低。&lt;/li&gt;
  &lt;li&gt;其次就是队头阻塞（headoflineblocking）。由于HTTP1.0规定下一个请求必须在前一个请求响应到达之前才能发送。假设前一个请求响应一直不到达，那么下一个请求就不发送，同样的后面的请求也给阻塞了。&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;
  &lt;code&gt;Http 1.0&lt;/code&gt;的致命缺点,就是无法复用  &lt;code&gt;TCP&lt;/code&gt;连接和并行发送请求，这样每次一个请求都需要三次握手，而且其实建立连接和释放连接的这个过程是最耗时的，传输数据相反却不那么耗时。还有本地时间被修改导致响应头  &lt;code&gt;expires&lt;/code&gt;的缓存机制失效的问题～（后面会详细讲）&lt;/blockquote&gt;
 &lt;ul&gt;  &lt;li&gt;常见的请求报文～&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVA?w=1582&amp;h=1432" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;于是出现了  &lt;code&gt;Http 1.1&lt;/code&gt;，这也是技术的发展必然结果～&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;
   &lt;code&gt;Http 1.1&lt;/code&gt;出现，继承了   &lt;code&gt;Http1.0&lt;/code&gt;的优点，也克服了它的缺点，出现了   &lt;code&gt;keep-alive&lt;/code&gt;这个头部字段，它表示会在建立   &lt;code&gt;TCP&lt;/code&gt;连接后，完成首次的请求，并不会立刻断开   &lt;code&gt;TCP&lt;/code&gt;连接，而是保持这个连接状态～进而可以复用这个通道&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;Http 1.1&lt;/code&gt;并且支持请求管道化，“并行”发送请求，但是这个并行，也不是真正意义上的并行，而是可以让我们把先进先出队列从客户端（请求队列）迁移到服务端（响应队列）&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;例如：客户端同时发了两个请求分别来获取html和css，假如说服务器的css资源先准备就绪，服务器也会先发送html再发送css。&lt;/blockquote&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;code&gt;B站&lt;/code&gt;首页，就有   &lt;code&gt;keep-alive&lt;/code&gt;，因为他们也有   &lt;code&gt;IM&lt;/code&gt;的成分在里面。需要大量复用   &lt;code&gt;TCP&lt;/code&gt;连接～&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVE?w=1442&amp;h=1234" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;code&gt;HTTP1.1&lt;/code&gt;好像还是无法解决队头阻塞的问题&lt;/li&gt;&lt;/ul&gt;
 &lt;blockquote&gt;实际上，现阶段的浏览器厂商采取了另外一种做法，它允许我们打开多个TCP的会话。也就是说，上图我们看到的并行，其实是不同的TCP连接上的HTTP请求和响应。这也就是我们所熟悉的浏览器对同域下并行加载6~8个资源的限制。而这，才是真正的并行！&lt;/blockquote&gt;
 &lt;h4&gt;
  &lt;code&gt;Http 1.1&lt;/code&gt;的致命缺点：&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;1.明文传输&lt;/li&gt;
  &lt;li&gt;2.其实还是没有解决无状态连接的&lt;/li&gt;
  &lt;li&gt;3.当有多个请求同时被挂起的时候 就会拥塞请求通道，导致后面请求无法发送&lt;/li&gt;
  &lt;li&gt;4.臃肿的消息首部:HTTP/1.1能压缩请求内容,但是消息首部不能压缩;在现今请求中,消息首部占请求绝大部分(甚至是全部)也较为常见.&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;我们也可以用  &lt;code&gt;dns-prefetch和 preconnect tcp&lt;/code&gt;来优化～&lt;/blockquote&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;link rel=&amp;quot;preconnect&amp;quot; href=&amp;quot;//example.com&amp;quot; crossorigin&amp;gt;
&amp;lt;link rel=&amp;quot;dns=prefetch&amp;quot; href=&amp;quot;//example.com&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;code&gt;Tip&lt;/code&gt;:     &lt;code&gt;webpack&lt;/code&gt;可以做任何事情，这些都可以用插件实现&lt;/li&gt;&lt;/ul&gt;
 &lt;h3&gt;基于这些缺点，出现了  &lt;code&gt;Http 2.0&lt;/code&gt;
&lt;/h3&gt;
 &lt;h4&gt;相较于HTTP1.1，HTTP2.0的主要优点有采用二进制帧封装，传输变成多路复用，流量控制算法优化，服务器端推送，首部压缩，优先级等特点。&lt;/h4&gt;
 &lt;h4&gt;HTTP1.x的解析是基于文本的，基于文本协议的格式解析存在天然缺陷，文本的表现形式有多样性，要做到健壮性考虑的场景必然很多。而HTTP/2会将所有传输的信息分割为更小的消息和帧，然后采用二进制的格式进行编码，HTTP1.x的头部信息会被封装到HEADER frame，而相应的RequestBody则封装到DATAframe里面。不改动HTTP的语义，使用二进制编码，实现方便且健壮。&lt;/h4&gt;
 &lt;h4&gt;多路复用&lt;/h4&gt;
 &lt;ul&gt;  &lt;li&gt;所有的请求都是通过一个 TCP 连接并发完成。HTTP/1.x 虽然通过 pipeline 也能并发请求，但是多个请求之间的响应会被阻塞的，所以 pipeline 至今也没有被普及应用，而 HTTP/2 做到了真正的并发请求。同时，流还支持优先级和流量控制。当流并发时，就会涉及到流的优先级和依赖。即：HTTP2.0对于同一域名下所有请求都是基于流的，不管对于同一域名访问多少文件，也只建立一路连接。优先级高的流会被优先发送。图片请求的优先级要低于 CSS 和 SCRIPT，这个设计可以确保重要的东西可以被优先加载完&lt;/li&gt;&lt;/ul&gt;
 &lt;h4&gt;流量控制&lt;/h4&gt;
 &lt;ul&gt;  &lt;li&gt;TCP协议通过sliding window的算法来做流量控制。发送方有个sending window，接收方有receive window。http2.0的flow control是类似receive window的做法，数据的接收方通过告知对方自己的flow window大小表明自己还能接收多少数据。只有Data类型的frame才有flow control的功能。对于flow control，如果接收方在flow window为零的情况下依然更多的frame，则会返回block类型的frame，这张场景一般表明http2.0的部署出了问题。&lt;/li&gt;&lt;/ul&gt;
 &lt;h4&gt;服务器端推送&lt;/h4&gt;
 &lt;ul&gt;  &lt;li&gt;服务器端的推送，就是服务器可以对一个客户端请求发送多个响应。除了对最初请求的响应外，服务器还可以额外向客户端推送资源，而无需客户端明确地请求。当浏览器请求一个html，服务器其实大概知道你是接下来要请求资源了，而不需要等待浏览器得到html后解析页面再发送资源请求。&lt;/li&gt;&lt;/ul&gt;
 &lt;h4&gt;首部压缩&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;HTTP 2.0 在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对，对于相同的数据，不再通过每次请求和响应发送;通信期间几乎不会改变的通用键-值对(用户代理、可接受的媒体类型,等等)只 需发送一次。事实上,如果请求中不包含首部(例如对同一资源的轮询请求),那么 首部开销就是零字节。此时所有首部都自动使用之前请求发送的首部。&lt;/li&gt;
  &lt;li&gt;如果首部发生变化了，那么只需要发送变化了数据在Headers帧里面，新增或修改的首部帧会被追加到“首部表”。首部表在 HTTP 2.0 的连接存续期内始终存在,由客户端和服务器共同渐进地更新 。&lt;/li&gt;
  &lt;li&gt;本质上，当然是为了减少请求啦，通过多个js或css合并成一个文件，多张小图片拼合成Sprite图，可以让多个HTTP请求减少为一个，减少额外的协议开销，而提升性能。当然，一个HTTP的请求的body太大也是不合理的，有个度。文件的合并也会牺牲模块化和缓存粒度，可以把“稳定”的代码or 小图 合并为一个文件or一张Sprite，让其充分地缓存起来，从而区分开迭代快的文件。&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;
  &lt;code&gt;Demo&lt;/code&gt;的性能对比：&lt;/blockquote&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVH?w=1700&amp;h=938" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;
  &lt;code&gt;Http&lt;/code&gt;的那些致命缺陷，并没有完全解决，于是有了  &lt;code&gt;https&lt;/code&gt;，也是目前应用最广的协议之一&lt;/h2&gt;
 &lt;h3&gt;
  &lt;code&gt;HTTP+ 加密 + 认证 + 完整性保护 =HTTPS &lt;/code&gt; ?&lt;/h3&gt;
 &lt;h4&gt;可以这样认为～HTTP 加上加密处理和认证以及完整性保护后即是 HTTPS&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;如果在 HTTP 协议通信过程中使用未经加密的明文，比如在 Web 页面中输入信用卡号，如果这条通信线路遭到窃听，那么信用卡号就暴露了。&lt;/li&gt;
  &lt;li&gt;另外，对于 HTTP 来说，服务器也好，客户端也好，都是没有办法确认通信方的。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;因为很有可能并不是和原本预想的通信方在实际通信。并且还需要考虑到接收到的报文在通信途中已经遭到篡改这一可能性。&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;为了统一解决上述这些问题，需要在 HTTP 上再加入加密处理和认证等机制。我们把添加了加密及认证机制的 HTTP 称为 HTTPS&lt;/li&gt;&lt;/ul&gt;
 &lt;blockquote&gt;不加密的重要内容被  &lt;code&gt;wireshark&lt;/code&gt;这类工具抓到包，后果很严重～&lt;/blockquote&gt;
 &lt;h3&gt;HTTPS 是身披 SSL 外壳的 HTTP&lt;/h3&gt;
 &lt;ul&gt;  &lt;li&gt;HTTPS 并非是应用层的一种新协议。只是 HTTP 通信接口部分用 SSL（SecureSocket Layer）和 TLS（Transport Layer Security）协议代替而已。&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;通常，HTTP 直接和 TCP 通信。&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;当使用 SSL 时，则演变成先和 SSL 通信，再由 SSL和 TCP 通信了。简言之，所谓 HTTPS，其实就是身披 SSL 协议这层外壳的HTTP。&lt;/li&gt;
  &lt;li&gt;在采用 SSL 后，HTTP 就拥有了 HTTPS 的加密、证书和完整性保护这些功能。SSL 是独立于 HTTP 的协议，所以不光是 HTTP 协议，其他运行在应用层的 SMTP和 Telnet 等协议均可配合 SSL 协议使用。可以说 SSL 是当今世界上应用最为广泛的网络安全术。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVI?w=1736&amp;h=740" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;相互交换密钥的公开密钥加密技术 -----对称加密&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVM?w=1720&amp;h=1310" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;在对 SSL 进行讲解之前，我们先来了解一下加密方法。SSL 采用一种叫做公开密钥加密（Public-key cryptography）的加密处理方式。&lt;/li&gt;
  &lt;li&gt;近代的加密方法中加密算法是公开的，而密钥却是保密的。通过这种方式得以保持加密方法的安全性。&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;加密和解密都会用到密钥。没有密钥就无法对密码解密，反过来说，任何人只要持有密钥就能解密了。如果密钥被攻击者获得，那加密也就失去了意义。&lt;/blockquote&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;a href="https://blog.csdn.net/ituling/article/details/52541585" rel="nofollow noreferrer"&gt;https://blog.csdn.net/ituling...&lt;/a&gt;，    &lt;code&gt;Https&lt;/code&gt;加密篇幅太长，这篇文章写得很好，大家可以去看看。&lt;/li&gt;&lt;/ul&gt;
 &lt;h4&gt;HTTPS 采用混合加密机制&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;HTTPS 采用共享密钥加密和公开密钥加密两者并用的混合加密机制。&lt;/li&gt;
  &lt;li&gt;但是公开密钥加密与共享密钥加密相比，其处理速度要慢。所以应充分利用两者各自的优势，将多种方法组合起来用于通信。在交换密钥环节使用公开密钥加密方式，之后的建立通信交换报文阶段则使用共享密钥加密方式。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;
  &lt;code&gt;HTTPS&lt;/code&gt;虽好，非对称加密虽好，但是不要滥用&lt;/h2&gt;
 &lt;h3&gt;HTTPS 也存在一些问题，那就是当使用 SSL 时，它的处理速度会变慢。&lt;/h3&gt;
 &lt;h4&gt;SSL 的慢分两种。一种是指通信慢。另一种是指由于大量消耗 CPU 及内存等资源，导致处理速度变慢。&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;和使用 HTTP 相比，网络负载可能会变慢 2 到 100 倍。除去和 TCP 连接、发送 HTTP 请求 ? 响应以外，还必须进行 SSL 通信，因此整体上处理通信量不可避免会增加。&lt;/li&gt;
  &lt;li&gt;另一点是 SSL 必须进行加密处理。在服务器和客户端都需要进行加密和解密的运算处理。因此从结果上讲，比起 HTTP 会更多地消耗服务器和客户端的硬件资源，导致负载增强。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;针对速度变慢这一问题，并没有根本性的解决方案，我们会使用 SSL 加速器这种（专用服务器）硬件来改善该问题。该硬件为 SSL 通信专用硬件，相对软件来讲，能够提高数倍 SSL 的计算速度。仅在 SSL 处理时发挥 SSL加速器的功效，以分担负载。&lt;/p&gt;
 &lt;h2&gt;为什么不一直使用 HTTPS&lt;/h2&gt;
 &lt;ul&gt;  &lt;li&gt;既然 HTTPS 那么安全可靠，那为何所有的 Web 网站不一直使用 HTTPS？&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;其中一个原因是，因为与纯文本通信相比，加密通信会消耗更多的 CPU 及内存资源。如果每次通信都加密，会消耗相当多的资源，平摊到一台计算机上时，能够处理的请求数量必定也会随之减少。&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;因此，如果是非敏感信息则使用 HTTP 通信，只有在包含个人信息等敏感数据时，才利用 HTTPS 加密通信。&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;特别是每当那些访问量较多的 Web 网站在进行加密处理时，它们所承担着的负载不容小觑。在进行加密处理时，并非对所有内容都进行加密处理，而是仅在那些需要信息隐藏时才会加密，以节约资源。&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;除此之外，想要节约购买证书的开销也是原因之一。&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;要进行 HTTPS 通信，证书是必不可少的。而使用的证书必须向认证机构（CA）购买。证书价格可能会根据不同的认证机构略有不同。通常，一年的授权需要数万日元（现在一万日元大约折合 600 人民币）。那些购买证书并不合算的服务以及一些个人网站，可能只会选择采用HTTP 的通信方式。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVR?w=1158&amp;h=1002" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;复习完了基本的协议，介绍下报文格式：&lt;/h2&gt;
 &lt;ul&gt;  &lt;li&gt;请求报文格式&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVT?w=1728&amp;h=852" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;响应报文格式&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVU?w=1614&amp;h=690" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;所谓响应头，请求头，其实都可以自己添加字段，只要前后端给对应的处理机制即可&lt;/blockquote&gt;
 &lt;h2&gt;
  &lt;code&gt;Node.js&lt;/code&gt;代码实现响应头的设置&lt;/h2&gt;
 &lt;pre&gt;  &lt;code&gt;
  if (config.cache.expires) {
                        res.setHeader(&amp;quot;expries&amp;quot;, new Date(Date.now() + (config.cache.maxAge * 1000)))
                    }
                    if (config.cache.lastModified) {
                        res.setHeader(&amp;quot;last-modified&amp;quot;, stat.mtime.toUTCString())
                    }
                    if (config.cache.etag) {
                        res.setHeader(&amp;apos;Etag&amp;apos;, etagFn(stat))
                    }
}&lt;/code&gt;&lt;/pre&gt;
 &lt;h2&gt;响应头的详解：&lt;/h2&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVW?w=1760&amp;h=1426" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;本人的开源项目，手写的  &lt;code&gt;Node.js&lt;/code&gt;静态资源服务器，  &lt;a href="https://github.com/JinJieTan/util-static-server" rel="nofollow noreferrer"&gt;https://github.com/JinJieTan/...&lt;/a&gt;，欢迎   &lt;code&gt;star&lt;/code&gt;~&lt;/h3&gt;
 &lt;h2&gt;浏览器的缓存策略：&lt;/h2&gt;
 &lt;ul&gt;  &lt;li&gt;首次请求：&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVX?w=1642&amp;h=1088" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;非首次请求：&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCVZ?w=1528&amp;h=1316" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;用户行为与缓存：&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbvCV0?w=1606&amp;h=1374" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;不能缓存的请求：&lt;/h2&gt;
 &lt;h3&gt;无法被浏览器缓存的请求如下：&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;HTTP信息头中包含Cache-Control:no-cache，pragma:no-cache（HTTP1.0），或Cache-Control:max-age=0等告诉浏览器不用缓存的请求&lt;/li&gt;
  &lt;li&gt;需要根据Cookie，认证信息等决定输入内容的动态请求是不能被缓存的&lt;/li&gt;
  &lt;li&gt;经过HTTPS安全加密的请求（有人也经过测试发现，ie其实在头部加入Cache-Control：max-age信息，firefox在头部加入Cache-Control:Public之后，能够对HTTPS的资源进行缓寸）&lt;/li&gt;
  &lt;li&gt;经过HTTPS安全加密的请求（有人也经过测试发现，ie其实在头部加入Cache-Control：max-age信息，firefox在头部加入Cache-Control:Public之后，能够对HTTPS的资源进行缓存，参考《HTTPS的七个误解》）&lt;/li&gt;
  &lt;li&gt;POST请求无法被缓存&lt;/li&gt;
  &lt;li&gt;HTTP响应头中不包含Last-Modified/Etag，也不包含Cache-Control/Expires的请求无法被缓存&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;即时通讯协议&lt;/h2&gt;
 &lt;h3&gt;从最初的没有  &lt;code&gt;websocket&lt;/code&gt;协议开始：&lt;/h3&gt;
 &lt;blockquote&gt;传统的协议无法服务端主动  &lt;code&gt;push&lt;/code&gt;数据，于是有了这些骚操作：&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;轮询，在一个定时器中不停向服务端发送请求。&lt;/li&gt;
  &lt;li&gt;长轮询，发送请求给服务端，直到服务端觉得可以返回数据了再返回响应，否则这个请求一直挂起～&lt;/li&gt;
  &lt;li&gt;以上两种都有瑕疵，而且比较明显，这里不再描述。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;为了解决实时通讯，数据同步的问题，出现了  &lt;code&gt;webSocket&lt;/code&gt;.&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;
   &lt;code&gt;webSockets&lt;/code&gt;的目标是在一个单独的持久连接上提供全双工、双向通信。在Javascript创建了Web Socket之后，会有一个HTTP请求发送到浏览器以发起连接。在取得服务器响应后，建立的连接会将HTTP升级从HTTP协议交换为WebSocket协议。&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;webSocket&lt;/code&gt;原理： 在   &lt;code&gt;TCP&lt;/code&gt;连接第一次握手的时候，升级为   &lt;code&gt;ws&lt;/code&gt;协议。后面的数据交互都复用这个   &lt;code&gt;TCP&lt;/code&gt;通道。&lt;/li&gt;
  &lt;li&gt;客户端代码实现：&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;  &lt;code&gt;  const ws = new WebSocket(&amp;apos;ws://localhost:8080&amp;apos;);
        ws.onopen = function () {
            ws.send(&amp;apos;123&amp;apos;)
            console.log(&amp;apos;open&amp;apos;)
        }
        ws.onmessage = function () {
            console.log(&amp;apos;onmessage&amp;apos;)
        }
        ws.onerror = function () {
            console.log(&amp;apos;onerror&amp;apos;)
        }
        ws.onclose = function () {
            console.log(&amp;apos;onclose&amp;apos;)
        }&lt;/code&gt;&lt;/pre&gt;
 &lt;ul&gt;  &lt;li&gt;服务端使用    &lt;code&gt;Node.js&lt;/code&gt;语言实现&lt;/li&gt;&lt;/ul&gt;
 &lt;pre&gt;  &lt;code&gt;const express = require(&amp;apos;express&amp;apos;)
const { Server } = require(&amp;quot;ws&amp;quot;);
const app = express()
const wsServer = new Server({ port: 8080 })
wsServer.on(&amp;apos;connection&amp;apos;, (ws) =&amp;gt; {
    ws.onopen = function () {
        console.log(&amp;apos;open&amp;apos;)
    }
    ws.onmessage = function (data) {
        console.log(data)
        ws.send(&amp;apos;234&amp;apos;)
        console.log(&amp;apos;onmessage&amp;apos; + data)
    }
    ws.onerror = function () {
        console.log(&amp;apos;onerror&amp;apos;)
    }
    ws.onclose = function () {
        console.log(&amp;apos;onclose&amp;apos;)
    }
});

app.listen(8000, (err) =&amp;gt; {
    if (!err) { console.log(&amp;apos;监听OK&amp;apos;) } else {
        console.log(&amp;apos;监听失败&amp;apos;)
    }
})&lt;/code&gt;&lt;/pre&gt;
 &lt;h2&gt;
  &lt;code&gt;webSocket&lt;/code&gt;的报文格式有一些不一样：&lt;/h2&gt;
 &lt;p&gt;![图片上传中...]&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;p&gt;客户端和服务端进行Websocket消息传递是这样的:&lt;/p&gt;
   &lt;ul&gt;
    &lt;li&gt;客户端：将消息切割成多个帧，并发送给服务端。&lt;/li&gt;
    &lt;li&gt;服务端：接收消息帧，并将关联的帧重新组装成完整的消息。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
 &lt;h2&gt;即时通讯的心跳检测：&lt;/h2&gt;
 &lt;h3&gt;
  &lt;code&gt;ping&lt;/code&gt;and  &lt;code&gt;pong&lt;/code&gt;
&lt;/h3&gt;
 &lt;ul&gt;  &lt;li&gt;服务端   &lt;code&gt;Go&lt;/code&gt;实现：&lt;/li&gt;&lt;/ul&gt;
 &lt;pre&gt;  &lt;code&gt;package main

import (
    &amp;quot;net/http&amp;quot;
    &amp;quot;time&amp;quot;

    &amp;quot;github.com/gorilla/websocket&amp;quot;
)

var (
    //完成握手操作
    upgrade = websocket.Upgrader{
       //允许跨域(一般来讲,websocket都是独立部署的)
       CheckOrigin:func(r *http.Request) bool {
            return true
       },
    }
)

func wsHandler(w http.ResponseWriter, r *http.Request) {
   var (
         conn *websocket.Conn
         err error
         data []byte
   )
   //服务端对客户端的http请求(升级为websocket协议)进行应答，应答之后，协议升级为websocket，http建立连接时的tcp三次握手将保持。
   if conn, err = upgrade.Upgrade(w, r, nil); err != nil {
        return
   }

    //启动一个协程，每隔5s向客户端发送一次心跳消息
    go func() {
        var (
            err error
        )
        for {
            if err = conn.WriteMessage(websocket.TextMessage, []byte(&amp;quot;heartbeat&amp;quot;)); err != nil {
                return
            }
            time.Sleep(5 * time.Second)
        }
    }()

   //得到websocket的长链接之后,就可以对客户端传递的数据进行操作了
   for {
         //通过websocket长链接读到的数据可以是text文本数据，也可以是二进制Binary
        if _, data, err = conn.ReadMessage(); err != nil {
            goto ERR
     }
     if err = conn.WriteMessage(websocket.TextMessage, data); err != nil {
         goto ERR
     }
   }
ERR:
    //出错之后，关闭socket连接
    conn.Close()
}

func main() {
    http.HandleFunc(&amp;quot;/ws&amp;quot;, wsHandler)
    http.ListenAndServe(&amp;quot;0.0.0.0:7777&amp;quot;, nil)
}&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;客户端的心跳检测(  &lt;code&gt;Node.js&lt;/code&gt;实现)：&lt;/h3&gt;
 &lt;pre&gt;  &lt;code&gt;this.heartTimer = setInterval(() =&amp;gt; {
      if (this.heartbeatLoss &amp;lt; MAXLOSSTIMES) {
        events.emit(&amp;apos;network&amp;apos;, &amp;apos;sendHeart&amp;apos;);
        this.heartbeatLoss += 1;
        this.phoneLoss += 1;
      } else {
        events.emit(&amp;apos;network&amp;apos;, &amp;apos;offline&amp;apos;);
        this.stop();
      }
      if (this.phoneLoss &amp;gt; MAXLOSSTIMES) {
        this.PhoneLive = false;
        events.emit(&amp;apos;network&amp;apos;, &amp;apos;phoneDisconnect&amp;apos;);
      }
    }, 5000);
&lt;/code&gt;&lt;/pre&gt;
 &lt;h2&gt;自定义即时通信协议：&lt;/h2&gt;
 &lt;h3&gt;从  &lt;code&gt;new Socket&lt;/code&gt;开始：&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;目前即时通讯大都使用现有大公司成熟的   &lt;code&gt;SDK&lt;/code&gt;接入，但是逼格高些还是自己重写比较好。&lt;/li&gt;
  &lt;li&gt;打个小广告，我们公司就是自己定义的即时通讯协议～招聘一位高级前端，地点深圳-深南大道，做跨平台   &lt;code&gt;IM&lt;/code&gt;桌面应用开发的～&lt;/li&gt;
  &lt;li&gt;客户端代码实现（Node.js）:&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;  &lt;code&gt;
const {Socket} = require(&amp;apos;net&amp;apos;) 
const tcp = new Socket()
tcp.setKeepAlive(true);
tcp.setNoDelay(true);
//保持底层tcp链接不断，长连接
指定对应域名端口号链接
tcp.connect(80,166.166.0.0)
建立连接后
根据后端传送的数据类型 使用对应不同的解析
readUInt8 readUInt16LE readUInt32LE readIntLE等处理后得到myBuf 
const myBuf = buffer.slice(start);//从对应的指针开始的位置截取buffer
const header = myBuf.slice(headstart,headend)//截取对应的头部buffer
const body = JSON.parse(myBuf.slice(headend-headstart,bodylength).tostring())
//精确截取数据体的buffer,并且转化成js对象&lt;/code&gt;&lt;/pre&gt;
 &lt;blockquote&gt;即时通讯强烈推荐使用  &lt;code&gt;Golang&lt;/code&gt;,  &lt;code&gt;GRPC&lt;/code&gt;,  &lt;code&gt;Prob&lt;/code&gt;传输数据。&lt;/blockquote&gt;
 &lt;h2&gt;上面的一些代码，都在我的开源项目中：&lt;/h2&gt;
 &lt;ul&gt;
  &lt;li&gt;手写的静态资源服务器,   &lt;a href="https://github.com/JinJieTan/util-static-server" rel="nofollow noreferrer"&gt;https://github.com/JinJieTan/...&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;webpack-electron-react-websocket&lt;/code&gt;的Demo,    &lt;a href="https://github.com/JinJieTan/react-electron-webpack" rel="nofollow noreferrer"&gt;https://github.com/JinJieTan/...&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;觉得写得不错，可以点个赞支持下，文章也借鉴了一下其他大佬的文章，但是地址都贴上来了～ 欢迎  &lt;code&gt;gitHub&lt;/code&gt;点个  &lt;code&gt;star&lt;/code&gt;哦～&lt;/blockquote&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>html5 html css node.js javascript</category>
      <guid isPermaLink="true">https://itindex.net/detail/59874-%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE-%E7%B2%BE%E8%AF%BB</guid>
      <pubDate>Sat, 27 Jul 2019 13:07:04 CST</pubDate>
    </item>
    <item>
      <title>使用Node.js爬取任意网页资源并输出高质量PDF文件到本地~</title>
      <link>https://itindex.net/detail/59698-node-js-%E7%BD%91%E9%A1%B5</link>
      <description>&lt;p&gt;  &lt;img alt="detail?ct=503316480&amp;z=0&amp;ipn=d&amp;word=%E6%B5%B7%E8%BE%B9%E5%A3%81%E7%BA%B8&amp;hs=2&amp;pn=0&amp;spn=0&amp;di=10120&amp;pi=0&amp;rn=1&amp;tn=baiduimagedetail&amp;is=0%2C0&amp;ie=utf-8&amp;oe=utf-8&amp;cl=2&amp;lm=-1&amp;cs=3590237416%2C2845421745&amp;os=3026828862%2C3835093178&amp;simid=0%2C0&amp;adpicid=0&amp;lpn=0&amp;ln=30&amp;fr=ala&amp;fm=&amp;sme=&amp;cg=&amp;bdtype=0&amp;oriquery=%E6%B5%B7%E8%BE%B9%E5%A3%81%E7%BA%B8&amp;objurl=http%3A%2F%2Fabc.2008php.com%2F2017_Website_appreciate%2F2017-10-09%2F20171009204205.jpg&amp;fromurl=ippr_z2C%24qAzdH3FAzdH3Fwkv_z%26e3Bdaabrir_z%26e3Bv54AzdH3Fp7h7AzdH3Fda80AzdH3F8aalAzdH3Flcblld_z%26e3Bip4s&amp;gsm=0&amp;islist=&amp;querylist=" src="https://segmentfault.com/img/bVbtVeV?w=3840&amp;h=2160" title="detail?ct=503316480&amp;z=0&amp;ipn=d&amp;word=%E6%B5%B7%E8%BE%B9%E5%A3%81%E7%BA%B8&amp;hs=2&amp;pn=0&amp;spn=0&amp;di=10120&amp;pi=0&amp;rn=1&amp;tn=baiduimagedetail&amp;is=0%2C0&amp;ie=utf-8&amp;oe=utf-8&amp;cl=2&amp;lm=-1&amp;cs=3590237416%2C2845421745&amp;os=3026828862%2C3835093178&amp;simid=0%2C0&amp;adpicid=0&amp;lpn=0&amp;ln=30&amp;fr=ala&amp;fm=&amp;sme=&amp;cg=&amp;bdtype=0&amp;oriquery=%E6%B5%B7%E8%BE%B9%E5%A3%81%E7%BA%B8&amp;objurl=http%3A%2F%2Fabc.2008php.com%2F2017_Website_appreciate%2F2017-10-09%2F20171009204205.jpg&amp;fromurl=ippr_z2C%24qAzdH3FAzdH3Fwkv_z%26e3Bdaabrir_z%26e3Bv54AzdH3Fp7h7AzdH3Fda80AzdH3F8aalAzdH3Flcblld_z%26e3Bip4s&amp;gsm=0&amp;islist=&amp;querylist="&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;本文适合无论是否有爬虫以及  &lt;code&gt;Node.js&lt;/code&gt;基础的朋友观看~&lt;/blockquote&gt;
 &lt;h5&gt;需求：&lt;/h5&gt;
 &lt;ul&gt;
  &lt;li&gt;使用   &lt;code&gt;Node.js&lt;/code&gt;爬取网页资源，开箱即用的配置&lt;/li&gt;
  &lt;li&gt;将爬取到的网页内容以   &lt;code&gt;PDF&lt;/code&gt;格式输出&lt;/li&gt;
&lt;/ul&gt;
 &lt;h5&gt;如果你是一名技术人员，那么可以看我接下来的文章，否则，请直接移步到我的  &lt;code&gt;github&lt;/code&gt;仓库，直接看文档使用即可&lt;/h5&gt;
 &lt;h4&gt;仓库地址:  &lt;a href="https://github.com/JinJieTan/puppeteer-pdf" rel="nofollow noreferrer"&gt;附带文档和源码&lt;/a&gt;,别忘了给个  &lt;code&gt;star&lt;/code&gt;哦&lt;/h4&gt;
 &lt;h4&gt;本需求使用到的技术：  &lt;code&gt;Node.js&lt;/code&gt;和  &lt;code&gt;puppeteer&lt;/code&gt;
&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;
   &lt;code&gt;puppeteer&lt;/code&gt; 官网地址:    &lt;a href="https://zhaoqize.github.io/puppeteer-api-zh_CN/#/" rel="nofollow noreferrer"&gt;puppeteer地址&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;Node.js&lt;/code&gt;官网地址:   &lt;a href="http://nodejs.cn/" rel="nofollow noreferrer"&gt;链接描述&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;Puppeteer&lt;/code&gt;是谷歌官方出品的一个通过   &lt;code&gt;DevTools&lt;/code&gt;协议控制   &lt;code&gt;headless Chrome&lt;/code&gt;的   &lt;code&gt;Node&lt;/code&gt;库。可以通过Puppeteer的提供的api直接控制Chrome模拟大部分用户操作来进行UI Test或者作为爬虫访问页面来收集数据。&lt;/li&gt;
  &lt;li&gt;环境和安装&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;Puppeteer&lt;/code&gt;本身依赖6.4以上的Node，但是为了异步超级好用的   &lt;code&gt;async/await&lt;/code&gt;，推荐使用7.6版本以上的Node。另外headless Chrome本身对服务器依赖的库的版本要求比较高，centos服务器依赖偏稳定，v6很难使用headless Chrome，提升依赖版本可能出现各种服务器问题（包括且不限于无法使用ssh），最好使用高版本服务器。（建议使用最新版本的   &lt;code&gt;Node.js&lt;/code&gt;）&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;小试牛刀，爬取京东资源&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;const puppeteer = require(&amp;apos;puppeteer&amp;apos;); //  引入依赖  
(async () =&amp;gt; {   //使用async函数完美异步 
    const browser = await puppeteer.launch();  //打开新的浏览器
    const page = await browser.newPage();   // 打开新的网页 
    await page.goto(&amp;apos;https://www.jd.com/&amp;apos;);  //前往里面 &amp;apos;url&amp;apos; 的网页
    const result = await page.evaluate(() =&amp;gt; {   //这个result数组包含所有的图片src地址
        let arr = []; //这个箭头函数内部写处理的逻辑  
        const imgs = document.querySelectorAll(&amp;apos;img&amp;apos;);
        imgs.forEach(function (item) {
            arr.push(item.src)
        })
        return arr 
    });
    // &amp;apos;此时的result就是得到的爬虫数据，可以通过&amp;apos;fs&amp;apos;模块保存&amp;apos;
})()

  复制过去 使用命令行命令 ` node 文件名 ` 就可以运行获取爬虫数据了 
这个 puppeteer 的包 ，其实是替我们开启了另一个浏览器，重新去开启网页，获取它们的数据。
&lt;/code&gt;&lt;/pre&gt;
 &lt;ul&gt;  &lt;li&gt;上面只爬取了京东首页的图片内容，假设我的需求进一步扩大，需要爬取京东首页&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;中的所有  &lt;code&gt;&amp;lt;a&amp;gt; 标签对应的跳转网页中的所有 title的文字内容，最后放到一个数组中&lt;/code&gt;。&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;我们的   &lt;code&gt;async&lt;/code&gt;函数上面一共分了五步， 只有    &lt;code&gt;puppeteer.launch()&lt;/code&gt; ,&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;  &lt;code&gt;browser.newPage()&lt;/code&gt;,   &lt;code&gt; browser.close()&lt;/code&gt; 是固定的写法。&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;code&gt; page.goto&lt;/code&gt; 指定我们去哪个网页爬取数据，可以更换内部url地址，也可以多次&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;调用这个方法。&lt;/p&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;code&gt; page.evaluate&lt;/code&gt; 这个函数，内部是处理我们进入想要爬取网页的数据逻辑&lt;/li&gt;&lt;/ul&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;code&gt;page.goto&lt;/code&gt;和   &lt;code&gt; page.evaluate&lt;/code&gt;两个方法，可以在   &lt;code&gt;async&lt;/code&gt;内部调用多次，&lt;/li&gt;&lt;/ul&gt;
 &lt;p&gt;那意味着我们可以先进入京东网页，处理逻辑后，再次调用  &lt;code&gt;page.goto&lt;/code&gt;这个函数，&lt;/p&gt;
 &lt;blockquote&gt;注意，上面这一切逻辑，都是  &lt;code&gt;puppeteer&lt;/code&gt;这个包帮我们在看不见的地方开启了另外一个  &lt;br /&gt;浏览器，然后处理逻辑，所以最终要调用  &lt;code&gt;browser.close()&lt;/code&gt;方法关闭那个浏览器。&lt;/blockquote&gt;
 &lt;p&gt;这时候我们对上一篇的代码进行优化，爬取对应的资源。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt; const puppeteer = require(&amp;apos;puppeteer&amp;apos;);
(async () =&amp;gt; {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto(&amp;apos;https://www.jd.com/&amp;apos;);
    const hrefArr = await page.evaluate(() =&amp;gt; {
        let arr = [];
        const aNodes = document.querySelectorAll(&amp;apos;.cate_menu_lk&amp;apos;);
        aNodes.forEach(function (item) {
            arr.push(item.href)
        })
        return arr
    });
    let arr = [];
    for (let i = 0; i &amp;lt; hrefArr.length; i++) {
        const url = hrefArr[i];
        console.log(url) //这里可以打印 
        await page.goto(url);
        const result = await page.evaluate(() =&amp;gt; { //这个方法内部console.log无效 
            
              return  $(&amp;apos;title&amp;apos;).text();  //返回每个界面的title文字内容
        });
        arr.push(result)  //每次循环给数组中添加对应的值
    }
    console.log(arr)  //得到对应的数据  可以通过Node.js的 fs 模块保存到本地
    await browser.close()
})()
&lt;/code&gt;&lt;/pre&gt;
 &lt;blockquote&gt;上面有天坑   page.evaluate函数内部的console.log不能打印，而且内部不能获取外部的变量,只能return返回，  &lt;br /&gt;使用的选择器必须先去对应界面的控制台实验过能不能选择DOM再使用，比如京东无法使用querySelector。这里由于  &lt;br /&gt;京东的分界面都使用了jQuery，所以我们可以用jQuery，总之他们开发能用的选择器，我们都可以用，否则就不可以。&lt;/blockquote&gt;
 &lt;h4&gt;接下来我们直接来爬取  &lt;code&gt;Node.js&lt;/code&gt;的官网首页然后直接生成  &lt;code&gt;PDF&lt;/code&gt;
&lt;/h4&gt;
 &lt;h5&gt;无论您是否了解Node.js和puppeteer的爬虫的人员都可以操作，请您一定万分仔细阅读本文档并按顺序执行每一步&lt;/h5&gt;
 &lt;blockquote&gt;本项目实现需求：给我们一个网页地址，爬取他的网页内容，然后输出成我们想要的PDF格式文档，请注意，是高质量的PDF文档&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;第一步，安装   &lt;code&gt;Node.js&lt;/code&gt; ,推荐   &lt;code&gt;http://nodejs.cn/download/&lt;/code&gt;，   &lt;code&gt;Node.js&lt;/code&gt;的中文官网下载对应的操作系统包&lt;/li&gt;
  &lt;li&gt;第二步，在下载安装完了   &lt;code&gt;Node.js&lt;/code&gt;后， 启动   &lt;code&gt;windows&lt;/code&gt;命令行工具(windows下启动系统搜索功能，输入cmd，回车，就出来了)&lt;/li&gt;
  &lt;li&gt;第三步 需要查看环境变量是否已经自动配置,在命令行工具中输入    &lt;code&gt;node -v&lt;/code&gt;，如果出现    &lt;code&gt;v10. ***&lt;/code&gt;字段，则说明成功安装   &lt;code&gt;Node.js&lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;第四步 如果您在第三步发现输入   &lt;code&gt;node -v&lt;/code&gt;还是没有出现 对应的字段，那么请您重启电脑即可&lt;/li&gt;
  &lt;li&gt;第五步 打开本项目文件夹，打开命令行工具（windows系统中直接在文件的   &lt;code&gt;url&lt;/code&gt;地址栏输入   &lt;code&gt;cmd&lt;/code&gt;就可以打开了），输入    &lt;code&gt;npm i cnpm  nodemon -g &lt;/code&gt;
&lt;/li&gt;
  &lt;li&gt;第六步 下载   &lt;code&gt;puppeteer&lt;/code&gt;爬虫包，在完成第五步后，使用   &lt;code&gt;cnpm i puppeteer --save &lt;/code&gt;命令 即可下载&lt;/li&gt;
  &lt;li&gt;第七步 完成第六步下载后，打开本项目的   &lt;code&gt;url.js&lt;/code&gt;，将您需要爬虫爬取的网页地址替换上去(默认是   &lt;code&gt;http://nodejs.cn/&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;第八步 在命令行中输入    &lt;code&gt;nodemon index.js&lt;/code&gt; 即可爬取对应的内容，并且自动输出到当前文件夹下面的   &lt;code&gt;index.pdf&lt;/code&gt;文件中&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;
  &lt;code&gt;TIPS&lt;/code&gt;: 本项目设计思想就是一个网页一个  &lt;code&gt;PDF&lt;/code&gt;文件，所以每次爬取一个单独页面后，请把  &lt;code&gt;index.pdf&lt;/code&gt;拷贝出去，然后继续更换  &lt;code&gt;url&lt;/code&gt;地址，继续爬取，生成新的  &lt;code&gt;PDF&lt;/code&gt;文件，当然，您也可以通过循环编译等方式去一次性爬取多个网页生成多个  &lt;code&gt;PDF&lt;/code&gt;文件。  &lt;p&gt;对应像京东首页这样的开启了图片懒加载的网页，爬取到的部分内容是   &lt;code&gt;loading&lt;/code&gt;状态的内容，对于有一些反爬虫机制的网页，爬虫也会出现问题，但是绝大多数网站都是可以的&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;pre&gt;  &lt;code&gt;const puppeteer = require(&amp;apos;puppeteer&amp;apos;);
const url = require(&amp;apos;./url&amp;apos;);
(async () =&amp;gt; {
    const browser = await puppeteer.launch({ headless: true })
    const page = await browser.newPage()
    //选择要打开的网页  
    await page.goto(url, { waitUntil: &amp;apos;networkidle0&amp;apos; })
    //选择你要输出的那个PDF文件路径，把爬取到的内容输出到PDF中，必须是存在的PDF，可以是空内容，如果不是空的内容PDF，那么会覆盖内容
    let pdfFilePath = &amp;apos;./index.pdf&amp;apos;;
    //根据你的配置选项，我们这里选择A4纸的规格输出PDF，方便打印
    await page.pdf({
        path: pdfFilePath,
        format: &amp;apos;A4&amp;apos;,
        scale: 1,
        printBackground: true,
        landscape: false,
        displayHeaderFooter: false
    });
    await browser.close()
})()
&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;文件解构设计&lt;/h4&gt;
 &lt;p&gt;  &lt;img alt="clipboard.png" src="https://segmentfault.com/img/bVbtVfj?w=202&amp;h=229" title="clipboard.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;blockquote&gt;数据在这个时代非常珍贵，按照网页的设计逻辑，选定特定的  &lt;code&gt;href&lt;/code&gt;的地址，可以先直接获取对应的资源，也可以通过再次使用   &lt;code&gt; page.goto&lt;/code&gt;方法进入，再调用  &lt;code&gt; page.evaluate()&lt;/code&gt; 处理逻辑，或者输出对应的  &lt;code&gt;PDF&lt;/code&gt;文件，当然也可以一口气输出多个  &lt;code&gt;PDF&lt;/code&gt;文件~  &lt;br /&gt;这里就不做过多介绍了，毕竟  &lt;code&gt; Node.js &lt;/code&gt;是可以上天的，或许未来它真的什么都能做。这么优质简短的教程，请收藏  &lt;br /&gt;或者转发给您的朋友，谢谢。&lt;/blockquote&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>html5 html css node.js javascript</category>
      <guid isPermaLink="true">https://itindex.net/detail/59698-node-js-%E7%BD%91%E9%A1%B5</guid>
      <pubDate>Fri, 14 Jun 2019 23:55:03 CST</pubDate>
    </item>
    <item>
      <title>前端性能优化不完全手册</title>
      <link>https://itindex.net/detail/59441-%E5%89%8D%E7%AB%AF-%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96-%E5%AE%8C%E5%85%A8</link>
      <description>&lt;h4&gt;性能优化是一门大学问，本文仅对个人一些积累知识的阐述，欢迎下面补充。&lt;/h4&gt;
 &lt;blockquote&gt;抛出一个问题，从输入  &lt;code&gt;url&lt;/code&gt;地址栏到所有内容显示到界面上做了哪些事？&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;1.浏览器向   &lt;code&gt; DNS &lt;/code&gt;服务器请求解析该 URL 中的域名所对应的    &lt;code&gt;IP&lt;/code&gt; 地址;&lt;/li&gt;
  &lt;li&gt;2.建立   &lt;code&gt;TCP&lt;/code&gt;连接（三次握手）;&lt;/li&gt;
  &lt;li&gt;3.浏览器发出读取文件(   &lt;code&gt;URL&lt;/code&gt; 中域名后面部分对应的文件)的   &lt;code&gt;HTTP&lt;/code&gt; 请求，该请求报文作为    &lt;code&gt;TCP&lt;/code&gt; 三次握手的第三个报文的数据发送给服务器;&lt;/li&gt;
  &lt;li&gt;4.服务器对浏览器请求作出响应，并把对应的 html 文本发送给浏览器;&lt;/li&gt;
  &lt;li&gt;5.浏览器将该    &lt;code&gt;html&lt;/code&gt; 文本并显示内容;&lt;/li&gt;
  &lt;li&gt;6.释放    &lt;code&gt;TCP&lt;/code&gt;连接（四次挥手）;&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;上面这个问题是一个面试官非常喜欢问的问题，我们下面把这6个步骤分解，逐步细谈优化。&lt;/blockquote&gt;
 &lt;h4&gt;一、  &lt;code&gt;DNS&lt;/code&gt; 解析&lt;/h4&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;p&gt;DNS`解析:将域名解析为ip地址 ,由上往下匹配，只要命中便停止&lt;/p&gt;
   &lt;ul&gt;
    &lt;li&gt;走缓存&lt;/li&gt;
    &lt;li&gt;浏览器DNS缓存&lt;/li&gt;
    &lt;li&gt;本机DNS缓存&lt;/li&gt;
    &lt;li&gt;路由器DNS缓存&lt;/li&gt;
    &lt;li&gt;网络运营商服务器DNS缓存 （80%的DNS解析在这完成的）&lt;/li&gt;
    &lt;li&gt;递归查询&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
 &lt;blockquote&gt;优化策略：尽量允许使用浏览器的缓存，能给我们节省大量时间。&lt;/blockquote&gt;
 &lt;h4&gt;二、  &lt;code&gt;TCP&lt;/code&gt;的三次握手&lt;/h4&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;p&gt;SYN （同步序列编号）ACK（确认字符）&lt;/p&gt;
   &lt;ul&gt;
    &lt;li&gt;第一次握手：Client将标志位SYN置为1，随机产生一个值seq=J，并将该数据包发送给Server，Client进入SYN_SENT状态，等 待Server确认。&lt;/li&gt;
    &lt;li&gt;第二次握手：Server收到数据包后由标志位SYN=1知道Client请求建立连接，Server将标志位SYN和ACK都置为1，ack=J+1，随机产生一个值seq=K，并将该数据包发送给Client以确认连接请求，Server进入SYN_RCVD状态。&lt;/li&gt;
    &lt;li&gt;第三次握手：Client收到确认后，检查ack是否为J+1，ACK是否为1，如果正确则将标志位ACK置为1，ack=K+1，并将该数据包发送给Server，Server检查ack是否为K+1，ACK是否为1，如果正确则连接建立成功，Client和Server进入ESTABLISHED状态，完成三次握手，随后Client与Server之间可以开始传输数据了。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
 &lt;h4&gt;三、浏览器发送请求&lt;/h4&gt;
 &lt;blockquote&gt;优化策略:&lt;/blockquote&gt;
 &lt;li&gt;  &lt;ul&gt;
   &lt;li&gt;1.    &lt;code&gt;HTTP&lt;/code&gt;协议通信最耗费时间的是建立    &lt;code&gt;TCP&lt;/code&gt;连接的过程，那我们就可以使用    &lt;code&gt;HTTP Keep-Alive&lt;/code&gt;，在    &lt;code&gt;HTTP &lt;/code&gt;早期，每个    &lt;code&gt;HTTP &lt;/code&gt;请求都要求打开一个    &lt;code&gt;TCP socket&lt;/code&gt;连接，并且使用一次之后就断开这个    &lt;code&gt;TCP&lt;/code&gt;连接。 使用    &lt;code&gt;keep-alive&lt;/code&gt;可以改善这种状态，即在一次TCP连接中可以持续发送多份数据而不会断开连接。通过使用    &lt;code&gt;keep-alive&lt;/code&gt;机制，可以减少    &lt;code&gt;TCP&lt;/code&gt;连接建立次数，也意味着可以减少    &lt;code&gt;TIME_WAIT&lt;/code&gt;状态连接，以此提高性能和提高    &lt;code&gt;http&lt;/code&gt;服务器的吞吐率(更少的    &lt;code&gt;tcp&lt;/code&gt;连接意味着更少的系统内核调用&lt;/li&gt;
   &lt;li&gt;2.但是，    &lt;code&gt;keep-alive&lt;/code&gt;并不是免费的午餐,长时间的    &lt;code&gt;TCP&lt;/code&gt;连接容易导致系统资源无效占用。配置不当的    &lt;code&gt;keep-alive&lt;/code&gt;，有时比重复利用连接带来的损失还更大。所以，正确地设置    &lt;code&gt;keep-alive timeout&lt;/code&gt;时间非常重要。(这个    &lt;code&gt;keep-alive_timout&lt;/code&gt;时间值意味着：一个    &lt;code&gt;http&lt;/code&gt;产生的    &lt;code&gt;tcp&lt;/code&gt;连接在传送完最后一个响应后，还需要    &lt;code&gt;hold&lt;/code&gt;住    &lt;code&gt;keepalive_timeout&lt;/code&gt;秒后，才开始关闭这个连接)，如果想更详细了解可以看这篇文章    &lt;a href="https://www.cnblogs.com/freefish12/p/5394876.html" rel="nofollow noreferrer"&gt;keep-alve性能优化的测试结果&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
 &lt;ul&gt;
  &lt;li&gt;3.使用   &lt;code&gt;webScoket&lt;/code&gt;通信协议，仅一次   &lt;code&gt;TCP&lt;/code&gt;握手就一直保持连接，而且他对二进制数据的传输有更好的支持，可以应用于即时通信，海量高并发场景。   &lt;a href="https://www.cnblogs.com/fuqiang88/p/5956363.html" rel="nofollow noreferrer"&gt;webSocket的原理以及详解&lt;/a&gt;
&lt;/li&gt;
  &lt;li&gt;4.减少   &lt;code&gt;HTTP&lt;/code&gt;请求次数，每次   &lt;code&gt;HTTP&lt;/code&gt;请求都会有请求头，返回响应都会有响应头，多次请求不仅浪费时间而且会让网络传输很多无效的资源，使用前端模块化技术    &lt;code&gt;AMD CMD commonJS ES6等模块化方案&lt;/code&gt;将多个文件压缩打包成一个，当然也不能都放在一个文件中，因为这样传输起来可能会很慢，权衡取一个中间值&lt;/li&gt;
  &lt;li&gt;5.配置使用懒加载，对于一些用户不立刻使用到的文件到特定的事件触发再请求，也许用户只是想看到你首页上半屏的内容，但是你却请求了整个页面的所有图片，如果用户量很大，那么这是一种极大的浪费&lt;/li&gt;
  &lt;li&gt;6.服务器资源的部署尽量使用同源策略&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;四、服务器返回响应，浏览器接受到响应数据&lt;/h4&gt;
 &lt;h4&gt;五、浏览器解析数据，绘制渲染页面的过程&lt;/h4&gt;
 &lt;ul&gt;
  &lt;li&gt;先预解析（将需要发送请求的标签的请求发出去）&lt;/li&gt;
  &lt;li&gt;从上到下解析   &lt;code&gt;html&lt;/code&gt;文件&lt;/li&gt;
  &lt;li&gt;遇到HTML标签，调用html解析器将其解析   &lt;code&gt;DOM&lt;/code&gt;树&lt;/li&gt;
  &lt;li&gt;遇到   &lt;code&gt;css&lt;/code&gt;标记，调用css解析器将其解析   &lt;code&gt;CSSOM&lt;/code&gt;树&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;link&lt;/code&gt; 阻塞 - 为了解决闪屏，所有解决闪屏的样式&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;style&lt;/code&gt; 非阻塞，与闪屏的样式不相关的&lt;/li&gt;
  &lt;li&gt;将   &lt;code&gt;DOM&lt;/code&gt;树和   &lt;code&gt;CSSOM&lt;/code&gt;树结合在一起，形成   &lt;code&gt;render&lt;/code&gt;树&lt;/li&gt;
  &lt;li&gt;layout布局 render渲染&lt;/li&gt;
  &lt;li&gt;遇到   &lt;code&gt;script&lt;/code&gt;标签，阻塞，调用   &lt;code&gt;js&lt;/code&gt;解析器解析   &lt;code&gt;js&lt;/code&gt;代码，可能会修改   &lt;code&gt;DOM&lt;/code&gt;树，也可能会修改   &lt;code&gt;CSSOM&lt;/code&gt;树&lt;/li&gt;
  &lt;li&gt;将   &lt;code&gt;DOM&lt;/code&gt;树和   &lt;code&gt;CSSOM&lt;/code&gt;树结合在一起，形成   &lt;code&gt;render&lt;/code&gt;树&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;layout&lt;/code&gt;布局    &lt;code&gt;render&lt;/code&gt;渲染（重排重绘）&lt;/li&gt;
  &lt;li&gt;
   &lt;p&gt;    &lt;code&gt;script&lt;/code&gt;标签的属性&lt;/p&gt;
   &lt;ul&gt;
    &lt;li&gt;async 异步 谁先回来谁就先解析，不阻塞&lt;/li&gt;
    &lt;li&gt;defer 异步 按照先后顺序（defer）解析，不阻塞&lt;/li&gt;
    &lt;li&gt;script标签放在body下，放置多次重排重绘，能够操作dom&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
 &lt;blockquote&gt;性能优化策略：&lt;/blockquote&gt;
 &lt;ul&gt;
  &lt;li&gt;需要阻塞的样式使用   &lt;code&gt;link&lt;/code&gt;引入，不需要的使用   &lt;code&gt;style&lt;/code&gt;标签(具体是否需要阻塞看业务场景)&lt;/li&gt;
  &lt;li&gt;图片比较多的时候，一定要使用懒加载，图片是最需要优化的，   &lt;code&gt;webpack4&lt;/code&gt;中也要配置图片压缩，能极大压缩图片大小，对于新版本浏览器可以使用   &lt;code&gt;webp格式图片&lt;/code&gt;   &lt;a href="https://baike.baidu.com/item/webp%E6%A0%BC%E5%BC%8F/4077671?fr=aladdin" rel="nofollow noreferrer"&gt;webP详解&lt;/a&gt;，图片优化对性能提升最大。&lt;/li&gt;
  &lt;li&gt;
   &lt;code&gt;webpack4&lt;/code&gt;配置 代码分割，提取公共代码成单独模块。方便缓存&lt;/li&gt;
&lt;/ul&gt;
 &lt;pre&gt;  &lt;code&gt;    /*
    runtimeChunk 设置为 true, webpack 就会把 chunk 文件名全部存到一个单独的 chunk 中，
    这样更新一个文件只会影响到它所在的 chunk 和 runtimeChunk，避免了引用这个 chunk 的文件也发生改变。
    */
    runtimeChunk: true, 
    splitChunks: {
      chunks: &amp;apos;all&amp;apos;  // 默认 entry 的 chunk 不会被拆分, 配置成 all, 就可以了
    }
  }
    //因为是单入口文件配置，所以没有考虑多入口的情况，多入口是应该分别进行处理。&lt;/code&gt;&lt;/pre&gt;
 &lt;ul&gt;
  &lt;li&gt;对于需要事件驱动的   &lt;code&gt;webpack4&lt;/code&gt;配置懒加载的，可以看这篇   &lt;a href="https://segmentfault.com/a/1190000018535749"&gt;webpack4优化教程&lt;/a&gt;,写得非常全面&lt;/li&gt;
  &lt;li&gt;一些原生   &lt;code&gt;javaScript&lt;/code&gt;的   &lt;code&gt;DOM&lt;/code&gt;操作等优化会在下面总结&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;六、  &lt;code&gt;TCP&lt;/code&gt;的四次挥手，断开连接&lt;/h4&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h4&gt;终结篇：性能只是 load 时间或者 DOMContentLoaded 时间的问题吗？&lt;/h4&gt;
 &lt;ul&gt;  &lt;li&gt;
   &lt;p&gt;    &lt;code&gt;RAIL&lt;/code&gt;&lt;/p&gt;
   &lt;ul&gt;
    &lt;li&gt;
     &lt;code&gt;Responce&lt;/code&gt; 响应，研究表明，100ms内对用户的输入操作进行响应，通常会被人类认为是立即响应。时间再长，操作与反应之间的连接就会中断，人们就会觉得它的操作有延迟。例如：当用户点击一个按钮，如果100ms内给出响应，那么用户就会觉得响应很及时，不会察觉到丝毫延迟感。&lt;/li&gt;
    &lt;li&gt;
     &lt;code&gt;Animaton&lt;/code&gt; 现如今大多数设备的屏幕刷新频率是60Hz，也就是每秒钟屏幕刷新60次；因此网页动画的运行速度只要达到60FPS，我们就会觉得动画很流畅。&lt;/li&gt;
    &lt;li&gt;
     &lt;code&gt;Idle&lt;/code&gt; RAIL规定，空闲周期内运行的任务不得超过50ms，当然不止RAIL规定，W3C性能工作组的Longtasks标准也规定了超过50毫秒的任务属于长任务，那么50ms这个数字是怎么得来的呢？浏览器是单线程的，这意味着同一时间主线程只能处理一个任务，如果一个任务执行时间过长，浏览器则无法执行其他任务，用户会感觉到浏览器被卡死了，因为他的输入得不到任何响应。为了达到100ms内给出响应，将空闲周期执行的任务限制为50ms意味着，即使用户的输入行为发生在空闲任务刚开始执行，浏览器仍有剩余的50ms时间用来响应用户输入，而不会产生用户可察觉的延迟。&lt;/li&gt;
    &lt;li&gt;
     &lt;code&gt;Load&lt;/code&gt;如果不能在1秒钟内加载网页并让用户看到内容，用户的注意力就会分散。用户会觉得他要做的事情被打断，如果10秒钟还打不开网页，用户会感到失望，会放弃他们想做的事，以后他们或许都不会再回来。&lt;/li&gt;
&lt;/ul&gt;
   &lt;blockquote&gt;如何使网页更丝滑？&lt;/blockquote&gt;
   &lt;ul&gt;
    &lt;li&gt;
     &lt;p&gt;使用requestAnimationFrame&lt;/p&gt;
     &lt;ul&gt;      &lt;li&gt;即便你能保证每一帧的总耗时都小于16ms，也无法保证一定不会出现丢帧的情况，这取决于触发JS执行的方式。假设使用 setTimeout 或 setInterval 来触发JS执行并修改样式从而导致视觉变化；那么会有这样一种情况，因为setTimeout 或 setInterval没有办法保证回调函数什么时候执行，它可能在每一帧的中间执行，也可能在每一帧的最后执行。所以会导致即便我们能保障每一帧的总耗时小于16ms，但是执行的时机如果在每一帧的中间或最后，最后的结果依然是没有办法每隔16ms让屏幕产生一次变化，也就是说，即便我们能保证每一帧总体时间小于16ms，但如果使用定时器触发动画，那么由于定时器的触发时机不确定，所以还是会导致动画丢帧。现在整个Web只有一个API可以解决这个问题，那就是requestAnimationFrame，它可以保证回调函数稳定的在每一帧最开始触发。&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;
    &lt;li&gt;
     &lt;p&gt;避免      &lt;code&gt;FSL &lt;/code&gt;&lt;/p&gt;
     &lt;ul&gt;      &lt;li&gt;
       &lt;p&gt;先执行        &lt;code&gt;JS&lt;/code&gt;，然后在        &lt;code&gt;JS&lt;/code&gt;中修改了样式从而导致样式计算，然后样式的改动触发了布局、绘制、合成。但        &lt;code&gt;JavaScript&lt;/code&gt;可以强制浏览器将布局提前执行，这就叫 强制同步布局        &lt;code&gt;FSL&lt;/code&gt;。&lt;/p&gt;
       &lt;pre&gt;        &lt;code&gt;  //读取offsetWidth的值会导致重绘
 const newWidth = container.offsetWidth;
   
  //设置width的值会导致重排，但是for循环内部
  代码执行速度极快，当上面的查询操作导致的重绘
  还没有完成，下面的代码又会导致重排，而且这个重
  排会强制结束上面的重绘，直接重排，这样对性能影响
  非常大。所以我们一般会在循环外部定义一个变量，这里
  面使用变量代替container.offsetWidth;
 boxes[i].style.width = newWidth + &amp;apos;px&amp;apos;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;
    &lt;li&gt;使用     &lt;code&gt;transform&lt;/code&gt;属性去操作动画，这个属性是由合成器单独处理的，所以使用这个属性可以避免布局与绘制。&lt;/li&gt;
    &lt;li&gt;使用     &lt;code&gt;translateZ(0)&lt;/code&gt;开启图层，减少重绘重排。特别在移动端，尽量使用     &lt;code&gt;transform&lt;/code&gt;代替     &lt;code&gt;absolute&lt;/code&gt;。创建图层的最佳方式是使用will-change，但某些不支持这个属性的浏览器可以使用3D 变形（transform: translateZ(0)）来强制创建一个新层。&lt;/li&gt;
    &lt;li&gt;有兴趣的可以看看这篇文字      &lt;a href="https://juejin.im/post/5c860282e51d45531330e10e#heading-12" rel="nofollow noreferrer"&gt;前端页面优化&lt;/a&gt;
&lt;/li&gt;
    &lt;li&gt;样式的切换最好提前定义好     &lt;code&gt;class&lt;/code&gt;，通过     &lt;code&gt;class&lt;/code&gt;的切换批量修改样式，避免多次重绘重排&lt;/li&gt;
    &lt;li&gt;可以先切换     &lt;code&gt;display:none&lt;/code&gt;再修改样式&lt;/li&gt;
    &lt;li&gt;多次的     &lt;code&gt;append &lt;/code&gt;操作可以先插入到一个新生成的元素中，再一次性插入到页面中。&lt;/li&gt;
    &lt;li&gt;代码复用，函数柯里化，封装高阶函数，将多次复用代码封装成普通函数（俗称方法），     &lt;code&gt;React&lt;/code&gt;中封装成高阶组件，     &lt;code&gt;ES6&lt;/code&gt;中可以使用继承，     &lt;code&gt;TypeScript&lt;/code&gt;中接口继承，类继承，接口合并，类合并。&lt;/li&gt;
    &lt;li&gt;强力推荐阅读:     &lt;a href="http://es6.ruanyifeng.com/#docs/promise" rel="nofollow noreferrer"&gt;阮一峰ES6教程&lt;/a&gt;
&lt;/li&gt;
    &lt;li&gt;以及     &lt;a href="https://ts.xcatliu.com/introduction/what-is-typescript.html" rel="nofollow noreferrer"&gt;什么是TypeScript以及入门&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;&lt;/ul&gt;
 &lt;blockquote&gt;以上都是根据本人的知识点总结得出，后期还会有  &lt;code&gt;React&lt;/code&gt;的性能优化方案等出来，路过点个赞收藏收藏~，欢迎提出问题补充~&lt;/blockquote&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>javascript node.js typescript css html5</category>
      <guid isPermaLink="true">https://itindex.net/detail/59441-%E5%89%8D%E7%AB%AF-%E6%80%A7%E8%83%BD%E4%BC%98%E5%8C%96-%E5%AE%8C%E5%85%A8</guid>
      <pubDate>Thu, 11 Apr 2019 00:06:56 CST</pubDate>
    </item>
    <item>
      <title>HTML编码规范</title>
      <link>https://itindex.net/detail/57130-html-%E7%BC%96%E7%A0%81-%E8%A7%84%E8%8C%83</link>
      <description>&lt;blockquote&gt;  &lt;p&gt;这段时间在整理前端部分代码规范，初步想法是从HTML、CSS、Javascipt、项目文件目录四部分是整理。之前已经整理完了   &lt;a href="https://segmentfault.com/a/1190000009951469?_ea=2108730"&gt;CSS编码规范&lt;/a&gt;，有兴趣可以了解下&lt;/p&gt;&lt;/blockquote&gt;
 &lt;h2&gt;1. 代码风格&lt;/h2&gt;
 &lt;h3&gt;1.1缩进与换行&lt;/h3&gt;
 &lt;h4&gt;[强制] 使用 4 个空格做为一个缩进层级，不允许使用 2 个空格 或 tab 字符。&lt;/h4&gt;
 &lt;p&gt;解释：   &lt;br /&gt;对于非 HTML 标签之间的缩进，比如 script 或 style 标签内容缩进，与 script 或 style 标签的缩进同级。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;style&amp;gt;
/* 样式内容的第一级缩进与所属的 style 标签对齐 */
ul {
    padding: 0;
}
&amp;lt;/style&amp;gt;
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;first&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;second&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;script&amp;gt;
// 脚本代码的第一级缩进与所属的 script 标签对齐
require([&amp;apos;app&amp;apos;], function (app) {
    app.init();
});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 每行不得超过 120 个字符。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;过长的代码不容易阅读与维护。但是考虑到 HTML 的特殊性，不做硬性要求。&lt;/p&gt;
 &lt;h3&gt;1.2命名&lt;/h3&gt;
 &lt;h4&gt;[强制] class 必须单词全字母小写，单词间以 - 分隔。&lt;/h4&gt;
 &lt;h4&gt;[强制] class 必须代表相应模块或部件的内容或功能，不得以样式信息进行命名。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;div class=&amp;quot;sidebar&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;!-- bad --&amp;gt;
&amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[强制] 元素 id 必须保证页面唯一。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;同一个页面中，不同的元素包含相同的 id，不符合 id 的属性含义。并且使用 document.getElementById 时可能导致难以追查的问题。&lt;/p&gt;
 &lt;h4&gt;[强制] 禁止为了 hook 脚本，创建无样式信息的 class。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;不允许 class 只用于让 JavaScript 选择某些元素，class 应该具有明确的语义和样式。否则容易导致 CSS class 泛滥。  &lt;br /&gt;使用 id、属性选择作为 hook 是更好的方式。&lt;/p&gt;
 &lt;h4&gt;[强制] 同一页面，应避免使用相同的 name 与 id。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;IE 浏览器会混淆元素的   &lt;code&gt;id&lt;/code&gt; 和   &lt;code&gt;name&lt;/code&gt; 属性，   &lt;code&gt;document.getElementById&lt;/code&gt; 可能获得不期望的元素。所以在对元素的 id 与 name属性的命名需要非常小心。  &lt;br /&gt;一个比较好的实践是，为   &lt;code&gt;id&lt;/code&gt; 和   &lt;code&gt;name&lt;/code&gt; 使用不同的命名法。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;input name=&amp;quot;foo&amp;quot;&amp;gt;
&amp;lt;div id=&amp;quot;foo&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;script&amp;gt;
    // IE6 将显示 INPUT
    alert(document.getElementById(&amp;apos;foo&amp;apos;).tagName);
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] id 建议单词全字母小写，单词间以   &lt;code&gt;_&lt;/code&gt; 分隔。同项目必须保持风格一致。&lt;/h4&gt;
 &lt;h4&gt;[建议] id、class 命名，在避免冲突并描述清楚的前提下尽可能短。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;div id=&amp;quot;nav&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;div id=&amp;quot;navigation&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;!-- good --&amp;gt;
&amp;lt;p class=&amp;quot;comment&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;p class=&amp;quot;com&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;

&amp;lt;!-- good --&amp;gt;
&amp;lt;span class=&amp;quot;author&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;span class=&amp;quot;red&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;1.3 标签&lt;/h3&gt;
 &lt;h4&gt;[强制] 标签名必须使用小写字母。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;p&amp;gt;Hello StyleGuide!&amp;lt;/p&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;P&amp;gt;Hello StyleGuide!&amp;lt;/P&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[强制] 对于无需自闭合的标签，不允许自闭合。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;常见无需自闭合标签有   &lt;code&gt;input&lt;/code&gt;、  &lt;code&gt;br&lt;/code&gt;、  &lt;code&gt;img&lt;/code&gt;等。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;title&amp;quot;&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;title&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[强制] 对 HTML5 中规定允许省略的闭合标签，不允许省略闭合标签。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;对代码体积要求非常严苛的场景，可以例外。比如：第三方页面使用的投放系统。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;first&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;second&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;first
    &amp;lt;li&amp;gt;second
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[强制] 标签使用必须符合标签嵌套规则。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;比如 div 不得置于 p 中，tbody 必须置于 table 中。  &lt;br /&gt;详细的标签嵌套规则参见  &lt;a&gt;HTML DTD&lt;/a&gt;中的 Elements 定义部分。&lt;/p&gt;
 &lt;h4&gt;[建议] HTML 标签的使用应该遵循标签的语义。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;下面是常见标签语义&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;p&gt;p - 段落&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;h1,h2,h3,h4,h5,h6 - 层级标题&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;strong,em - 强调&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;abbr - 缩写&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;blockquote - 一段或长篇引用&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;ul - 无序列表&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;ol - 有序列表&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;dl,dt,dd - 定义列表&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;p&amp;gt;Esprima serves as an important &amp;lt;strong&amp;gt;building block&amp;lt;/strong&amp;gt; for some JavaScript language tools.&amp;lt;/p&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;div&amp;gt;Esprima serves as an important &amp;lt;span class=&amp;quot;strong&amp;quot;&amp;gt;building block&amp;lt;/span&amp;gt; for some JavaScript language tools.&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 在 CSS 可以实现相同需求的情况下不得使用表格进行布局。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;在兼容性允许的情况下应尽量保持语义正确性。对网格对齐和拉伸性有严格要求的场景允许例外，如多列复杂表单。&lt;/p&gt;
 &lt;h4&gt;[建议] 标签的使用应尽量简洁，减少不必要的标签。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;img class=&amp;quot;avatar&amp;quot; src=&amp;quot;image.png&amp;quot;&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;span class=&amp;quot;avatar&amp;quot;&amp;gt;
    &amp;lt;img src=&amp;quot;image.png&amp;quot;&amp;gt;
&amp;lt;/span&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;1.4 属性&lt;/h3&gt;
 &lt;h4&gt;[强制] 属性名必须使用小写字母，自定义属性视情况定。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;table cellspacing=&amp;quot;0&amp;quot;&amp;gt;...&amp;lt;/table&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;table cellSpacing=&amp;quot;0&amp;quot;&amp;gt;...&amp;lt;/table&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;[强制] 属性值必须用双引号包围.自定义属性视情况定。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;script src=&amp;quot;esl.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;script src=&amp;apos;esl.js&amp;apos;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=esl.js&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 布尔类型的属性，建议不添加属性值。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;input type=&amp;quot;text&amp;quot; disabled&amp;gt;
&amp;lt;input type=&amp;quot;checkbox&amp;quot; value=&amp;quot;1&amp;quot; checked&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 自定义属性建议以 xxx- 为前缀，推荐使用 data-。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;使用前缀有助于区分自定义属性和标准定义的属性。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;ol data-ui-type=&amp;quot;Select&amp;quot;&amp;gt;&amp;lt;/ol&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h2&gt;2.Head&lt;/h2&gt;
 &lt;h3&gt;2.1 DOCTYPE&lt;/h3&gt;
 &lt;h4&gt;[强制] 使用 HTML5 的 doctype 来启用标准模式，建议使用大写的 DOCTYPE。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 启用 IE Edge 模式。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;meta http-equiv=&amp;quot;X-UA-Compatible&amp;quot; content=&amp;quot;IE=Edge&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 在 html 标签上设置正确的 lang 属性。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;有助于提高页面的可访问性，如：让语音合成工具确定其所应该采用的发音，令翻译工具确定其翻译语言等。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;html lang=&amp;quot;zh-CN&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;2.2 编码&lt;/h3&gt;
 &lt;p&gt;[强制] 页面必须使用精简形式，明确指定字符编码。指定字符编码的 meta 必须是 head 的第一个直接子元素。  &lt;br /&gt;解释：  &lt;br /&gt;见  &lt;a href="http://www.qianduan.net/html5-charset-can-it.html"&gt;HTML5 Charset&lt;/a&gt;能用吗 一文。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;
        ......
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        ......
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;2.3 title&lt;/h3&gt;
 &lt;h4&gt;[强制] 页面必须包含 title 标签声明标题。&lt;/h4&gt;
 &lt;h4&gt;[强制] title 必须作为 head 的直接子元素，并紧随 charset 声明之后。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;title 中如果包含 ASCII 之外的字符，浏览器需要知道字符编码类型才能进行解码，否则可能导致乱码。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&amp;quot;UTF-8&amp;quot;&amp;gt;
    &amp;lt;title&amp;gt;页面标题&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;2.4favicon&lt;/h3&gt;
 &lt;h4&gt;[强制] 保证 favicon 可访问。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;在未指定 favicon 时，大多数浏览器会请求 Web Server 根目录下的 favicon.ico 。为了保证 favicon 可访问，避免 404，必须遵循以下两种方法之一：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;在 Web Server 根目录放置 favicon.ico 文件。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;使用 link 指定 favicon。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;link rel=&amp;quot;shortcut icon&amp;quot; href=&amp;quot;path/to/favicon.ico&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;2.5 CSS 和 JavaScript 引入&lt;/h3&gt;
 &lt;h4&gt;[强制] 引入 CSS 时必须指明 rel=&amp;quot;stylesheet&amp;quot;。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;page.css&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 引入 CSS 和 JavaScript 时无须指明 type 属性。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;text/css 和 text/javascript 是 type 的默认值。&lt;/p&gt;
 &lt;h4&gt;[建议] 在 head 中引入页面需要的所有 CSS 资源。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;在页面渲染的过程中，新的CSS可能导致元素的样式重新计算和绘制，页面闪烁。&lt;/p&gt;
 &lt;h4&gt;[建议] JavaScript 应当放在页面末尾，或采用异步加载。&lt;/h4&gt;
 &lt;p&gt;解释：   &lt;br /&gt;将 script 放在页面中间将阻断页面的渲染。出于性能方面的考虑，如非必要，请遵守此条建议。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;body&amp;gt;
    &amp;lt;!-- a lot of elements --&amp;gt;
    &amp;lt;script src=&amp;quot;init-behavior.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;2.6 viewport&lt;/h3&gt;
 &lt;h4&gt;[建议] 若页面欲对移动设备友好，需指定页面的 viewport。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;viewport meta tag 可以设置可视区域的宽度和初始缩放大小，避免在移动设备上出现页面展示不正常。&lt;/p&gt;
 &lt;p&gt;比如，在页面宽度小于 980px 时，若需 iOS 设备友好，应当设置 viewport 的 width 值来适应你的页面宽度。同时因为不同移动设备分辨率不同，在设置时，应当使用 device-width 和 device-height 变量。&lt;/p&gt;
 &lt;p&gt;另外，为了使 viewport 正常工作，在页面内容样式布局设计上也要做相应调整，如避免绝对定位等。关于 viewport 的更多介绍，可以参见  &lt;a href="https://developer.apple.com/library/mac/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html#//apple_ref/doc/uid/TP40006509-SW26"&gt;Safari Web Content Guide的介绍&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;2.7 IE Style Fixed&lt;/h3&gt;
 &lt;h4&gt;[建议] 为兼容IE9及以下浏览器样式，有必要在head中使用CSS if IE条件注释。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!--[if lt IE 9]&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot; class=&amp;quot;ie8&amp;quot;&amp;gt;
&amp;lt;![endif]--&amp;gt;
&amp;lt;!--[if gt IE 8]&amp;gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;
&amp;lt;![endif]--&amp;gt;
&amp;lt;!-- IE8 fixed --&amp;gt;
&amp;lt;!--[if lt IE 9]&amp;gt;
&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;&amp;lt;?php echo STATICURL; ?&amp;gt;/css/iefix.css?&amp;lt;?php echo VERHASH; ?&amp;gt;&amp;quot;/&amp;gt;
&amp;lt;![endif]--&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h2&gt;3. 图片&lt;/h2&gt;
 &lt;h4&gt;[强制] 禁止 img 的 src 取值为空。延迟加载的图片也要增加默认的 src。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;src 取值为空，会导致部分浏览器重新加载一次当前页面，参考：  &lt;a href="https://developer.yahoo.com/performance/rules.html#emptysrc"&gt;https://developer.yahoo.com/performance/rules.html#emptysrc&lt;/a&gt;&lt;/p&gt;
 &lt;h4&gt;[建议] 避免为 img 添加不必要的 title 属性。&lt;/h4&gt;
 &lt;h4&gt;[建议] 为重要图片添加 alt 属性。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;可以提高图片加载失败时的用户体验。&lt;/p&gt;
 &lt;h4&gt;[建议] 添加 width 和 height 属性，以避免页面抖动。&lt;/h4&gt;
 &lt;h4&gt;[建议] 有下载需求的图片采用 img 标签实现，无下载需求的图片采用 CSS 背景图实现。&lt;/h4&gt;
 &lt;p&gt;解释：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;产品 logo、用户头像、用户产生的图片等有潜在下载需求的图片，以 img 形式实现，能方便用户下载。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;无下载需求的图片，比如：icon、背景、代码使用的图片等，尽可能采用 CSS 背景图实现。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;h2&gt;4. 表单&lt;/h2&gt;
 &lt;h3&gt;4.1 控件标题&lt;/h3&gt;
 &lt;h4&gt;[强制] 有文本标题的控件必须使用 label 标签将其与其标题相关联。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;有两种方式：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;将控件置于 label 内。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;label 的 for 属性指向控件的 id。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;推荐使用第一种，减少不必要的 id。如果 DOM 结构不允许直接嵌套，则应使用第二种。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;label&amp;gt;&amp;lt;input type=&amp;quot;checkbox&amp;quot; name=&amp;quot;confirm&amp;quot; value=&amp;quot;on&amp;quot;&amp;gt; 我已确认上述条款&amp;lt;/label&amp;gt;
&amp;lt;label for=&amp;quot;username&amp;quot;&amp;gt;用户名：&amp;lt;/label&amp;gt; &amp;lt;input type=&amp;quot;textbox&amp;quot; name=&amp;quot;username&amp;quot; id=&amp;quot;username&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;4.2 按钮&lt;/h3&gt;
 &lt;h4&gt;[强制] 使用 button 元素时必须指明 type 属性值。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;button 元素的默认 type 为 submit，如果被置于 form 元素中，点击后将导致表单提交。为显示区分其作用方便理解，必须给出 type 属性。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;button type=&amp;quot;submit&amp;quot;&amp;gt;提交&amp;lt;/button&amp;gt;
&amp;lt;button type=&amp;quot;button&amp;quot;&amp;gt;取消&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 尽量不要使用按钮类元素的 name 属性。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;由于浏览器兼容性问题，使用按钮的 name 属性会带来许多难以发现的问题。具体情况可参考  &lt;a href="http://w3help.org/zh-cn/causes/CM2001"&gt;此文&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;4.3可访问性&lt;/h3&gt;
 &lt;h4&gt;[建议] 负责主要功能的按钮在 DOM 中的顺序应靠前。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;负责主要功能的按钮应相对靠前，以提高可访问性。如果在 CSS 中指定了 float: right 则可能导致视觉上主按钮在前，而 DOM 中主按钮靠后的情况。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;style&amp;gt;
.buttons .button-group {
    float: right;
}
&amp;lt;/style&amp;gt;
&amp;lt;div class=&amp;quot;buttons&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;button-group&amp;quot;&amp;gt;
        &amp;lt;button type=&amp;quot;submit&amp;quot;&amp;gt;提交&amp;lt;/button&amp;gt;
        &amp;lt;button type=&amp;quot;button&amp;quot;&amp;gt;取消&amp;lt;/button&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;style&amp;gt;
.buttons button {
    float: right;
}
&amp;lt;/style&amp;gt;
&amp;lt;div class=&amp;quot;buttons&amp;quot;&amp;gt;
    &amp;lt;button type=&amp;quot;button&amp;quot;&amp;gt;取消&amp;lt;/button&amp;gt;
    &amp;lt;button type=&amp;quot;submit&amp;quot;&amp;gt;提交&amp;lt;/button&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 当使用 JavaScript 进行表单提交时，如果条件允许，应使原生提交功能正常工作。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;当浏览器 JS 运行错误或关闭 JS 时，提交功能将无法工作。如果正确指定了 form 元素的 action 属性和表单控件的 name 属性时，提交仍可继续进行。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;form action=&amp;quot;/login&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;
     &amp;lt;p&amp;gt;&amp;lt;input name=&amp;quot;username&amp;quot; type=&amp;quot;text&amp;quot; placeholder=&amp;quot;用户名&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
     &amp;lt;p&amp;gt;&amp;lt;input name=&amp;quot;password&amp;quot; type=&amp;quot;password&amp;quot; placeholder=&amp;quot;密码&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 在针对移动设备开发的页面时，根据内容类型指定输入框的 type 属性。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;根据内容类型指定输入框类型，能获得能友好的输入体验。  &lt;br /&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;input type=&amp;quot;date&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h2&gt;5. 多媒体&lt;/h2&gt;
 &lt;h4&gt;[建议] 当在现代浏览器中使用 audio 以及 video 标签来播放音频、视频时，应当注意格式。&lt;/h4&gt;
 &lt;p&gt;解释：  &lt;br /&gt;音频应尽可能覆盖到如下格式：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;p&gt;MP3&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;WAV&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;Ogg&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;视频应尽可能覆盖到如下格式：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;p&gt;MP4&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;WebM&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;Ogg&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;h4&gt;[建议] 在支持 HTML5 的浏览器中优先使用 audio 和 video 标签来定义音视频元素。&lt;/h4&gt;
 &lt;h4&gt;[建议] 只在必要的时候开启音视频的自动播放。&lt;/h4&gt;
 &lt;h4&gt;[建议] 在 object 标签内部提供指示浏览器不支持该标签的说明。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;object width=&amp;quot;100&amp;quot; height=&amp;quot;50&amp;quot; data=&amp;quot;something.swf&amp;quot;&amp;gt;DO NOT SUPPORT THIS TAG&amp;lt;/object&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h2&gt;6. 模板中的 HTML&lt;/h2&gt;
 &lt;h4&gt;[建议] 模板代码的缩进优先保证 HTML 代码的缩进规则。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
{if $display == true}
&amp;lt;div&amp;gt;
    &amp;lt;ul&amp;gt;
    {foreach $item_list as $item}
        &amp;lt;li&amp;gt;{$item.name}&amp;lt;li&amp;gt;
    {/foreach}
    &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
{/if}
&amp;lt;!-- bad --&amp;gt;
{if $display == true}
    &amp;lt;div&amp;gt;
        &amp;lt;ul&amp;gt;
    {foreach $item_list as $item}
        &amp;lt;li&amp;gt;{$item.name}&amp;lt;li&amp;gt;
    {/foreach}
        &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
{/if}&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;[建议] 模板代码应以保证 HTML 单个标签语法的正确性为基本原则。&lt;/h4&gt;
 &lt;p&gt;示例：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!-- good --&amp;gt;
&amp;lt;li class=&amp;quot;{if $item.type_id == $current_type}focus{/if}&amp;quot;&amp;gt;{ $item.type_name }&amp;lt;/li&amp;gt;
&amp;lt;!-- bad --&amp;gt;
&amp;lt;li {if $item.type_id == $current_type} class=&amp;quot;focus&amp;quot;{/if}&amp;gt;{ $item.type_name }&amp;lt;/li&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>代码规范 html5 html</category>
      <guid isPermaLink="true">https://itindex.net/detail/57130-html-%E7%BC%96%E7%A0%81-%E8%A7%84%E8%8C%83</guid>
      <pubDate>Tue, 27 Jun 2017 20:45:27 CST</pubDate>
    </item>
    <item>
      <title>视频H5のVideo标签在微信里的坑和技巧</title>
      <link>https://itindex.net/detail/57124-%E8%A7%86%E9%A2%91-h5-video</link>
      <description>&lt;p&gt;随着 4G 的普遍以及 WiFi 的广泛使用，手机上的网速已经足够稳定和高速，以视频为主的 HTML5 也越来越普遍了，相比帧动画，视频的表现更加丰富，前段时间开发了一个以视频为主的移动端 HTML5，在这里介绍一些实践经验。&lt;/p&gt;
 &lt;h2&gt;统一播放效果&lt;/h2&gt;
 &lt;p&gt;我们希望视频播放时可以全屏播放，没有进度条、播放按钮等与系统相关的元素，可以在视频上方增加自定义的元素（比如一个跳过按钮），类型下面的效果：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/04/iphone-ok.jpg"&gt;   &lt;img alt="iphone-ok" height="535" src="http://jdc.jd.com/wp-content/uploads/2017/04/iphone-ok.jpg" width="300"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;在不同的操作系统（主要就是 iOS 和 Android），为了达到比较统一的播放效果，分别对其进行兼容。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;iOS&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在 iOS 上，APP 都是使用的系统自带的浏览器进行页面渲染，video 播放视频的效果是统一的，只需要考虑不同的 iOS 版本是否有不一致的地方。在 iOS 上，播放视频默认会弹出一个播放器全屏播放视频，如下效果&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/04/iphone-fullscreen.jpg"&gt;   &lt;img alt="iphone-fullscreen" height="535" src="http://jdc.jd.com/wp-content/uploads/2017/04/iphone-fullscreen.jpg" width="300"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;播放器上下有的系统默认的控制栏，可以控制视频的播放进度、音量以及暂停或继续播放，播放视频时，视频会 “浮” 在页面上，页面上的所有元素都只能是在视频下面，这种效果显然不是我们想要的。  &lt;br /&gt;
但好在 iOS 10 Safari 中，  &lt;code&gt;video&lt;/code&gt; 新增了    &lt;strong&gt;   &lt;code&gt;playsinline &lt;/code&gt;&lt;/strong&gt;属性，可以使视频内联播放。&lt;/p&gt;
 &lt;p&gt;在   &lt;a href="https://webkit.org/blog/6784/new-video-policies-for-ios/" rel="external" target="_blank"&gt;webkit 的 blog&lt;/a&gt; 上提到&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt; A note about the playsinline attribute: this attribute has recently been added to the HTML specification, and WebKit has adopted this new attribute by unprefixing its legacy webkit-playsinline attribute. This legacy attribute has been supported since iPhoneOS 4.0, and accordance with our updated unprefixing policy, we’re pleased to have been able to unprefix webkit-playsinline.&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;iOS 10 之前的版本支持 webkit-playsinline，但是加了这个属性后，在 iOS 9 的上出现  &lt;strong&gt;只能听到声音不能看到画面的问题&lt;/strong&gt;，最后使用的标签代码&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;&amp;lt;video id=&amp;quot;video&amp;quot; class=&amp;quot;video&amp;quot; preload=&amp;quot;auto&amp;quot; playsinline src=&amp;quot;//wqs.jd.com/promote/superfestival/superfestival.mp4&amp;quot; width=&amp;quot;1&amp;quot; height=&amp;quot;1&amp;quot; type=&amp;quot;video/mp4&amp;quot;&amp;gt;&amp;lt;/video&amp;gt;&lt;/pre&gt; &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;然后再加上这个库   &lt;a href="https://github.com/bfred-it/iphone-inline-video" rel="external" target="_blank"&gt;iphone-inline-video&lt;/a&gt;一起使用。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Android&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在 Android 上，因为各个软件使用的浏览器渲染引擎不一样，所以视频播放的效果差异也很大，这里主要以微信为主。微信使用的是自带的渲染引擎 TBS，默认的播放效果&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/04/android-default.jpg"&gt;   &lt;img alt="android-default" height="534" src="http://jdc.jd.com/wp-content/uploads/2017/04/android-default.jpg" width="300"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;在播放器的下方也是会有控制栏，视频也会 “浮” 在页面上。而 Android 是不支持   &lt;code&gt;playsinline&lt;/code&gt; 属性使视频内联播放的。但是，如果你看过一些腾讯的视频类 HTML5，会发现它们在微信里是可以内联播放的，而这个功能是需要申请加入白名单的。&lt;/p&gt;
 &lt;p&gt;不过新版的 TBS 内核（&amp;gt;=036849）支持一个叫   &lt;code&gt;同层播放器&lt;/code&gt; 的视频播放器，这个不需要申请白名单，只需给   &lt;code&gt;video&lt;/code&gt;设置两个属性   &lt;code&gt;x5-video-player-type=&amp;quot;h5&amp;quot;&lt;/code&gt; 和   &lt;code&gt;x5-video-player-fullscreen=&amp;quot;true&amp;quot;&lt;/code&gt;，播放效果&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/04/android-fullscreen.jpg"&gt;   &lt;img alt="android-fullscreen" height="534" src="http://jdc.jd.com/wp-content/uploads/2017/04/android-fullscreen.jpg" width="300"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;当点击左上角的箭头的时，会退出播放&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://jdc.jd.com/wp-content/uploads/2017/04/android-exist.jpg"&gt;   &lt;img alt="android-exist" height="534" src="http://jdc.jd.com/wp-content/uploads/2017/04/android-exist.jpg" width="300"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;退出播放时，我们需要做相应的处理。TBS 有提供相应的事件，不过不同的版本有一点差异&lt;/p&gt;
 &lt;table&gt;

  &lt;tr&gt;
   &lt;th&gt;&lt;/th&gt;
   &lt;th&gt;TBS &amp;lt; 036849&lt;/th&gt;
   &lt;th&gt;036849 &amp;lt;= TBS &amp;lt; 036900&lt;/th&gt;
   &lt;th&gt;036900 &amp;lt;= TBS&lt;/th&gt;
&lt;/tr&gt;


  &lt;tr&gt;
   &lt;td&gt;是否支持同层播放器&lt;/td&gt;
   &lt;td&gt;否&lt;/td&gt;
   &lt;td&gt;是&lt;/td&gt;
   &lt;td&gt;是&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;退出全屏播放时触发&lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
   &lt;td&gt;x5videoenterfullscreen&lt;/td&gt;
   &lt;td&gt;x5videoexitfullscreen&lt;/td&gt;
&lt;/tr&gt;
  &lt;tr&gt;
   &lt;td&gt;进入全屏播放时触发&lt;/td&gt;
   &lt;td&gt;&lt;/td&gt;
   &lt;td&gt;x5videoexitfullscreen&lt;/td&gt;
   &lt;td&gt;x5videoenterfullscreen&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;
 &lt;p&gt;通过监听这两个事件就可以知道当前的播放状态&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;document.getElementById(&amp;apos;video&amp;apos;).addEventListener(&amp;quot;x5videoexitfullscreen&amp;quot;, function(){
  alert(&amp;quot;exit fullscreen&amp;quot;)
})
document.getElementById(&amp;apos;video&amp;apos;).addEventListener(&amp;quot;x5videoenterfullscreen&amp;quot;, function(){
  alert(&amp;quot;enter fullscreen&amp;quot;)
})&lt;/pre&gt; &lt;p&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt; 在对话框中发送    &lt;code&gt;//gettbs&lt;/code&gt; 可以查看相关信息，   &lt;code&gt;tbsCoreVersion&lt;/code&gt; 就是当前安装的 TBS 内核版本。&lt;/p&gt;&lt;/blockquote&gt;
 &lt;h2&gt;video 的事件&lt;/h2&gt;
 &lt;p&gt;  &lt;code&gt;video&lt;/code&gt; 支持的事件很多，但在有些事件在不同的系统上跟预想的表现不一致，在尝试比较之后，使用   &lt;code&gt;timeupdate&lt;/code&gt; 和   &lt;code&gt;ended&lt;/code&gt; 这两个事件基本可以满足需求&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;video.addEventListener(&amp;apos;timeupdate&amp;apos;, function (e) {
  console.log(video.currentTime) // 当前播放的进度
})
video.addEventListener(&amp;apos;ended&amp;apos;, function (e) {
  // 播放结束时触发
})&lt;/pre&gt; &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;视频居中&lt;/h2&gt;
 &lt;p&gt;视频的宽高比是固定的，而手机的屏幕宽高比则不是，所以，为了让观看到的视频的体验尽可能一致，以宽度为先，进行适配&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;function handleResize() {
  var sWidth = 9
  var sHeight = 16
  var width = window.innerWidth
  var height = window.innerHeight
  var marginTop = height - (width * sHeight) / sWidth
  marginTop = Math.round(marginTop)
  if (marginTop &amp;lt; -2) {
    video.$wrapper.css(&amp;apos;marginTop&amp;apos;, marginTop / 2 + &amp;apos;px&amp;apos;)
  } else {
    video.$wrapper.css(&amp;apos;marginTop&amp;apos;, &amp;apos;0&amp;apos;)
  }
}&lt;/pre&gt; &lt;p&gt;&lt;/p&gt;
 &lt;h2&gt;示例&lt;/h2&gt;
 &lt;p&gt;  &lt;a href="http://video.aco.aotu.io/" rel="external" target="_blank"&gt;在线示例&lt;/a&gt;  &lt;br /&gt;
  &lt;a href="https://github.com/o2team/elf/tree/master/templates/video" rel="external" target="_blank"&gt;代码仓库&lt;/a&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;代码基于    &lt;a href="https://github.com/o2team/elf" rel="external" target="_blank"&gt;    &lt;code&gt;ELF&lt;/code&gt;&lt;/a&gt; 构建，运行示例需要    &lt;a href="https://github.com/o2team/elf#&amp;#23433;&amp;#35013;" rel="external" target="_blank"&gt;安装 ELF&lt;/a&gt;，欢迎试用反馈。&lt;/p&gt;&lt;/blockquote&gt;
 &lt;h2&gt;参考&lt;/h2&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="https://www.w3.org/wiki/HTML/Elements/video" rel="external" target="_blank"&gt;https://www.w3.org/wiki/HTML/Elements/video&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://caniuse.com/#search=video" rel="external" target="_blank"&gt;http://caniuse.com/#search=video&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/Guide/Events/Media_events" rel="external" target="_blank"&gt;https://developer.mozilla.org/zh-CN/docs/Web/Guide/Events/Media_events&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://zhaoda.net/2014/10/30/html5-video-optimization" rel="external" target="_blank"&gt;http://zhaoda.net/2014/10/30/html5-video-optimization&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://webkit.org/blog/6784/new-video-policies-for-ios/" rel="external" target="_blank"&gt;https://webkit.org/blog/6784/new-video-policies-for-ios/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://github.com/bfred-it/iphone-inline-video" rel="external" target="_blank"&gt;https://github.com/bfred-it/iphone-inline-video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt; &lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>前端开发 HTML5 Video 移动端</category>
      <guid isPermaLink="true">https://itindex.net/detail/57124-%E8%A7%86%E9%A2%91-h5-video</guid>
      <pubDate>Tue, 27 Jun 2017 10:08:45 CST</pubDate>
    </item>
    <item>
      <title>页面架构HTML+CSS ●▽● 各种布局各种实现</title>
      <link>https://itindex.net/detail/56867-%E9%A1%B5%E9%9D%A2-%E6%9E%B6%E6%9E%84-html</link>
      <description>&lt;h1&gt;CSS Reset&lt;/h1&gt;
 &lt;h2&gt;1.作用&lt;/h2&gt;
 &lt;p&gt;（1）清除浏览器默认样式  &lt;br /&gt;（2）全局样式定义&lt;/p&gt;
 &lt;h2&gt;2.特别注意&lt;/h2&gt;
 &lt;p&gt;（1）项目开发初期就定义好  &lt;br /&gt;（2）  &lt;code&gt;reset.css&lt;/code&gt; 在引入的时候一定要放在第一位  &lt;br /&gt;（3）不同的产品  &lt;code&gt;reset.css&lt;/code&gt;不一样&lt;/p&gt;
 &lt;h2&gt;3.table合并边框间距&lt;/h2&gt;
 &lt;pre&gt;  &lt;code&gt;table {
  border-collapse: collapse; // 合并边框
  border-spacing: 0; //边框间距。当 `border-collapse` 值为 `seperate` 时生效

}
&lt;/code&gt;&lt;/pre&gt;
 &lt;h2&gt;4.一个并不完整也并不通用的reset.css样例&lt;/h2&gt;
 &lt;pre&gt;  &lt;code&gt;    html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,form,fieldset,legend,input,button,textarea,menu{margin:0;padding:0;}
    header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:block;}
    table{border-collapse:collapse;border-spacing:0;}
    caption,th{text-align:left;font-weight:normal;}
    html,body,fieldset,img,iframe,abbr{border:0;}
    i,cite,em,var,address,dfn{font-style:normal;}
    [hidefocus],summary{outline:0;}
    li{list-style:none;}
    h1,h2,h3,h4,h5,h6,small{font-size:100%;}
    sup,sub{font-size:83%;}
    pre,code,kbd,samp{font-family:inherit;}
    q:before,q:after{content:none;}
    textarea{overflow:auto;resize:none;}
    label,summary{cursor:default;}
    a,button{cursor:pointer;}
    h1,h2,h3,h4,h5,h6,em,strong,b{font-weight:normal;}
    del,ins,u,s,a,a:hover{text-decoration:none;}
    body,textarea,input,button,select,keygen,legend{font:12px/1.14 arial,simsun;color:#333;outline:0;}
    body{background:#fff;}
    a,a:hover{color:#333;}&lt;/code&gt;&lt;/pre&gt;
 &lt;h1&gt;布局解决方案&lt;/h1&gt;
 &lt;h2&gt;居中布局&lt;/h2&gt;
 &lt;h3&gt;1.水平居中&lt;/h3&gt;
 &lt;p&gt;父元素和子元素宽度未知。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;div class=&amp;quot;parent&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;child&amp;quot;&amp;gt;child&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;要达到的效果是这样：  &lt;br /&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMh18?w=588&amp;h=121" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h4&gt;方法一：flex + justify-content&lt;/h4&gt;
 &lt;p&gt;主要代码：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.parent { 
  display: flex;
  justify-content: center;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;没啥好解释，直接看   &lt;a href="https://jsfiddle.net/DarcyAn/tz62nf4L/"&gt;神奇的flex实现栗子&lt;/a&gt; 吧 (~￣▽￣)~&lt;/p&gt;
 &lt;h4&gt;方法二：absolute + transform&lt;/h4&gt;
 &lt;p&gt;主要代码：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.parent { position: relative; }
.child { 
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;原理是：  &lt;code&gt;left: 50%;&lt;/code&gt;在子元素的左侧添加了一段距离，这段距离是父元素宽度的50%，接着因为translateX(50%) 设置百分比时的参照物是自身宽度，所以向左偏移了自身宽度的50%，就居中啦  ╮(‵▽′)╭ &lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/0nrw7s4w/"&gt;动动小手看看栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h4&gt;方法三：inline-block + text-align&lt;/h4&gt;
 &lt;p&gt;主要代码：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.parent { text-align: center; }
.child { display: inline-block; }&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;这种方法有一个问题是：  &lt;code&gt;parent&lt;/code&gt;设置了  &lt;code&gt;text-align: center;&lt;/code&gt;后， 因为这个属性可继承，会导致  &lt;code&gt;child&lt;/code&gt;中的文字也会居中，而这个效果是我们未必需要的，所以我们很多时候需要在  &lt;code&gt;.child&lt;/code&gt;中加一句   &lt;code&gt;text-align: left;&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/e8ns3qnx/"&gt;自己看看栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h4&gt;方法四：table + margin&lt;/h4&gt;
 &lt;p&gt;主要代码：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.child { display: table; margin: 0 auto; }&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;table的特点：宽度为内容宽度 的  &lt;strong&gt;块状元素&lt;/strong&gt;，所以也可以用  &lt;code&gt;margin: 0 auto;&lt;/code&gt;居中。&lt;/p&gt;
 &lt;p&gt;优点：只设置子元素样式就可以了，不需关心父元素。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/c0krtduf/"&gt;看看栗子&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;不喜欢这第四个方案，table是辣么有语义的一个样式，为什么随便把人家变成table (￣.￣)&lt;/p&gt;
 &lt;h3&gt;2.垂直居中&lt;/h3&gt;
 &lt;p&gt;父元素和子元素高度未知。&lt;/p&gt;
 &lt;p&gt;意欲达到的效果：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMh5R?w=117&amp;h=317" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h4&gt;方法一：flex+ align-items&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.parent {
  display: flex;
  align-items: center;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;同  &lt;strong&gt;水平居中&lt;/strong&gt;的方法一&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/d3zrvz4q/"&gt;栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h4&gt;方法二：absolute + transform&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.parent { position: relative; }
.child {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;同  &lt;strong&gt;水平居中&lt;/strong&gt;的方法二&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/btx0ueox/"&gt;栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h4&gt;方法三：table-cell + vertical-align&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.parent {
  display: table-cell;
  vertical-align: middle;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;vertical-align 可以作用在   &lt;code&gt;inline&lt;/code&gt;元素，  &lt;code&gt;inline-table&lt;/code&gt;元素，以及  &lt;code&gt;table-cell&lt;/code&gt;元素上。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/xz1879vk/"&gt;栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;3.水平垂直居中&lt;/h3&gt;
 &lt;p&gt;父元素和子元素宽高都未知。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMh7w?w=313&amp;h=314" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h4&gt;方法一：flex + justify-content + align-items&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;综合了  &lt;strong&gt;水平居中&lt;/strong&gt;和  &lt;strong&gt;垂直居中&lt;/strong&gt;的方法一&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/cyyphynb/"&gt;栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h4&gt;方法二： absolute + transform&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.parent { position: relative; }
.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;综合了  &lt;strong&gt;水平居中&lt;/strong&gt;和  &lt;strong&gt;垂直居中&lt;/strong&gt;的方法二&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/2rb78s87/"&gt;栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h4&gt;方法三：[inline-block + text-align] + [table-cell + vertical-align]&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.parent {
  display: table-cell;
  vertical-align: middle;
  text-align: center;
}
.child {
  display: inline-block;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/h9o8batt/"&gt;栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h2&gt;多列布局&lt;/h2&gt;
 &lt;h3&gt;1.一列定宽 + 一列自适应&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMk9w?w=599&amp;h=175" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;div class=&amp;quot;parent&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt;&amp;lt;p&amp;gt;left&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;right&amp;quot;&amp;gt;
    &amp;lt;p&amp;gt;right&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;right&amp;lt;/p&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;方法1：float + margin&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.left {float: left; width: 100px;}
.right { margin-left: 120px;} //有20px是间距&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;方法2：（对方法一的改进）float + margin + (fix)&lt;/h4&gt;
 &lt;p&gt;因为方法1在低版本浏览器有兼容性问题，所以改进一下。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;// 首先在right外面加了right-fix这个div
&amp;lt;div class=&amp;quot;parent&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt;&amp;lt;p&amp;gt;left&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;right-fix&amp;quot;&amp;gt; 
    &amp;lt;div class=&amp;quot;right&amp;quot;&amp;gt;
      &amp;lt;p&amp;gt;right&amp;lt;/p&amp;gt;
      &amp;lt;p&amp;gt;right&amp;lt;/p&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;CSS改动：&lt;/p&gt;
 &lt;p&gt;STEP1：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;// .left 和 .right 设置暂时不变
.right-fix {float: right; width: 100%;}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;效果为：（注意：我们把right-fix设置为白色背景，只是为了方便观察。）&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMlz7?w=459&amp;h=124" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;STEP2：&lt;/p&gt;
 &lt;p&gt;可以看到，由于right-fix宽度为100%，所以跑到了left下面一行。想要回到同一行，需要给right-fix设置一个负的margin-left值-100px。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.right-fix { margin-left: -100px; }&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;关于为什么设置了  &lt;code&gt;margin-left: 100px;&lt;/code&gt;就可以使得回到同一行呢？是因为设置了负的margin-left值之后，浏览器计算right-fix元素的宽度后，会加上-100px，也就是减掉100px，这也就是left的宽度，所以left 与 right-fix 加起来没有超过整行的宽度。  &lt;br /&gt;想要进一步了解负的margin值可以参考这篇文章：  &lt;a href="http://www.cnblogs.com/2050/archive/2012/08/13/2636467.html#2457812"&gt;CSS布局奇淫巧计之-强大的负边距&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;效果如图：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMlA8?w=522&amp;h=88" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;STEP3：&lt;/p&gt;
 &lt;p&gt;不幸的是，因为html文档中right-fix处于left后面，所以left被right-fix遮住了，实际应用中right-fix虽然没有背景色，但是我们还是不会希望它覆盖在left上面。&lt;/p&gt;
 &lt;p&gt;所以，我们需要提高 left 的层级。如何提高呢？由于设置了position: relative;的元素层级要高于普通元素，所以加上这样一条：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.left{ position: relative; }&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;具体可以参考张鑫旭写的一篇讲解  &lt;code&gt;position:relative;&lt;/code&gt;很详细的文章：  &lt;a href="http://www.zhangxinxu.com/wordpress/2011/08/css%E7%9B%B8%E5%AF%B9%E5%AE%9A%E4%BD%8Drelative%E7%BB%9D%E5%AF%B9%E5%AE%9A%E4%BD%8Dabsolute%E7%B3%BB%E5%88%97%EF%BC%88%E5%9B%9B%EF%BC%89/"&gt;CSS 相对/绝对(relative/absolute)定位系列（四）&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;最终达到我们要的效果：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMlBL?w=519&amp;h=89" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/t7xjwujj/"&gt;到jsfiddle中自己试试去&lt;/a&gt;&lt;/p&gt;
 &lt;h4&gt;方法3：float + overflow&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.left{
  width: 100px;
  margin-right: 20px;
}
.right {
  overflow: hidden;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;原理是：设置了overflow:hidden; 之后，会触发BFC模式，而BFC模式内部的布局不受外部影响，所以不会受浮动影响，不会围绕left而是跑到left右边去了。&lt;/p&gt;
 &lt;h4&gt;方法4：table&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.parent{
  display: table;
  width: 100%;
  table-layout: fixed; //加速table渲染，实现了布局优先
}
.left, .right {
  display: table-cell;
}
.left {
  width: 100px;
  padding-right: 20px;//因为table-cell不能设margin，所以设置padding来加间距
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;根据table的特性,left设置了100px后，right就占了剩余宽度。&lt;/p&gt;
 &lt;h4&gt;方法5：flex&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;.parent{ display: flex; }
.left{ width: 100px; margin-right: 20px; }
.right{ flex: 1; }&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;So easy.&lt;/p&gt;
 &lt;h3&gt;2.多列定宽 + 一列自适应&lt;/h3&gt;
 &lt;p&gt;再加一列定宽就行啦 o(≧v≦)o&lt;/p&gt;
 &lt;h3&gt;3.不定宽 + 一列自适应&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMlDY?w=427&amp;h=131" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;不定宽&lt;/strong&gt;意思是：  &lt;br /&gt;1.可以随意更改宽度：比如改为100px，200px，同时不需要更改其他样式也可以做到两列自适应布局。  &lt;br /&gt;2.或不设置宽度而是由里面子元素的宽度决定。&lt;/p&gt;
 &lt;p&gt;以下方法对应 [一列定宽+一列自适应] 中的方法&lt;/p&gt;
 &lt;p&gt;方法1： float + margin ？&lt;/p&gt;
 &lt;p&gt;不好意思，做不到。&lt;/p&gt;
 &lt;p&gt;方法2： float + margin +（fix） ？&lt;/p&gt;
 &lt;p&gt;不好意思，也做不到。&lt;/p&gt;
 &lt;p&gt;方法3： float + overflow ？&lt;/p&gt;
 &lt;p&gt;阔以！  &lt;strong&gt;right的样式没有依赖于width的宽度。&lt;/strong&gt;代码量也少，很棒棒哦！&lt;/p&gt;
 &lt;p&gt;方法4：table&lt;/p&gt;
 &lt;p&gt;阔以！  &lt;strong&gt;right的样式没有依赖于width的宽度，即不关心width的宽度。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;方法5：flex&lt;/p&gt;
 &lt;p&gt;强大的flex当然可以~（傲娇脸 ）&lt;/p&gt;
 &lt;h3&gt;4.两列不定宽 + 一列自适应&lt;/h3&gt;
 &lt;p&gt;没错，跟你想的一样，加一列不定宽的就行了，样式都一样 ㄟ( ▔, ▔ )ㄏ&lt;/p&gt;
 &lt;h3&gt;5.等分布局&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMlFE?w=544&amp;h=326" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;C + G = 4*（W + G）   &lt;br /&gt;以下例子假设间距G = 20px&lt;/p&gt;
 &lt;p&gt;结构：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;div class=&amp;quot;parent&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&amp;lt;p&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&amp;lt;p&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&amp;lt;p&amp;gt;3&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&amp;lt;p&amp;gt;4&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;方法1：float&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.parent{ margin-left: -20px; }//就是上面公式中等号左边的G
.column{
  float: left;
  width: 25%;
  padding-left: 20px;//这里要注意，因为我们用padding来表示间距，所以如果你是给p元素设置了background-color，会发现没有间距，p标签的width才是上图中的W
  box-sizing: border-box;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;方法2：table&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;div class=&amp;quot;parent-fix&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;parent&amp;quot;&amp;gt;
      &amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&amp;lt;p&amp;gt;1&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&amp;lt;p&amp;gt;2&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&amp;lt;p&amp;gt;3&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
      &amp;lt;div class=&amp;quot;column&amp;quot;&amp;gt;&amp;lt;p&amp;gt;4&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;.parent-fix{
  margin-left: -20px;
}
.parent {
  display: table;
  width: 100%;
}
.column {
  display: table-cell;
  padding-left: 20px;//因为单元格不能设置margin，所以间距只能用padding来做。
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;因为table的width默认是随内容宽度变化的，所以需要手动设置  &lt;code&gt;width: 100%;&lt;/code&gt;。又因为明确设置了宽度的元素就没办法用将margin设为负值的方式增加20px宽度了，所以需要在外面加一个父元素  &lt;code&gt;parent-fix&lt;/code&gt;。  &lt;br /&gt;这里大家可以自己试试比较一下给  &lt;code&gt;parent-fix&lt;/code&gt;  &lt;strong&gt;设置width为100%&lt;/strong&gt;与  &lt;strong&gt;不设置width&lt;/strong&gt;时parent-fix实际宽度（用调试工具里的查看元素看）的区别来理解。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/o7czrt0o/"&gt;呐，jsfiddle示例在这&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;方法3：flex&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.parent { display: flex; }
.column { flex: 1; } 
.column + .column { margin-left: 20px; }//好用的兄弟选择器 (｡・`ω´･)&lt;/code&gt;&lt;/pre&gt;
 &lt;h1&gt;上面这个等分布局这个整理完在另一篇CSS布局的文章里面给个链接&lt;/h1&gt;
 &lt;h3&gt;6.一列定宽+一列自适应（当其中较高的一列高度变化，另一列同步变化）&lt;/h3&gt;
 &lt;p&gt;右侧变高，左侧高度随之变化：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#21491;&amp;#20391;&amp;#21464;&amp;#39640;&amp;#65292;&amp;#24038;&amp;#20391;&amp;#39640;&amp;#24230;&amp;#38543;&amp;#20043;&amp;#21464;&amp;#21270;1" src="https://segmentfault.com/img/bVMo93?w=765&amp;h=276" title="&amp;#21491;&amp;#20391;&amp;#21464;&amp;#39640;&amp;#65292;&amp;#24038;&amp;#20391;&amp;#39640;&amp;#24230;&amp;#38543;&amp;#20043;&amp;#21464;&amp;#21270;1"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;↓↓&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#21491;&amp;#20391;&amp;#21464;&amp;#39640;&amp;#65292;&amp;#24038;&amp;#20391;&amp;#39640;&amp;#24230;&amp;#38543;&amp;#20043;&amp;#21464;&amp;#21270;2" src="https://segmentfault.com/img/bVMpan?w=767&amp;h=200" title="&amp;#21491;&amp;#20391;&amp;#21464;&amp;#39640;&amp;#65292;&amp;#24038;&amp;#20391;&amp;#39640;&amp;#24230;&amp;#38543;&amp;#20043;&amp;#21464;&amp;#21270;2"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;方法1：table&lt;/p&gt;
 &lt;p&gt;table的列之间有天然等高的特性。&lt;/p&gt;
 &lt;p&gt;就是上面   &lt;strong&gt;1.一列定宽 + 一列自适应&lt;/strong&gt;中的  &lt;strong&gt;方法4：table&lt;/strong&gt;。&lt;/p&gt;
 &lt;p&gt;方法2：flex&lt;/p&gt;
 &lt;p&gt;flex也是天然的等高 &amp;lt;(￣︶￣)&amp;gt; 因为它默认的align-items为stretch，即在交叉轴上默认拉伸占满整个容器。&lt;/p&gt;
 &lt;p&gt;仍旧是上面  &lt;strong&gt;1.一列定宽 + 一列自适应&lt;/strong&gt;中的  &lt;strong&gt;方法5：flex&lt;/strong&gt;。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/kshefy4s/"&gt;简单到不好意思给栗子&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;方法3：float&lt;/p&gt;
 &lt;p&gt;仍旧是参照上面  &lt;strong&gt;1.一列定宽 + 一列自适应&lt;/strong&gt;中的  &lt;strong&gt;方法3：float + overflow&lt;/strong&gt;，float并没有天然等高，所以要在这个基础上做改动。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.left{
  width: 100px;
  margin-right: 20px;
}
.right {
  overflow: hidden;
}
//增加部分
.left, .right{
  padding-bottom: 9999px;//使得有背景色的部分变的很高
  margin-bottom: -9999px;//用负的margin抵消掉很高的padding，让高度变回left和right中较高的那部分的内容高度，以便parent用overflow: hidden;去隐藏掉超出部分
}
.parent {
  overflow: hidden;//隐藏掉超出边界的部分 
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;其实left的实际高度并没有变，是一种伪等高，只是背景变高。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/8hyacvkg/"&gt;栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;7.全等四宫格&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVqUsZ" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;这是练习题，置几试试吧。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;div class=&amp;quot;parent&amp;quot;&amp;gt;
  &amp;lt;div class=&amp;quot;outer&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;column&amp;gt;1&amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;column&amp;gt;2&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div class=&amp;quot;outer&amp;quot;&amp;gt;
    &amp;lt;div class=&amp;quot;column&amp;gt;3&amp;lt;/div&amp;gt;
    &amp;lt;div class=&amp;quot;column&amp;gt;4&amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;方法1：flex&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.parent {
  display: flex;
  flex-wrap: wrap;
  align-content: space-between;
}
.outer {
  flex-basis: 100%;
  display: flex;
  justify-content: space-between;
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/d1ndbpxn/"&gt;一颗仅供参考的栗子&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;方法2：float&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/twckmv31/"&gt;我的栗子&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;方法3：table&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/t1for4g0/"&gt;一个栗子不一定对&lt;/a&gt;&lt;/p&gt;
 &lt;h2&gt;全屏布局&lt;/h2&gt;
 &lt;h3&gt;1.定宽（px）+自适应&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMsBG?w=588&amp;h=428" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;只有主内容区 right 随内容滚动。&lt;/p&gt;
 &lt;p&gt;方法1.position&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;div class=&amp;quot;parent&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;top&amp;quot;&amp;gt;top&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt;left&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;right&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;help-right&amp;quot;&amp;gt;right&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;bottom&amp;quot;&amp;gt;bottom&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;html, body, .parent {height: 100%; overflow: hidden;}//为了让整个页面不滚动
.top {
  position: absolute;
  top: 0; 
  left: 0; right: 0; //注意这个很棒的设置！可以自动占满整行 ヾ(o◕∀◕)ﾉ 
  height: 100px;
}
.left {
  position: absolute;
  left: 0;
  top: 100px; bottom: 50px;
  width:200px;
}
.right {
  position: absolute;
  left: 200px; right: 0;
  top: 100px; bottom: 50px; //这也是上下占满除了top和bottom之外的所有高度
  overflow: auto;//让主内容区可以滚动
}
.help-right {//假装有很多内容
  width: 1000px;
  height: 1000px;
}
.bottom{
  position: absolute;
  bottom: 0; 
  left: 0; right: 0;
  height: 50px;
}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/50j3q2bg/"&gt;动手写写才记得住&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;方法2.flex&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;div class=&amp;quot;parent&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;top&amp;quot;&amp;gt;top&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;middle&amp;quot;&amp;gt;
&amp;lt;div class=&amp;quot;left&amp;quot;&amp;gt;left&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;right&amp;quot;&amp;gt;&amp;lt;div class=&amp;quot;help-right&amp;quot;&amp;gt;right&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;quot;bottom&amp;quot;&amp;gt;bottom&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;html, body, .parent {height: 100%; overflow: hidden;}
.parent {display: flex; flex-direction: column;}
.top { height: 100px; }
.middle {flex: 1; display: flex;}
.left { width:200px; }
.right { flex: 1; overflow: auto; }
.help-right { width: 1000px; height: 1000px; }
.bottom{ height: 50px; }&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/txcfpsLy/"&gt;栗子&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;2.百分比定宽（%）+自适应&lt;/h3&gt;
 &lt;p&gt;方法1.position ， 方法2.flex ：&lt;/p&gt;
 &lt;p&gt;把原来的用px写的定宽改成百分比就可以了。是相对于body的高度和宽度来变化的。感觉top和bottom高度设置百分比不是很实用。&lt;/p&gt;
 &lt;h3&gt;3.自适应+自适应&lt;/h3&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMsCj?w=583&amp;h=434" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;方法1.position&lt;/p&gt;
 &lt;p&gt;定宽的高度和宽度影响旁边栏的布局，所以实现不了  - 。-&lt;/p&gt;
 &lt;p&gt;方法2.flex&lt;/p&gt;
 &lt;p&gt;阔以实现，而且相当简单 ╮(╯▽╰)╭  把刚刚设置了高度和宽度的地方去掉就可以了  ∑(っ °Д °;)っ &lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://jsfiddle.net/DarcyAn/j1t84e9r/"&gt;惊人的栗子&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;方法3.Grid&lt;/p&gt;
 &lt;p&gt;阔以实现，但是因为还是W3C的草案，所以会经常变化，不稳定，而且浏览器支持也不好。&lt;/p&gt;
 &lt;h1&gt;响应式&lt;/h1&gt;
 &lt;h3&gt;想要达到的效果&lt;/h3&gt;
 &lt;p&gt;只写一个网站，在多个终端显示，在小屏幕上会隐藏部分元素。&lt;/p&gt;
 &lt;h3&gt;现在的情况&lt;/h3&gt;
 &lt;p&gt;在PC端浏览器中可以正常访问的网站，到了手机上之后，内容就会变得特别小。  &lt;br /&gt;原因：所有的移动设备都有一个viewport（视窗），这个视窗不是手机屏幕大小，而是一个虚拟的窗口，比如iPhone4的viewport宽度为980px（如下图所示）。显示的时候再按照比例将这980px的内容压缩显示到实际的屏幕宽度中。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMsCT?w=667&amp;h=456" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;所以为防止让页面缩小，在移动设备中，我们会做如下设置&lt;/h3&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;
 width=device-width //让宽度等于设备宽度，因为不同的移动设备宽度不同 iphone4为320px
 ,initial-scale=1.0 //初始缩放1.0， 即不缩放，网站就不会被缩小了
 ,user-scalable=no //防止用户手动缩放
&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;设置结束之后，如何具体开发？&lt;/h3&gt;
 &lt;h4&gt;方法1.宽度尽量自适应，而不要用定宽。&lt;/h4&gt;
 &lt;h4&gt;方法2.用媒体查询 @media&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;@media screen and (max-width: 320px) {
  //最大宽度为320px，即视窗宽度小于等于320px
  div{..}
  .class-name{...}
}

@media screen and (min-width: 320px) and (max-width: 769px){
  //最小宽度为320px，最大宽度为769px，即视窗宽度大于320px，小于769px
}&lt;/code&gt;&lt;/pre&gt;
 &lt;h1&gt;响应式&lt;/h1&gt;
 &lt;h2&gt;目的&lt;/h2&gt;
 &lt;p&gt;减少卡顿  &lt;br /&gt;利于SEO  &lt;br /&gt;便于代码维护&lt;/p&gt;
 &lt;h2&gt;方法&lt;/h2&gt;
 &lt;h3&gt;1. 减少页面请求&lt;/h3&gt;
 &lt;h4&gt;减少css文件请求&lt;/h4&gt;
 &lt;p&gt;（1）多个css文件合并成一个  &lt;br /&gt;（2）少量css样式内联  &lt;br /&gt;（3）避免用import的方式引入css文件，因为每个import语句都会产生一个css请求，并且是同步的请求。&lt;/p&gt;
 &lt;h3&gt;2.减少资源文件大小&lt;/h3&gt;
 &lt;p&gt;（1）减少图片大小  &lt;br /&gt;选择合适的图片格式，小尺寸、半透明的用png，大尺寸、色彩绚丽用jpg（因为jpg会对图片进行压缩）  &lt;br /&gt;压缩图片&lt;/p&gt;
 &lt;p&gt;（2）css值缩写  &lt;br /&gt;margin，padding，border，font，border-radius等属性&lt;/p&gt;
 &lt;p&gt;（3）省略值为0 的单位&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;margin: 0 10px;
line-height: .5;
background-position: 50% 0;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;（4）颜色值最短表示&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;red
rgb(0,0,0)
rgba(0,0,0,0)
#000000
#000&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;（5）css选择器合并&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;.left, .right {...}&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;（6）文件压缩  &lt;br /&gt;用工具对文件进行自动压缩，去掉空格。&lt;/p&gt;
 &lt;h3&gt;3.提升页面性能&lt;/h3&gt;
 &lt;h4&gt;加载顺序&lt;/h4&gt;
 &lt;p&gt;css通常放在head中，而js通常放在body底部，因为js会阻碍其他资源加载。&lt;/p&gt;
 &lt;h4&gt;减少标签数量。&lt;/h4&gt;
 &lt;h4&gt;选择器长度&lt;/h4&gt;
 &lt;pre&gt;  &lt;code&gt;body .menu ul li a { ... } //太长了
.menu a { ... } //更好&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;避免耗性能属性&lt;/h4&gt;
 &lt;p&gt;比如：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;expression
filter
border-radius
box-shadow
gradients&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;给图片设置固定宽高，并且图片实际宽高与设置宽高相同，否则浏览器会回流设置多次宽高&lt;/h4&gt;
 &lt;h4&gt;所有表现用css实现&lt;/h4&gt;
 &lt;h3&gt;4.通过规范提高代码可读性，可维护性&lt;/h3&gt;
 &lt;p&gt;（1）规范：缩进，变量名等  &lt;br /&gt;（2）语义化：除了标签，css、id名最好也尽量有意义  &lt;br /&gt;（3）尽量避免Hack，一定要用也要统一的标识，比如IE7用*  &lt;br /&gt;（4）模块化：相关联的结构做成一个个模块，复用性更强  &lt;br /&gt;（5）添加注释&lt;/p&gt;
 &lt;h1&gt;规范与模块化&lt;/h1&gt;
 &lt;h2&gt;规范&lt;/h2&gt;
 &lt;p&gt;1.注释的文字两侧需加空格，防止因编码问题导致注释失效&lt;/p&gt;
 &lt;p&gt;2.为避免命名污染，可以给class加前缀，比如：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;g- 布局命名
m- 模块命名
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;3.语义化命名&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;//结构化命名
top { ... }

//改用语义化命名
nav { ... }&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;4.属性的书写顺序&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;" src="https://segmentfault.com/img/bVMwjz?w=848&amp;h=457" title="&amp;#22270;&amp;#29255;&amp;#25551;&amp;#36848;"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;模块化&lt;/h2&gt;
 &lt;h3&gt;什么是模块化&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;ol&gt;
   &lt;li&gt;    &lt;p&gt;一系列相关联的结构组成的整体&lt;/p&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;p&gt;带有一定的语义，而非表现&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
 &lt;p&gt;比如，翻页器（或叫分页器paging）、轮播图。&lt;/p&gt;
 &lt;h3&gt;怎么做？&lt;/h3&gt;
 &lt;blockquote&gt;  &lt;ol&gt;
   &lt;li&gt;    &lt;p&gt;为模块分类命名（如.m-, .md-）&lt;/p&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;p&gt;以一个主选择器开头（模块根节点）&lt;/p&gt;&lt;/li&gt;
   &lt;li&gt;    &lt;p&gt;使用以主选择器开头的后代选择器（模块子节点）&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/blockquote&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;div class=&amp;quot;m-nav&amp;quot;&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li class=&amp;quot;z-crt&amp;quot;&amp;gt;&amp;lt;a&amp;gt;链接&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;a&amp;gt;链接&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;//根节点
.m-nav { ... }
//子节点
.m-nav ul{ ... }
.m-nav li{ ... }
.m-nav a{ ... }
.m-nav .z-crt a{ ... }/* 交互状态变化 */&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;若有一个模块只是比上述模块多了一个按钮，其余部分完全相同，怎么办？&lt;/p&gt;
 &lt;h3&gt;怎样扩展？&lt;/h3&gt;
 &lt;p&gt;为根节点加一个class就好了，这里我们加一个   &lt;code&gt;m-nav-1&lt;/code&gt;。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;div class=&amp;quot;m-nav m-nav-1&amp;quot;&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li class=&amp;quot;z-crt&amp;quot;&amp;gt;&amp;lt;a&amp;gt;链接&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;&amp;lt;a&amp;gt;链接&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;lt;a class=&amp;quot;btn&amp;quot;&amp;gt;我是新加的a标签&amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;pre&gt;  &lt;code&gt;//变化的部分在 .m-nav-1 这个新class中写
.m-nav-1 { ... }
.m-nav-1 a{ ... }
.m-nav-1 .btn{ ... }&lt;/code&gt;&lt;/pre&gt;
 &lt;h3&gt;网易的规范和代码库&lt;/h3&gt;
 &lt;p&gt;  &lt;a href="http://nec.netease.com/standard"&gt;规范页&lt;/a&gt;：包含了CSS规范、HTML规范和工程师规范&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://nec.netease.com/library"&gt;代码库&lt;/a&gt;：包含了常用的布局方式、常见模块和元件的实现以及一些bug、技巧等&lt;/p&gt;
 &lt;p&gt;——————  &lt;br /&gt;  &lt;em&gt;教是最好的学。&lt;/em&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>html css 页面布局 html5 css3</category>
      <guid isPermaLink="true">https://itindex.net/detail/56867-%E9%A1%B5%E9%9D%A2-%E6%9E%B6%E6%9E%84-html</guid>
      <pubDate>Fri, 21 Apr 2017 21:54:10 CST</pubDate>
    </item>
    <item>
      <title>工作中经常用到github上优秀、实用、轻量级、无依赖的插件和库</title>
      <link>https://itindex.net/detail/56842-%E5%B7%A5%E4%BD%9C-github-%E8%BD%BB%E9%87%8F%E7%BA%A7</link>
      <description>&lt;p&gt;  &lt;strong&gt;原文收录在我的 GitHub博客 (   &lt;a href="https://github.com/jawil/blog)"&gt;https://github.com/jawil/blog)&lt;/a&gt; ，喜欢的可以关注最新动态，大家一起多交流学习，共同进步，以学习者的身份写博客，记录点滴。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;按照格式推荐好用的插件有福利哦，说不定会送1024论坛邀请码，好自为之，你懂的，嘿嘿嘿。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997801" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;由于github的issues没有TOC菜单栏导航，所以这里方便大家查看，先安利一款Chrome浏览器的插件，感谢github用户@BBcaptain 推荐。  &lt;a href="https://chrome.google.com/webstore/detail/smart-toc/lifgeihcfpkmmlfjbailfpfhbahhibba"&gt;点击我呀，进入商店，自备梯子，如果不会翻墙，赶紧转行&lt;/a&gt;。。。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;效果预览，是不是很方便，图片较多，建议等待一会或者多刷新几下：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997802" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;Echo.js – 简单易用的图片延迟加载插件&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/toddmotto/echo/strong"&gt;https://github.com/toddmotto/...&lt;/a&gt; &lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="https://toddmotto.com/echo-js-simple-javascript-image-lazy-loading//strong"&gt;https://toddmotto.com/echo-js...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：3k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm:npm install echo-js
bower:bower install echojs&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：2KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　Echo.js 是一个独立的延迟加载图片的 JavaScript 插件。Echo.js 不依赖第三方库，压缩后不到1KB大小。 延迟加载是提高网页首屏显示速度的一种很有效的方法，当图片元素进入窗口可视区域的时候，它就会改变图像的 src 属性，从服务端加载所需的图片，这也是一个异步的过程。  &lt;br /&gt;　　  &lt;br /&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="https://jawil.github.io/demo/echo.js/"&gt;https://jawil.github.io/demo/...&lt;/a&gt;  &lt;br /&gt;Demo源码：  &lt;a href="https://github.com/jawil/jawil.github.io/tree/master/demo/echo.js"&gt;https://github.com/jawil/jawi...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997803" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Lazyr.js – 延迟加载图片（Lazy Loading）&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/callmecavs/layzr.js/strong"&gt;https://github.com/callmecavs...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://callmecavs.com/layzr.js//strong"&gt;http://callmecavs.com/layzr.j...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：5k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm:npm install layzr.js --save&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：2.75 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　Lazyr.js 是一个小的、快速的、现代的、相互间无依赖的图片延迟加载库。通过延迟加载图片，让图片出现在（或接近)）视窗才加载来提高页面打开速度。这个库通过保持最少选项并最大化速度。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;跟上面的Echo.js用法类似，喜欢的可以自行去尝试，这里就不再演示了，我一般用Echo.js。&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;better-scroll.js – 小巧，灵活的 JavaScript 模拟滚动条的插件&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/ustbhuangyi/better-scroll/strong"&gt;https://github.com/ustbhuangy...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="https://ustbhuangyi.github.io/better-scroll//strong"&gt;https://ustbhuangyi.github.io...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：300+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm install better-scroll --save-dev
import BScroll from &amp;apos;better-scroll&amp;apos;;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：24 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　better-scroll 是一个只有24.8KB的 JavaScript 模拟浏览器自带滚动条的插件，是在  &lt;strong&gt;   &lt;a href="https://github.com/cubiq/iscroll"&gt;iscroll&lt;/a&gt;&lt;/strong&gt;开源的基础上进行优化的一款插件，简单好用，轻巧高性能，功能强大，API通俗易懂，是一款优秀的scroll插件，抛弃原生滚动条，从现在做起。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="https://jawil.github.io/demo/eleme/"&gt;https://jawil.github.io/demo/...&lt;/a&gt; (PC端切换到移动模式)  &lt;br /&gt;Demo源码：  &lt;a href="https://github.com/jawil/webpack2"&gt;https://github.com/jawil/webp...&lt;/a&gt;  &lt;br /&gt;注：在ustbhuangyi的源码下改进了一下，做成多页面，技术栈：webpack2+vue.js2+sass+axios&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997804" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;better-picker – 一款轻量级IOS风格的JavaScript选择器&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/ustbhuangyi/picker/strong"&gt;https://github.com/ustbhuangy...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://ustbhuangyi.github.io/picker//strong"&gt;http://ustbhuangyi.github.io/...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：200+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm: npm install better-picker --save-dev
import Picker from &amp;apos;better-picker&amp;apos;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：46.5 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　  移动端最好用的的筛选器组件，高仿 ios 的 UIPickerView ，非常流畅的体验，原生 JS 实现，不依赖任何插件和第三方库。  &lt;br /&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://ustbhuangyi.github.io/picker/"&gt;http://ustbhuangyi.github.io/...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997805" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Sortable – 一款用于实现元素拖拽排序的功能的插件&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/RubaXa/Sortable/strong"&gt;https://github.com/RubaXa/Sor...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://rubaxa.github.io/Sortable//strong"&gt;http://rubaxa.github.io/Sorta...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：9k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Bower: bower install sortablejs --save
npm: npm install sortablejs &lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：5 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　Sortable：现代浏览器上用于实现元素拖拽排序的功能，支持 Meteor, AngularJS, React，不依赖 jQuery这玩意。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://rubaxa.github.io/Sortable/"&gt;http://rubaxa.github.io/Sorta...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997806" title=""&gt;&lt;/img&gt;  &lt;br /&gt;   &lt;/p&gt;
 &lt;h2&gt;slick – 功能异常强大的一个图片滑动切换效果库&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/kenwheeler/slick/strong"&gt;https://github.com/kenwheeler...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://kenwheeler.github.io/slick//strong"&gt;http://kenwheeler.github.io/s...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：17k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Bower: bower install slick-carousel --save
npm: npm install slick-carousel
CDNs:
https://cdnjs.com/libraries/slick-carousel
https://www.jsdelivr.com/projects/jquery.slick&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：40 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　slick 是一个功能异常强大的一个图片滑动切换效果库，接口丰富，支持各种动画和各种样式的切换滑动，唯一的缺点就是  &lt;strong&gt;基于jQuery&lt;/strong&gt;，基本废了，现在没人喜欢用jQuery，该淘汰了。。。支持 RequireJS 以及 Bower 安装。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://kenwheeler.github.io/slick/"&gt;http://kenwheeler.github.io/s...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997807" title=""&gt;&lt;/img&gt;   &lt;br /&gt;   &lt;/p&gt;
 &lt;h2&gt;swipe – 非常轻量级的一个图片滑动切换效果库&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/lyfeyaj/Swipe/strong"&gt;https://github.com/lyfeyaj/Sw...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://lyfeyaj.github.io/swipe//strong"&gt;http://lyfeyaj.github.io/swip...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：200+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Bower: bower install swipe-js  --save
npm: npm install swipe-js &lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：5 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　swipe：非常轻量级的一个图片滑动切换效果库, 性能良好, 尤其是对手机的支持, 压缩后的大小约 5kb。可以结合 jQuery、RequireJS 使用。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://lyfeyaj.github.io/swipe/"&gt;http://lyfeyaj.github.io/swipe/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997808" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Slideout.js – 触摸滑出式 Web App 导航菜单&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/mango/slideout/strong"&gt;https://github.com/mango/slid...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="https://slideout.js.org//strong"&gt;https://slideout.js.org/https://github.com/t4t5/sweet...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://t4t5.github.io/sweetalert//strong"&gt;http://t4t5.github.io/sweetal...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：15k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;bower:bower install sweetalert
npm:npm install sweetalert
&amp;lt;script src=&amp;quot;dist/sweetalert.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;dist/sweetalert.css&amp;quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：16 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　 Sweet Alert 是一个替代传统的 JavaScript Alert 的漂亮提示效果。SweetAlert 自动居中对齐在页面中央，不管您使用的是台式电脑，手机或平板电脑看起来效果都很棒。另外提供了丰富的自定义配置选择，可以灵活控制。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://t4t5.github.io/sweetalert/"&gt;http://t4t5.github.io/sweetal...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997809" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;类似插件：limonte/sweetalert2，好像这个最近还在更新，这个感觉更漂亮，大同小异，这里不多做介绍。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/limonte/sweetalert2/strong"&gt;https://github.com/limonte/sw...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：    &lt;a href="https://limonte.github.io/sweetalert2//strong"&gt;https://limonte.github.io/swe...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Awesomplete.js - 比datalist更强大更实用，零依赖的简单自动补全插件&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/leaverou/awesomplete//strong"&gt;https://github.com/leaverou/a...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://leaverou.github.io/awesomplete//strong"&gt;http://leaverou.github.io/awe...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：5k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;  &lt;br /&gt;`npm: npm install awesomplete  &lt;br /&gt;`&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;大小：5 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　Awesomplete 是一款超轻量级的，可定制的，简单的自动完成插件，零依赖，使用现代化标准构建。你可以简单地添加 awesomplete 样式，让它自动处理（你仍然可以通过指定 HTML 属性配置更多选项），您可以用几行 JS 代码，提供更多的自定义。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://leaverou.github.io/awesomplete/"&gt;http://leaverou.github.io/awe...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997810" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h2&gt;Cleave.js – 自动格式化表单输入框的文本内容&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/nosir/cleave.js//strong"&gt;https://github.com/nosir/clea...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://nosir.github.io/cleave.js//strong"&gt;http://nosir.github.io/cleave...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：6k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm:npm install --save cleave.js
bower:bower install --save cleave.js&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：11.1 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　Cleave.js 有一个简单的目的：帮助你自动格式输入的文本内容。 这个想法是提供一个简单的方法来格式化您的输入数据以增加输入字段的可读性。通过使用这个库，您不需要编写任何正则表达式来控制输入文本的格式。然而，这并不意味着取代任何验证或掩码库，你仍应在后端验证数据。它支持信用卡号码、电话号码格式（支持各个国家）、日期格式、数字格式、自定义分隔符，前缀和块模式等，提供 CommonJS/AMD 模式以及ReactJS 组件端口。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://nosir.github.io/cleave.js/"&gt;http://nosir.github.io/cleave...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。  &lt;br /&gt;输入201748自动格式化成2017-04-08，是不是很方便  &lt;br /&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997811" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;/p&gt;
 &lt;h2&gt;Immutable.js – JavaScript 不可变数据集合（Facebook出品）&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/facebook/immutable-js/strong"&gt;https://github.com/facebook/i...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://facebook.github.io/immutable-js//strong"&gt;http://facebook.github.io/imm...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：18k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm install immutable --S-D&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：60 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　不可变数据是指一旦创建就不能被修改的数据，使得应用开发更简单，允许使用函数式编程技术，比如惰性评估。Immutable JS 提供一个惰性 Sequence，允许高效的队列方法链，类似 map 和 filter ，不用创建中间代表。Immutable.js 提供持久化的列表、堆栈、Map， 以及 OrderedMap 等，最大限度地减少需要复制或缓存数据。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;script src=&amp;quot;immutable.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
var map1 = Immutable.Map({a:1, b:2, c:3});
var map2 = map1.set(&amp;apos;b&amp;apos;, 50);
map1.get(&amp;apos;b&amp;apos;); // 2
map2.get(&amp;apos;b&amp;apos;); // 50
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;更多信息和探讨请移步,这里不多做介绍：  &lt;a href="https://www.zhihu.com/question/28016223"&gt;facebook immutable.js 意义何在，使用场景？&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Popmotion.js – 小巧，灵活的 JavaScript 运动引擎&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/Popmotion/popmotion/strong"&gt;https://github.com/Popmotion/...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="https://popmotion.io//strong"&gt;https://popmotion.io/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：3k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm install --save popmotion
import { tween } from &amp;apos;popmotion&amp;apos;;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：12 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　Popmotion 是一个只有12KB的 JavaScript 运动引擎，可以用来实现动画，物理效果和输入跟踪。原生的DOM支持：CSS，SVG，SVG路径和DOM属性的支持，开箱即用。Popmotion 网站上有很多很赞的效果，赶紧去体验一下。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://codepen.io/popmotion/pen/egwMGQ"&gt;http://codepen.io/popmotion/p...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997812" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;    &lt;/p&gt;
 &lt;h2&gt;Dynamics.js - 创建逼真的物理动画的 JS 库&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/michaelvillar/dynamics.js/strong"&gt;https://github.com/michaelvil...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://dynamicsjs.com//strong"&gt;http://dynamicsjs.com/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：6k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm: npm install dynamics.js
bower: bower install dynamics.js&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：20 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　Popmotion 是一个只有12KB的 JavaScript 运动引擎，可以用来实现动画，物理效果和输入跟踪。原生的DOM支持：CSS，SVG，SVG路径和DOM属性的支持，开箱即用。Popmotion 网站上有很多很赞的效果，赶紧去体验一下。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://dynamicsjs.com/"&gt;http://dynamicsjs.com/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997813" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Rainyday.js – 使用 JavaScript 实现雨滴效果&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/maroslaw/rainyday.js/strong"&gt;https://github.com/maroslaw/r...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://maroslaw.github.io/rainyday.js//strong"&gt;http://maroslaw.github.io/rai...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：5k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在github的dist目录下载rainyday.min.js&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;大小：10 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　Rainyday.js 背后的想法是创建一个 JavaScript 库，利用 HTML5 Canvas 渲染一个雨滴落在玻璃表面的动画。Rainyday.js 有功能可扩展的 API，例如碰撞检测和易于扩展自己的不同的动画组件的实现。它是一个使用 HTML5 特性纯 JavaScript 库，支持大部分现代浏览器。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://maroslaw.github.io/rainyday.js/demo012_1.html"&gt;http://maroslaw.github.io/rai...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997814" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;Swiper – 经典的移动触摸滑块轮播插件&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/nolimits4web/Swiper/strong"&gt;https://github.com/nolimits4w...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://idangero.us/swiper//strong"&gt;http://idangero.us/swiper/https://github.com/daniel-lun...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://daniel-lundin.github.io/snabbt.js//strong"&gt;http://daniel-lundin.github.i...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：5k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;bower:bower install snabbt.js
npm:npm install snabbt.js
CDNs:
https://cdnjs.com/libraries/snabbt.js
http://www.jsdelivr.com/#!snabbt&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：16 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　Snabbt.js 是一个简约的 JavaScript 动画库。它会平移，旋转，缩放，倾斜和调整你的元素。通过矩阵乘法运算，变换等可以任何你想要的方式进行组合。最终的结果通过 CSS3 变换矩阵设置。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://daniel-lundin.github.io/snabbt.js/periodic.html"&gt;http://daniel-lundin.github.i...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997815" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;imagesLoaded – 检测网页中的图片是否加载完成&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/desandro/imagesloaded/strong"&gt;https://github.com/desandro/i...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://imagesloaded.desandro.com//strong"&gt;http://imagesloaded.desandro....&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：6k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Bower: bower install imagesloaded --save
npm: npm install imagesloaded
CDNs:
&amp;lt;script src=&amp;quot;https://unpkg.com/imagesloaded@4.1/imagesloaded.pkgd.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;https://unpkg.com/imagesloaded@4.1/imagesloaded.pkgd.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：5 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　imagesLoaded 是一个用于来检测网页中的图片是否载入完成的 JavaScript 工具库。支持回调的获取图片加载的进度，还可以绑定自定义事件。可以结合 jQuery、RequireJS 使用。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://codepen.io/desandro/full/hlzaw/"&gt;http://codepen.io/desandro/fu...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997816" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Fort.js – 时尚、现代的表单填写进度提示效果&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/idriskhenchil/Fort.js/strong"&gt;https://github.com/idriskhenc...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="https://github.com/idriskhenchil/Fort.js/strong"&gt;https://github.com/idriskhenc...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：800+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;CDN:
css:
https://cdnjs.cloudflare.com/ajax/libs/Fort.js/2.0.0/fort.min.css
js:
https://cdnjs.cloudflare.com/ajax/libs/Fort.js/2.0.0/fort.min.js&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：6 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　Fort.js 是一款用于时尚、现代的表单填写进度提示效果的 JavaScript 库，你需要做的就是添加表单，剩下的任务就交给 Fort.js 算法了，使用非常简单。提供了Default、Gradient、Sections 以及 Flash 四种效果，满足开发的各种场合需要。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://idriskhenchil.github.io/default/index.html"&gt;http://idriskhenchil.github.i...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997817" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;MagicSuggest – Bootstrap 主题的多选组合框&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/nicolasbize/magicsuggest/strong"&gt;https://github.com/nicolasbiz...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://nicolasbize.com/magicsuggest//strong"&gt;http://nicolasbize.com/magics...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：1k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;github自行进行下载&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：21.8 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　MagicSuggest 是专为 Bootstrap 主题开发的多选组合框。它支持自定义呈现，数据通过 Ajax 异步获取，使用组件自动过滤。它允许空间免费项目，也有动态加载固定的建议。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://nicolasbize.com/magicsuggest/examples.html"&gt;http://nicolasbize.com/magics...&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997818" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Numeral.js – 格式化和操作数字的 JavaScript 库&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/adamwdraper/Numeral-js/strong"&gt;https://github.com/adamwdrape...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://numeraljs.com//strong"&gt;http://numeraljs.com/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：4k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm: npm install numeral
CDNs:
&amp;lt;script src=&amp;quot;//cdnjs.cloudflare.com/ajax/libs/numeral.js/2.0.6/numeral.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：10 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　　Numeral.js 是一个用于格式化和操作数字的 JavaScript 库。数字可以格式化为货币，百分比，时间，甚至是小数，千位，和缩写格式，功能十分强大。支持包括中文在内的17种语言。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;var myNumeral = numeral(1000);

var value = myNumeral.value();
// 1000

var myNumeral2 = numeral(&amp;apos;1,000&amp;apos;);

var value2 = myNumeral2.value();
// 1000&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Draggabilly – 轻松实现拖放功能（Drag &amp;amp; Drop）&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/desandro/draggabilly/strong"&gt;https://github.com/desandro/d...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://draggabilly.desandro.com//strong"&gt;http://draggabilly.desandro.c...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：2k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Bower: bower install draggabilly --save
npm: npm install draggabilly
CDNs:
&amp;lt;script src=&amp;quot;https://npmcdn.com/draggabilly@2.1/dist/draggabilly.pkgd.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;https://npmcdn.com/draggabilly@2.1/dist/draggabilly.pkgd.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：5 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　Draggabilly 是一个很小的 JavaScript 库，专注于拖放功能。只需要简单的设置参数就可以在你的网站用添加拖放功能。兼容 IE8+ 浏览器，支持多点触摸。可以灵活绑定事件，支持 RequireJS 以及 Bower 安装。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://draggabilly.desandro.com/"&gt;http://draggabilly.desandro.com/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997819" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;Quill – 可以灵活自定义的开源的富文本编辑器&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/quilljs/quill//strong"&gt;https://github.com/quilljs/qu...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="https://quilljs.com/strong"&gt;https://quilljs.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：12k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;npm: npm install quill
CDNs:
&amp;lt;!-- Main Quill library --&amp;gt;
&amp;lt;script src=&amp;quot;//cdn.quilljs.com/1.0.0/quill.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&amp;quot;//cdn.quilljs.com/1.0.0/quill.min.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;!-- Theme included stylesheets --&amp;gt;
&amp;lt;link href=&amp;quot;//cdn.quilljs.com/1.0.0/quill.snow.css&amp;quot; rel=&amp;quot;stylesheet&amp;quot;&amp;gt;
&amp;lt;link href=&amp;quot;//cdn.quilljs.com/1.0.0/quill.bubble.css&amp;quot; rel=&amp;quot;stylesheet&amp;quot;&amp;gt;

&amp;lt;!-- Core build with no theme, formatting, non-essential modules --&amp;gt;
&amp;lt;link href=&amp;quot;//cdn.quilljs.com/1.0.0/quill.core.css&amp;quot; rel=&amp;quot;stylesheet&amp;quot;&amp;gt;
&amp;lt;script src=&amp;quot;//cdn.quilljs.com/1.0.0/quill.core.js&amp;quot; type=&amp;quot;text/javascript&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：需求不同，大小不同&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　　Quill 的建立是为了解决现有的所见即所得（WYSIWYG）的编辑器本身就是所见即所得（指不能再扩张）的问题。如果编辑器不正是你想要的方式，这是很难或不可能对其进行自定义以满足您的需求。&lt;/p&gt;
 &lt;p&gt;　　Quill 旨在通过把自身组织成模块，并提供了强大的 API 来构建额外的模块来解决这个问题。它也并没有规定你用样式来定义编辑器皮肤。Quill 还提供了所有你希望富文本编辑器说用于的功能，包括轻量级封装，众多的格式化选项，以及广泛的跨平台支持。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="https://quilljs.com/"&gt;https://quilljs.com/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997820" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;basket.js – 基于 LocalStorage 的资源加载器&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/addyosmani/basket.js/strong"&gt;https://github.com/addyosmani...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="https://addyosmani.com/basket.js//strong"&gt;https://addyosmani.com/basket...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：2k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;Bower: bower install basket.js --save
npm: npm install basket.js&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：4 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　basket.js是一款基于 LocalStorage 的资源加载器，可以用来缓存 script 和 css, 手机端使用速度快于浏览器直接缓存。  &lt;br /&gt;　  &lt;br /&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="https://addyosmani.com/basket.js/"&gt;https://addyosmani.com/basket...&lt;/a&gt;  &lt;br /&gt;更多示例请查看官方文档&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;scrollReveal.js – 使元素以非常酷帅的方式进入画布 (Viewpoint)&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/jlmakes/scrollreveal/strong"&gt;https://github.com/jlmakes/sc...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="https://scrollrevealjs.org//strong"&gt;https://scrollrevealjs.org/https://github.com/moment/mom...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://momentjs.com//strong"&gt;http://momentjs.com/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：30k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;bower install moment --save # bower
npm install moment --save   # npm
yarn add moment             # Yarn
Install-Package Moment.js   # NuGet
spm install moment --save   # spm
meteor add momentjs:moment  # meteor&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：16.6 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　 moment.js是一个轻量级的JavaScript库日期解析、验证操作,格式化日期的库。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://momentjs.com/"&gt;http://momentjs.com/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;这是一个GIF动图，不信，你看第一行的日期，时间在走。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997821" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;infinite-scroll – 一款滚动加载按需加载的轻量级插件&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;github：   &lt;a href="https://github.com/infinite-scroll/infinite-scroll/strong"&gt;https://github.com/infinite-s...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;官方网站：   &lt;a href="http://www.infinite-scroll.com//strong"&gt;http://www.infinite-scroll.co...&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;star：4k+&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Install：&lt;/strong&gt;&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;github自行下载&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;strong&gt;大小：20 KB&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;功能介绍：&lt;/strong&gt;  &lt;br /&gt;　infinite-scroll是一款滚动加载，滚动到最下到自动加载的轻量级JavaScript插件，简单实用，按需加载提高用户体验，非常适合移动端使用，配合上面的图片懒加载如虎添翼。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo：&lt;/strong&gt;  &lt;br /&gt;效果预览地址：  &lt;a href="http://www.dazeddigital.com/"&gt;http://www.dazeddigital.com/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Demo效果预览：&lt;/strong&gt;  &lt;br /&gt;图片有点大，稍等片刻。建议上面Demo效果预览地址进行预览。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997822" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;   &lt;/p&gt;
 &lt;h2&gt;欢迎大家按照格式补充，持续更新，有什么好用的轮子赶紧滚起来吧！&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;推荐有福利，送1024论坛邀请码，嘿嘿嘿。&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997823" title=""&gt;&lt;/img&gt;  &lt;br /&gt;  &lt;img alt="" src="https://segmentfault.com/img/remote/1460000008997824" title=""&gt;&lt;/img&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>javascript html5 github html</category>
      <guid isPermaLink="true">https://itindex.net/detail/56842-%E5%B7%A5%E4%BD%9C-github-%E8%BD%BB%E9%87%8F%E7%BA%A7</guid>
      <pubDate>Sun, 09 Apr 2017 11:09:41 CST</pubDate>
    </item>
    <item>
      <title>如何做一个让人闻风丧胆的 H5</title>
      <link>https://itindex.net/detail/54399-h5</link>
      <description>&lt;h2&gt;前言&lt;/h2&gt;
 &lt;p&gt;最近火热的有声娱乐平台 APP，企鹅 FM，在8月28日鬼节前夕，联合《盗墓笔记》推出了“勇敢者的游戏”活动。作为一个 UI 工程师，在这个移动互联网叱咤风云的时代，每次看到朋友圈中被分享的各种花样 H5 页面，总是心痒难耐，也想做有着酷炫动画和带感声效的 H5 呢。回想到做鬼节活动页的时候，接近午夜零点还在调整页面效果，看着页面上渐隐渐现的可怕画面，活生生吓到了自己，也是蛮难忘的。作为刚刚来到活动页新手村的朋友，踩到了一些坑，所以让我进入正题吧。哦，等一下，请先扫一下二维码啦~&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://qzs.qq.com/qzone/mall/app/meteor/act/index.html?sid=&amp;rid=796" target="_blank"&gt;   &lt;img alt="sf-qr" height="171" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150909105720493.jpg" width="171"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;h2&gt;&lt;/h2&gt;
 &lt;h2&gt;与设计师的沟通&lt;/h2&gt;
 &lt;p&gt;在拿到视觉稿和需求单之后，我们需要了解整个活动的流程。有的时候，设计师并不会把每个页面的动画效果做成视频，而是用口述的方式和工程师进行沟通。这样就需要工程师结合活动页流程和设计稿之后，自己先构思一些动效再去同产品以及设计沟通，这样交流的效率才会比较高。&lt;/p&gt;
 &lt;p&gt;动画新手有的时候会天马行空想到一些奇怪的效果，可能会不符合整体设计风格，可能会违反现实物理规律，有自己的想法，还要和产品设计确认。比如这个页面：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203623223.gif" target="_blank"&gt;   &lt;img alt="share-guide" height="733" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203623223.gif" width="414"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;一开始是做成了先出现手电筒，再出现光，在我的设想中刚开始手电筒上不会有那层黄绿色的光。后来经设计师提醒：如果完全没有光源，也应该看不到手电筒。才改成了现在的方案：灯光闪两下：物理定律什么的，我才记不清了呢T T。&lt;/p&gt;
 &lt;p&gt;P.S. 做动画的时候铭记  &lt;a href="http://isux.tencent.com/20122.html" target="_blank"&gt;动效原则&lt;/a&gt;，基本上动画的效果不会跑偏。&lt;/p&gt;
 &lt;h2&gt;具体实现&lt;/h2&gt;
 &lt;p&gt;仔细想想，这个活动页面并没有用到什么高深技巧，基本上是用 position 定位和 CSS3 动画完成的。不过在写页面之前，还是有不少担心的：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;页面兼容怎么做   &lt;br /&gt;
    &lt;br /&gt;
按照 iPhone6 的尺寸确定元素的位置，然后用    &lt;code&gt;zoom&lt;/code&gt; 或者    &lt;code&gt;transform: scale(x)&lt;/code&gt; 拉伸页面或者拉伸元素。在实际开发的时候，我一度对这两个属性的用法产生混淆，所以作些了研究，稍后会详细说说这两个属性。&lt;/li&gt;
  &lt;li&gt;3D 变化效果怎么实现   &lt;br /&gt;
    &lt;br /&gt;
大家应该早就听说过或者使用过    &lt;code&gt;perspective&lt;/code&gt; 和    &lt;code&gt;perspective-origin&lt;/code&gt; 这两个属性了，虽然教程和分享都看过不少，但真正写起来还是有一些摸不着头脑，各种搜索关于 3D 动画的解释之后我认为原理大概是这样的：   &lt;p&gt;&lt;/p&gt;
   &lt;p&gt;    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203646637.jpg" target="_blank"&gt;     &lt;img alt="perspective" height="411" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203646637.jpg" width="505"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
   &lt;p&gt;简单粗暴地说，请想象你是站在上图中的红点位置，你与物体间的距离是 perspective，眼睛的位置是 perspective-origin。好了，现在站定位置，去看这个物体，想象物体投影在某个平面上的效果（这里的平面就是我们的显示屏），这就是 3D 投影的结果。&lt;/p&gt;
   &lt;p&gt;关于     &lt;code&gt;perspective-origin&lt;/code&gt;，可以看看这个    &lt;a href="https://css-tricks.com/almanac/properties/p/perspective-origin/" target="_blank"&gt;demo&lt;/a&gt;。    &lt;br /&gt;
说了这么多，在实际运用中，我还是找了一个    &lt;a href="http://css3gen.com/css-3d-transform/" target="_blank"&gt;生成器&lt;/a&gt;。    &lt;br /&gt;
得到的效果大概是这样的：&lt;/p&gt;
   &lt;p&gt;    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203743175.gif" target="_blank"&gt;     &lt;img alt="share" height="664" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203743175.gif" width="372"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
   &lt;p&gt;    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203748317.gif" target="_blank"&gt;     &lt;img alt="cast-rotaion" height="216" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203748317.gif" width="414"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
   &lt;p&gt;想要重点说一下磁带的实现，主要牵涉到的图片资源是下面这几个：    &lt;br /&gt;
    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203932592.png" target="_blank"&gt;     &lt;img alt="cast-small" height="78" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203932592.png" width="78"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;br /&gt;
    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203913265.png" target="_blank"&gt;     &lt;img alt="cast-wrapper" height="117" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203913265.png" width="331"&gt;&lt;/img&gt;&lt;/a&gt;    &lt;br /&gt;
    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203940892.png" target="_blank"&gt;     &lt;img alt="cast-inner-bus" height="161" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908203940892.png" width="291"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
   &lt;p&gt;磁带被分成了3个部分，磁带底部，磁带封面和磁带。其中封面和磁带是正视图，需要使用 3D 旋转，让这两个元素“躺下去”，而且为了保证这三个元素之间不会因为屏幕的缩放，出现错位的问题，需要保证磁带封面和磁带的定位是基于磁带底部的。其实磁带上还有两片盖子，不知道大家有没有注意到。其实这个盖子是左右对称且中心对称的，所以完全可以只用一张图片完成这样的效果，用     &lt;code&gt;transform: scale(-1, 1);&lt;/code&gt; 和     &lt;code&gt;transform: scale(1, -1);&lt;/code&gt; 实现。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;动画如何才有代入感
   &lt;p&gt;    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/2015090820421232.gif" target="_blank"&gt;     &lt;img alt="share" height="664" src="http://isux.tencent.com/wp-content/uploads/2015/09/2015090820421232.gif" width="372"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
   &lt;p&gt;这个活动页面我个人最喜欢的地方就是星星砸下去的动画，感觉所有的戏份都在它身上。开始的设想只是星星砸下去，感谢在制作过程中，经验丰富的同事所提的建议：星星砸下去的时候要有灰尘溅起或者火星四溅的效果。后来和设计商量，最后用了灰尘溅起的效果。不过本来还想做，星星背后的铁板应该要有震动的效果。由于时间关系，震动的效果有点不好添加，所以放弃了，这一点感觉有一些遗憾。可能页面新手的经验不够，很多动画的效果因为有限的想象力所以不太完善。这个时候和身边经验丰富的同事请教是很有效的方法。同时，一定要多看 B 站拓宽视野才行哦。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;h2&gt;&lt;/h2&gt;
 &lt;h2&gt;踩到了一些坑&lt;/h2&gt;
 &lt;p&gt;页面布局并不复杂。前文也提到，基本上使用 position: absolute; 来实现的，不过遇到了一些问题就有了以下总结：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;杀鸡就不要用牛刀，能又快又好解决问题才最重要
   &lt;p&gt;    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204237638.gif" target="_blank"&gt;     &lt;img alt="index-header" height="141" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204237638.gif" width="372"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
   &lt;p&gt;上图是首页的截图，页面加载之后应该可以看到“胆量测试”下面的蓝色线条有一个动画。&lt;/p&gt;
   &lt;p&gt;故事是这样的，自从 SVG 帝王小啪带着神器     &lt;a href="https://github.com/janily/svgartisan" target="_blank"&gt;svgartisan&lt;/a&gt; 降临（对 SVG 有兴趣的同学欢迎加群 426886128 一同讨论 SVG 技术），做页面的时候总想加上一点 SVG。然而这个蓝色线条上有特效，所以用 PS 导出 SVG 后还要做二次处理才能还原设计稿上的效果，而且 SVG 的代码你懂得，它总是有点长。其实有个简单粗暴的方法：改变蓝色线条的图片宽度，虽然这个方法从性能上看并不好，但考虑到这个页面也只有这里发生了重绘，所以还是用图片+宽度控制来实现了。&lt;/p&gt;
   &lt;p&gt;不知道大家会不会为了某一种技术而去做某一件事情，但其实完成那件事情才是真正的目的，却因为那个技术而耽误了不少进度，这样就有点进入了炫技的误区。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;答应我，伪元素上就不要做动画了   &lt;br /&gt;
伪元素真的是神一样的存在，一个标签自带两个儿子，不知道为什么就有种金闪闪的感觉。但是伪元素上的动画真的很坑，年少无知，页面都写完了，发现在 iOS 上美如画的动画效果，到了小米和魅族上就……总之看到屏幕那一刻我是这样的：   &lt;p&gt;&lt;/p&gt;
   &lt;p&gt;    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204313587.jpg" target="_blank"&gt;     &lt;img alt="sad" height="48" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204313587.jpg" width="79"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
   &lt;p&gt;Android 上坑多，不要一次应用太多新技术。比如在魅族上用 flexbox 布局，就要加上 display: -webkit-box。还有一个教训就是，页面果然应该做一个测试一个啊QAQ。因为这个项目是重构和前端并行开发的……把伪元素改成实际 DOM 元素的时候，是怀着一颗对不起前台的心的。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;请写好注释
   &lt;p&gt;    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204417499.jpg" target="_blank"&gt;     &lt;img alt="comment" height="308" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204417499-590x308.jpg" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
   &lt;p&gt;与UI工程师对接的前台同学需要看注释才知道什么时候要加什么class，想到刚刚开始接需求的时候，从来不写注释…真是对不起前台同学T T现在我个人的注释如上图所示。也看过组里不同同事的注释风格，大同小异，主体思想就是“在XX时候添加XX class”这样，和对接的同学约定好就可以~&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;h2&gt;zoom 和 transform: scale(x); 的使用&lt;/h2&gt;
 &lt;p&gt;我将会在接下来详细谈到前文提到的 zoom 和 transform: scale(x); 问题。&lt;/p&gt;
 &lt;h3&gt;  &lt;a href="http://isux.tencent.com#_5" name="user-content-_5" target="_blank"&gt;&lt;/a&gt;为什么要使用缩放&lt;/h3&gt;
 &lt;p&gt;现在不管是活动页的设计稿还是产品页的设计稿，逐渐以 375×667 的 iPhone6 为基础。但是实际生活里，这些页面是会出现在细细长长的 iPhone5、480px 高度的 iPhone4 还有大屏幕的 iPhone 6+，更不要说在三星小米魅族一加等等等等尺寸都不知道怎么办才好的 Android 系列上打开会是什么gui。&lt;/p&gt;
 &lt;p&gt;拿这次的活动页面设计稿来说，与用户产生交互的按钮在页面篇底部的位置。有一个前提，为了兼容不同宽度的屏幕，所以页面是基于 iPhone 6 的 375px 用 zoom 属性进行缩放，可以看出iPhone 5 和 iPhone 4 的宽度一样，而且看设计稿，页面元素是从上到下分布的：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="design-screenshot" height="882" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204509956.jpg" width="502"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;也就是说，使用相同的 zoom 值，满足了 iPhone5 的页面效果，但是在 iPhone4 上，按钮就会偏底，页面整体感觉也偏底。但是 zoom 值不能随便更改，否则红框中的录音机图片的左右边界就会显示出来。所以要针对 iPhone 4 调整元素的之间的间距，最终的效果大概是这样的：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204509956.jpg" target="_blank"&gt;   &lt;img alt="ip4-effect" height="497" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204451183.jpg" width="334"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;可以看得出效果并不是很好，整个页面非常的拥挤，所以在这个情况下，我觉得用统一 zoom 值来调整有点一棍子打倒了，如果一个个元素微调，那么最好效果会好得多。加上 zoom 会有一定的性能问题，组里的同事有些是 zoom 调整，也有给每个元素加 class 通过 transform: scale() 调整的。重构最神奇的就是，条条大路通罗马，怎么样都能达到自己想要的视觉效果，但是中间会因为各种原因，实现的方式不太一样。&lt;/p&gt;
 &lt;p&gt;拿到设计稿一开始就先看看这个设计稿的布局，有一些是从页面顶部到底部都有效果的，这个时候就要考虑在 iPhone4 这样屏幕不够高的设备上如何保证页面完整呈现；或者在不影响交互的情况下，隐藏哪些元素。有的时候页面上元素比较集中，这个时候就要考虑在 iPhone6+ 这样的大屏幕设备上，要不要调整间距使得页面不会太空旷。&lt;/p&gt;
 &lt;p&gt;要知晓设计稿背后的含义，不是一拿到就开始做了，有些元素其实是要整体考虑的。有些乍一看好像是用 position 定位，分别写 top 值就好。殊不知，设计师真正要表达的是，作为一个整体，它们在页面上要绝对居中。没有 get 到这个 point，兼容的时候就要哭了。&lt;/p&gt;
 &lt;h3&gt;  &lt;a href="http://isux.tencent.com#zoom-transformscale" name="user-content-zoom-transformscale" target="_blank"&gt;&lt;/a&gt;zoom 和 transform:scale 的概念&lt;/h3&gt;
 &lt;p&gt;先来看一下   &lt;code&gt;zoom&lt;/code&gt; 和   &lt;code&gt;transform:scale&lt;/code&gt; 的说明：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;Specifies the initial zoom factor for the window or viewing area. This is a magnifying glass type of zoom. Interactively changing the zoom factor from the initial zoom factor does not affect the size of the initial or the actual viewport.&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;从定义上看 zoom 缩放的是被 zoom 的容器的视口，可以把它想象成放大镜的效果，这个属性是可被继承的，所以我们做设备屏幕兼容的时候，可以在 body 标签下加一个 div 包裹住页面上的其他元素，然后在这个 div 上加 zoom，达到的视觉效果就是页面上其他元素也被缩放了。但是有些元素并不支持 zoom。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;A two-dimensional transformation is applied to the coordinate system an element renders in through the ‘transform’ property. This property contains a list of transform functions. The final transformation value for a coordinate system is obtained by converting each function in the list to its corresponding matrix (either defined in this specification or by reference to the SVG specification), then multiplying the matrices.&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;在说 scale 应该要先看看 transform。transform 属性应用到元素的过程其实是矩阵变换的过程，在渲染的时候，元素的坐标就会被确定下来，然后和 transform 的属性值进行矩阵运算得到最终的坐标，不过你会发现，一个绝对定位的元素通过 transform 改变显示位置后，这个元素的 tbrl 值并不会被更新，且 transform 属性不可继承的。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;The value of the transform property is a list of applied in the order provided. … specifies a scale operation using the [sx,1] scaling vector, where sx is given as the parameter. … specifies a scale operation using the [1,sy] scaling vector, where sy is given as the parameter.&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;scale 是 transform 的一个属性值，这是一个缩放矩阵。当一个元素被定义了 transfrom: scale(x); 后，还是再结合它的 transfrom-origin，才能确定最后的缩放效果。依然是兼容屏幕分辨率的问题，要想 transfrom: scale(x) 达到和 zoom 相似的效果，要记得把 transfrom-origin 设置成 0 0。这么设置的原因是，在文档流中的元素，是以它的左上角为中心进行 zoom 的，而当元素脱离文档流时，要使 transform: scale(x) 和 zoom 达到相同的效果，还要具体分析 transform-origin 要如何设置。&lt;/p&gt;
 &lt;p&gt;大概你也注意到了，在前一句中，我说的是“相似的效果”而不用“一样的效果”，这是因为使用 scale 的时候可能遇到下面这样的问题。下图中左边为 transform:scale(.85)，右边为 zoom: .85：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204536628.jpg" target="_blank"&gt;   &lt;img alt="scale-zoom-ip4" height="415" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204536628-590x415.jpg" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;下面这段是外层容器的样式，背景是定义在 switch-wh 动画中，通过绝对定位让浏览器自行计算，保证容器大小占满整个屏幕：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150909104252887.jpg" target="_blank"&gt;   &lt;img alt="code-sf-index" height="227" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150909104252887-590x227.jpg" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;因为 zoom 是作用在 body 下面这个占满了屏幕空间的容器，所以根据定义以及 zoom 的继承性，我们可以说在这个页面上使用 zoom 其实是缩放了整个屏幕（也就是视口），可以想象成在浏览器中打开了页面，然后放大这个页面的效果：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150909102346606.jpg" target="_blank"&gt;   &lt;img alt="browser-zoom" height="183" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150909102346606-590x183.jpg" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;为什么 scale 会留下右部和底部的迷の白色呢？让我们回到 transform 的定义中，“applied to the coordinate system an element renders in through the ‘transform’ property”。当元素都进行渲染了，坐标已经确定了，再进行缩放，也就是在原来元素基础上改变大小。所以 .sf-index 虽然在渲染时四个角的位置分别是(0,0)、(100%,0)、(0,100%)、(100%, 100%)，经过以 (0,0) 为变换中心的 scale，就变成了(0,0)、(85%,0)、(0,85%)、(85%,85%)。我们就会看到页面右边出现宽度为15%的一条白边，以及页面下方高度为15%的白边。&lt;/p&gt;
 &lt;h3&gt;  &lt;a href="http://isux.tencent.com#zoom" name="user-content-zoom" target="_blank"&gt;&lt;/a&gt;好像 zoom 无敌了呢&lt;/h3&gt;
 &lt;p&gt;看起来，好像兼容的时候应该用 zoom 呢。嗯看到 scale 之后的结果我就是这么想的。接着就发现 zoom 之后的页面，文字的显示不太正常。下图左边是被 zoom 的 iPhone4，右边是没有被 zoom 的 iPhone6：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204632164.jpg" target="_blank"&gt;   &lt;img alt="zoom-prob" height="384" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204632164-590x384.jpg" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;由于页面是被整体缩放了，所以文字也自然出现了缩放，刚好这种好像被砍了一刀的文字效果还蛮适合鬼节的活动页面，所以我并没有做处理。正常来说，如果需要做处理就是调整文字的 line-height 和容器的 height，使其不出现遮挡。&lt;/p&gt;
 &lt;p&gt;正如页面元素经过 zoom 后，实际的大小会发生改变，图片的大小也发生了改变，使用雪碧图就出现了一些问题。雪碧图是把各种小图拼合到一张大图上面，通过 width、height 和 background-position 定位到图片，看下图可以发现相邻图片的边界也一起显示出来了。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204649651.png" target="_blank"&gt;   &lt;img alt="float-px1" height="134" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204649651.png" width="267"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;审查元素发现，用于显示图片的元素尺寸也不对啊：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204708143.png" target="_blank"&gt;   &lt;img alt="float-px2" height="270" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150908204708143-590x270.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;可以看出这个元素正确的尺寸应该是 198×52，经过 zoom: 1.10 放大后容器反而变小了，后来将 zoom 值调整到 1.104（414/375），图片的边界问题算是解决了。&lt;/p&gt;
 &lt;p&gt;关于图片没有正常显示的问题，我的推断是，原因在于 zoom 值设定偏小，图片经过 zoom 后没有被正确地计算，而图片的容器又偏大，所以相邻图片的边就被显示了出来。后来 zoom 值是根据比例设定了，就不会出现这个问题。&lt;/p&gt;
 &lt;p&gt;最后，zoom 对性能不友好，下面两个 gif 分别是 zoom 和 transform: scale 引起的重绘：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/2015090820473231.gif" target="_blank"&gt;   &lt;img alt="zoom-repaint" height="535" src="http://isux.tencent.com/wp-content/uploads/2015/09/2015090820473231.gif" width="317"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/2015090820474399.gif" target="_blank"&gt;   &lt;img alt="scale-repaint" height="535" src="http://isux.tencent.com/wp-content/uploads/2015/09/2015090820474399.gif" width="317"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;很明显，在文档流中 zoom 加在任意一个元素上都会引起  &lt;strong&gt;整个页面&lt;/strong&gt;的重新渲染，而 transform: scale 只是在当前的元素上重绘。&lt;/p&gt;
 &lt;h3&gt;  &lt;a href="http://isux.tencent.com#_6" name="user-content-_6" target="_blank"&gt;&lt;/a&gt;还有没有更好的兼容方法呢&lt;/h3&gt;
 &lt;p&gt;这样说来，简直两个方法都不能用了嘛…还有没有什么别的兼容的方法呢？  &lt;br /&gt;
有的。  &lt;br /&gt;
像需要大量图片的页面，做兼容的时候我们常常担心的是什么？当然是图片比例出问题咯，所以也会使用通过伪元素设置 padding-top 的方法，保证图片比例正常地显示出来。只是这样的写法通常要结合 background-size:cover; 而我们常用的工具 CssGaga 在生成雪碧图了之后会覆盖 background-size。目前的这个方案的话……就不合成雪碧图了。&lt;/p&gt;
 &lt;p&gt;还有一个方案是使用   &lt;code&gt;media query&lt;/code&gt; 结合 rem （或百分比）完成这样的布局，不过目前 gaga 不支持 background-size 的 rem，所以要采用什么方式合成雪碧图以及如何生成新的样式，还需要寻找新的方向。在不需要合成雪碧图的时候，可以用这两种方法。&lt;/p&gt;
 &lt;h2&gt;  &lt;a href="http://isux.tencent.com#_7" name="user-content-_7" target="_blank"&gt;&lt;/a&gt;工具/网站推荐&lt;/h2&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;a href="http://mydevice.io/" target="_blank"&gt;查看设备的屏幕参数&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://cssanimate.com/" target="_blank"&gt;设计keyframes&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;动画灵感哪里找：   &lt;a href="http://codepen.io/" target="_blank"&gt;http://codepen.io/&lt;/a&gt;，   &lt;a href="https://dribbble.com/" target="_blank"&gt;https://dribbble.com/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;无聊时候陪着你的企鹅 FM 退出《鬼吹灯》大结局啦，无聊时候陪着你的企鹅 FM 退出《鬼吹灯》大结局啦，无聊时候陪着你的企鹅 FM 退出《鬼吹灯》大结局啦。听完盗墓听鬼吹灯，根本停不下来！&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/09/20150909120416941.jpg" target="_blank"&gt;   &lt;img alt="20150618123855_polrJ7oZHM" height="184" src="http://isux.tencent.com/wp-content/uploads/2015/09/20150909120416941-590x184.jpg" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>前端技术 html5 动画</category>
      <guid isPermaLink="true">https://itindex.net/detail/54399-h5</guid>
      <pubDate>Wed, 23 Sep 2015 19:32:55 CST</pubDate>
    </item>
    <item>
      <title>顺势而为，HTML发展与UI组件设计进化</title>
      <link>https://itindex.net/detail/55103-html-%E5%8F%91%E5%B1%95-ui</link>
      <description>&lt;p&gt;在阅读本文之前，建议先阅读之前的一篇文章：“  &lt;a href="http://isux.tencent.com/half-package-web-components-for-design.html" target="_blank"&gt;面向设计的半封装web组件开发&lt;/a&gt;”，便于理解文章的一些解惑。&lt;/p&gt;
 &lt;h3&gt;一、现状&lt;/h3&gt;
 &lt;p&gt;  &lt;strong&gt;1. 前端发展现状&lt;/strong&gt;  &lt;br /&gt;
前端这几年的发展都是有目共睹的，然而，如果按照已经落地投入实践的标准梳理下，会发现，基本上都是偏后的JS开发层面的，比方说Node.js下的前后端分离，MV*库，React.js，各种包管理工具及前端集成解决方案等。&lt;/p&gt;
 &lt;p&gt;而往前，Shadow DOM, Web Components规范和标准虽然也出现了，给大家看到了方向和未来，但由于兼容性的问题（参见下表），或者可能缺乏优秀团队的强势引领，我们在实际的项目中鲜有看到。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt;
 &lt;p&gt;就算有  &lt;a href="https://github.com/WebComponents/webcomponentsjs" target="_blank"&gt;webcomponents.js&lt;/a&gt;这样的polyfills处理，也只有IE11+才完全支持。&lt;/p&gt;
 &lt;p&gt;难道我们就这样干等着，直到Web Components一统江山的时候，我们才开始在HTML侧发力吗？这么多年HTML5的发展就这么白费了？我们做PC端的就因为一些过时的浏览器而止步不前？&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;2. UI组件现状&lt;/strong&gt;  &lt;br /&gt;
成熟的团队都有自己的一套组件库，以便各种项目来的时候，都能从容应对。&lt;/p&gt;
 &lt;p&gt;为了能够从容应对，我们必然要考虑周全，企业级，能应对大型项目，各种复杂场景，充分发挥组件的复用性。往往最终，会让组件变得比较重，逻辑比较复杂，API数量也比较多。我们不妨可以看下kissy 5.0的DatePicker的组件使用示意：  &lt;br /&gt;
  &lt;img alt="kissy Datepicker&amp;#32452;&amp;#20214;&amp;#20351;&amp;#29992;" height="615" src="http://isux.tencent.com/wp-content/uploads/2015/12/20160113172239951.png" width="588"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;如果我们单看功能，确实很强大，禁用日期可以任意自定义，可以轻松定义各个操作栏是否显示，确实是企业级的web组件，看上去能适应各种复杂场景。&lt;/p&gt;
 &lt;p&gt;但是，在我看来，问题却非常多。&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;诸位静下心来想想看，我们所经历的项目，是不是绝大多数都不复杂，我们是否有必要使用企业级的大而重的产品？就好比你一个展示性为主的网站，却使用AngularJS MVVM来高大上。截趾适屦，敦云其愚。&lt;/li&gt;
  &lt;li&gt;看上去能适应各种场景，但是，眼下现代web技术飞速发展，UI层变化日新月异，你确定你这个组件能跟得上这些变化。怕是最后演变成，组件支持跟不上，而否决了设计师的一些想法。本末倒置了！&lt;/li&gt;
  &lt;li&gt;代码中出现了   &lt;code&gt;GregorianCalendar&lt;/code&gt;,    &lt;code&gt;GregorianCalendarFormat&lt;/code&gt;这样的方法或对象，请问在座的各位你知道这是个什么鬼吗？你知道他是干嘛用的吗？学习成本啊~~&lt;/li&gt;
  &lt;li&gt;   &lt;code&gt;render&lt;/code&gt;,    &lt;code&gt;showWeekNumber&lt;/code&gt;,    &lt;code&gt;showClear&lt;/code&gt;,    &lt;code&gt;showToday&lt;/code&gt;,    &lt;code&gt;disabledDate&lt;/code&gt;这些API名称大家有没有觉得在哪里见过？   &lt;br /&gt;
“好像是在哪儿见过？”   &lt;br /&gt;
“好像个鬼啊，是之前根本就没见过！”   &lt;br /&gt;
现在大家闭上眼睛，还记不记得这些API名称是什么？假设一周以后呢，你还记不记得。是不是你要去翻API文档了？使用成本啊~&lt;/li&gt;
  &lt;li&gt;想象这样的场景，项目启动了，负责组件的前端和负责业务的前端一起开工，谁知突然，负责组件的前端的老婆突然要临盆，不得不去陪产。此时负责业务的前端该怎么搞？会不会像这样一样在心中马景涛：“时间选择组件还没完成，这里的日期交互依赖组件，这不是丢锅给我接吗！？”可以看到，两人的开发被牵制了！两种结果，一是自己上，二是这块工作暂停。   &lt;br /&gt;
所以大家发现没，组件和业务耦合在一起，不利于协作啊。比方说上面截图代码的   &lt;code&gt;picker.on(&amp;apos;select&amp;apos;, function(e) {});&lt;/code&gt;，组件不弄好，根本就没法使用啊！要么就自己先搞搞，回头再改，都是很烦的。&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;二、探索&lt;/h3&gt;
 &lt;p&gt;正是由于当下有这些不如意的现状，所以我就一直在思考，有没有什么办法可以做出改变，不一定是大跨越式的一步到位，至少能指明柳暗花明的另一条路。&lt;/p&gt;
 &lt;p&gt;我们还是拿时间选择器举例，想想看，HTML5有没有为我们带来  &lt;code&gt;native&lt;/code&gt;的UI组件？对吧，有的，应该都知道的：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;date&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;code&gt;date&lt;/code&gt;类型的  &lt;code&gt;input&lt;/code&gt;输入框，天然可以选择时间。  &lt;br /&gt;
  &lt;img alt="&amp;#21407;&amp;#29983;&amp;#26102;&amp;#38388;&amp;#36873;&amp;#25321;" height="251" src="http://isux.tencent.com/wp-content/uploads/2015/12/20160113181504658.png" width="279"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;我们可以使用  &lt;code&gt;min&lt;/code&gt;/  &lt;code&gt;max&lt;/code&gt;属性限制可以选择的时间范围，使用  &lt;code&gt;value&lt;/code&gt;确定当前选择日期。也就是说，从原始功能角度而言，原生的  &lt;code&gt;date&lt;/code&gt;时间选择可以满足绝大多数的业务需求。&lt;/p&gt;
 &lt;p&gt;这些符合标准，业界规范的HTML特性要是可以直接在实际项目中应用该多好啊！&lt;/p&gt;
 &lt;p&gt;然而，问题在于，浏览器原生的界面往往跟我们站点的设计风格有些不协调，说白了，就是设计师觉得丑，而且不能自由定义某些功能，例如清除。&lt;/p&gt;
 &lt;p&gt;还有一个很现实的问题是兼容性，包括IE11在内的IE浏览器都没有  &lt;code&gt;type=&amp;quot;date&amp;quot;&lt;/code&gt;组件行为，  &lt;img align="absmiddle" alt="" src="http://mat1.gtimg.com/www/mb/images/face/36.gif"&gt;&lt;/img&gt; 这个补刀直接剐在了心头。&lt;/p&gt;
 &lt;p&gt;怎么办呢？&lt;/p&gt;
 &lt;p&gt;我们此时不妨梳理下：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;date&amp;quot; min=&amp;quot;2016-01-01&amp;quot; max=&amp;quot;2016-12-31&amp;quot; value=&amp;quot;2016-02-14&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;  &lt;code&gt;type&lt;/code&gt;/  &lt;code&gt;min&lt;/code&gt;/  &lt;code&gt;max&lt;/code&gt;/  &lt;code&gt;value&lt;/code&gt;这些原生标准的HTML属性并没有问题，有问题的只是点击出现的那个长相简陋的选择浮层。所谓对症下药，哪个有问题就搞哪个，我们只要想办法把丑陋的浮层搞漂亮就可以了。&lt;/p&gt;
 &lt;p&gt;考虑到兼容性，我们其实可以和传统的时间选择器组件一样，对浮层内容进行自定义，注意，我们仅自定义浮层，HTML还是原始的。&lt;/p&gt;
 &lt;p&gt;我们构建一个名叫  &lt;code&gt;DateTime&lt;/code&gt;的实例方法，理想状况下，我们只要绑定初始化一下，类似这样：&lt;/p&gt;
 &lt;pre&gt;new DateTime($(&amp;quot;[type=date]&amp;quot;);&lt;/pre&gt;
 &lt;p&gt;然后duang，时间选择器浮层直接美化成设计师需要的模样，那该多完美啊！&lt;/p&gt;
 &lt;p&gt;梦想总是有的，万一实现了呢？&lt;/p&gt;
 &lt;p&gt;既然使用自定义的浮层，那就需要干掉浏览器原生的浮层，怎么弄呢？我们可以让  &lt;code&gt;input&lt;/code&gt;框  &lt;code&gt;readonly&lt;/code&gt;只读，这样，就不会出现原始的输入框了。&lt;/p&gt;
 &lt;p&gt;那  &lt;code&gt;input&lt;/code&gt;框内置的三角(需要隐藏)和斜杠(需要使用短横)该怎么办呢？ 这部分是支持自定义的，类似：&lt;/p&gt;
 &lt;pre&gt;::-webkit-clear-button,
::-webkit-inner-spin-button,
::-webkit-calendar-picker-indicator {
  display:none;
}
[type=&amp;quot;date&amp;quot;]::-webkit-datetime-edit-text {
  color: transparent;
}
[type=&amp;quot;date&amp;quot;]::-webkit-datetime-edit-text::before {
  content: &amp;apos;-&amp;apos;;
  position: absolute;
}
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-year-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-minute-field,
::-webkit-datetime-edit-ampm-field {
  background: none;
}&lt;/pre&gt;
 &lt;p&gt;就可以把webkit下的时间输入框改造成我们想要的样子了，而IE等不支持date输入框的浏览器，保持原来的样子就可以。&lt;/p&gt;
 &lt;p&gt;于是乎，通过CSS和JS的配合，我们就可以实现基于原生HTML5标准的时间选择器了。&lt;/p&gt;
 &lt;p&gt;“稍等，怎么就实现了？”有人可能会有这样的疑问。&lt;/p&gt;
 &lt;p&gt;下面这段是我年轻时候使用过的一套组件库的初始化示意：&lt;/p&gt;
 &lt;pre&gt;new DatePicker($(&amp;quot;#date&amp;quot;), {
  type: &amp;quot;date&amp;quot;,
  initDate: ..,
  beginDate: ..,
  endDate: ..,
  onSelected: $.noop
});&lt;/pre&gt;
 &lt;p&gt;对比：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;date&amp;quot; min=&amp;quot;2016-01-01&amp;quot; max=&amp;quot;2016-12-31&amp;quot; value=&amp;quot;2016-02-14&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;我们是不是可以找到之间的关系？没错，这位同学好生眼力，HTML中的  &lt;code&gt;type&lt;/code&gt;属性对应JS中的  &lt;code&gt;type&lt;/code&gt; API,   &lt;code&gt;value&lt;/code&gt;属性值对应  &lt;code&gt;initDate&lt;/code&gt;值,   &lt;code&gt;min&lt;/code&gt;/  &lt;code&gt;max&lt;/code&gt;分别对应  &lt;code&gt;beginDate&lt;/code&gt;/  &lt;code&gt;endDate&lt;/code&gt;。其实内部实现跟传统的组件没什么差别。&lt;/p&gt;
 &lt;p&gt;那  &lt;code&gt;onSelected&lt;/code&gt;呢？  &lt;code&gt;onSelected&lt;/code&gt;是个回调方法，解读下就是当选择日期之后，干嘛干嘛。其实我们原生的  &lt;code&gt;input&lt;/code&gt;框有类似的事件，什么呢？  &lt;code&gt;change&lt;/code&gt;事件。既然，我们这里使用的是原生的HTML输入框，那我们就可以使用其原生的  &lt;code&gt;change&lt;/code&gt;事件。所以，什么  &lt;code&gt;onSelected&lt;/code&gt;回调，完全不需要。我们只要在组件内部，当赋值的同时  &lt;code&gt;trigger&lt;/code&gt;下原生的  &lt;code&gt;change&lt;/code&gt;事件。&lt;/p&gt;
 &lt;p&gt;于是乎，我们就得到了一个HTML是原生，API也是原生，事件也是原生，UI自定义的时间选择控件。真真切切将HTML5应用到了实际项目中，同时，就算是是10年前的IE6也是可以兼容。&lt;/p&gt;
 &lt;p&gt;完美！&lt;/p&gt;
 &lt;p&gt;然而，一定会有小伙伴提出质疑，你这个功能也太局限了吧，如果遇到特殊需求，例如，所有的周末都不能选择，你怎么整？&lt;/p&gt;
 &lt;p&gt;OK，此时就需要“  &lt;a href="http://isux.tencent.com/half-package-web-components-for-design.html" target="_blank"&gt;面向设计的半封装web组件开发&lt;/a&gt;”的这篇文章出马了？&lt;/p&gt;
 &lt;p&gt;之所以有人会提出上面的质疑，还是按照了传统组件的思维方式去思考。没错，确实有些项目的时间组件要求周末不能选择。但是，你现在做的这个项目，有这个需求吗？你好好想想。&lt;/p&gt;
 &lt;p&gt;CSS3现在发展越来越成熟，UI层的变化越来越迅速和不可预知，这种趋势，要求我们的UI组件要轻快，灵活，随时可以根据上层变化做调整。而那种妄图考虑各种场景，代码又大又冗余的组件开发方式已经越来越不适应未来的潮流了。&lt;/p&gt;
 &lt;p&gt;如果你真的遇到“周末都不能选择”的需求，我告诉你怎么办？自定义一个名为”  &lt;code&gt;date-no-weekend&lt;/code&gt;“的  &lt;code&gt;type&lt;/code&gt;类型，内部的JS代码当然该重用的重用，该模块化的模块化：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;date-no-weekend&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;还是觉得难以接受，仔细品味后面这句话：组件要面向设计，落地项目，追求品质。&lt;/p&gt;
 &lt;p&gt;好，我们现在实现了基于HTML5时间选择组件落地实践生产，加以推广，势必对HTML5标准在国内的学习与普及带来帮助。&lt;/p&gt;
 &lt;p&gt;然而，就单单一个组件，势单力薄，怕是针落大海，激不起一点水花，其他些组件是不是也可以找这种面向HTML的思路去开发呢？&lt;/p&gt;
 &lt;p&gt;有！&lt;/p&gt;
 &lt;p&gt;告诉大家，QQ公众平台的UI组件体系贯穿始终，就是基于面向HTML标准开发的思想实现，同时借助面向设计的开发思想，让组件极致体验，同时轻便快捷，风一吹就可以飞到天上去。&lt;/p&gt;
 &lt;h3&gt;三、实践&lt;/h3&gt;
 &lt;p&gt;QQ公众平台的UI组件实现，和传统实现是完全不同的设计思想。从JS层进一步往下沉淀了一个层次，基于原生的HTML实现。&lt;/p&gt;
 &lt;p&gt;多说无益，眼见为实（狠击下面）。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151221162207754.html" target="_blank"&gt;   &lt;strong&gt;demo-点击这里-demo&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;点击上面的demo, 进入一个平凡的静态页面，引入眼帘的是一个普通的表单，里面的UI都是系统默认的，HTML功能也是原生的。&lt;/p&gt;
 &lt;div&gt;  &lt;strong&gt;例如：&lt;/strong&gt;&lt;/div&gt;
 &lt;ul&gt;
  &lt;li&gt;title提示   &lt;br /&gt;
   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151221150833418.png" target="_blank"&gt;    &lt;img alt="title&amp;#25552;&amp;#31034;" height="109" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151221150833418.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;选择日期   &lt;br /&gt;
   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151221151623905.png" target="_blank"&gt;    &lt;img alt="&amp;#36873;&amp;#25321;&amp;#26085;&amp;#26399;" height="225" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151221151623905.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;点击提交的表单验证   &lt;br /&gt;
   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151222142540703.png" target="_blank"&gt;    &lt;img alt="&amp;#34920;&amp;#21333;&amp;#39564;&amp;#35777;" height="556" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151222142540703.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;div&gt;UI虽然原始，但是功能却是很健全的。&lt;/div&gt;
 &lt;div&gt;  &lt;strong&gt;例如：&lt;/strong&gt;&lt;/div&gt;
 &lt;ul&gt;
  &lt;li&gt;男女款式、城市以及运费险对价格的影响   &lt;br /&gt;
   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151222142805210.png" target="_blank"&gt;    &lt;img alt="&amp;#20132;&amp;#20114;&amp;#19982;&amp;#26368;&amp;#32456;&amp;#20215;&amp;#26684;" height="403" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151222142805210.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;表单提交事件   &lt;br /&gt;
   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151221154020659.png" target="_blank"&gt;    &lt;img alt="&amp;#34920;&amp;#21333;&amp;#25552;&amp;#20132;" height="277" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151221154020659.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;div&gt;下面，见证奇迹的时刻到了，点击demo页面（下图所示）的按钮进行QQ公众平台UI组件资源的加载和初始化：&lt;/div&gt;
 &lt;p&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/2015122214303373.png" target="_blank"&gt;   &lt;img alt="&amp;#28857;&amp;#20987;&amp;#27979;&amp;#35797;&amp;#25353;&amp;#38062;&amp;#31034;&amp;#24847;" height="109" src="http://isux.tencent.com/wp-content/uploads/2015/12/2015122214303373.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;结果，一瞬间，上面原始粗糙的界面一下子变成了这样子：  &lt;br /&gt;
  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151221155007578.png" target="_blank"&gt;   &lt;img alt="&amp;#21152;&amp;#36733;CSS&amp;#36164;&amp;#28304;&amp;#21518;&amp;#30340;&amp;#27169;&amp;#26679;" height="727" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151221155007578.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;妥妥的丑小鸭变成了白天鹅，包括之前原生的HTML功能。&lt;/p&gt;
 &lt;div&gt;  &lt;strong&gt;例如：&lt;/strong&gt;&lt;/div&gt;
 &lt;ul&gt;
  &lt;li&gt;title提示   &lt;br /&gt;
   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151221161323875.png" target="_blank"&gt;    &lt;img alt="&amp;#24341;&amp;#20837;UI&amp;#32452;&amp;#20214;&amp;#21518;&amp;#30340;&amp;#25552;&amp;#31034;" height="98" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151221161323875.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;选择日期   &lt;br /&gt;
   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151221162536141.png" target="_blank"&gt;    &lt;img alt="&amp;#26085;&amp;#26399;&amp;#36873;&amp;#25321;&amp;#31034;&amp;#24847;" height="338" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151221162536141.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;点击提交的表单验证   &lt;br /&gt;
   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151221162606553.png" target="_blank"&gt;    &lt;img alt="&amp;#34920;&amp;#21333;&amp;#39564;&amp;#35777;" height="177" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151221162606553.png" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;而，最最重要，和  &lt;strong&gt;最最神奇的事情是&lt;/strong&gt;：我们仅仅是引入了QQ公众平台的UI组件，对，仅仅是引入和一点初始化，没有动之前一点点一丝丝的业务JS. 但是，之前的各种交互功能，却完全不受影响，反而体验更上两层楼！&lt;/p&gt;
 &lt;p&gt;请看下面的gif截图演示：  &lt;br /&gt;
  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/12/20151221161027795.gif" target="_blank"&gt;   &lt;img alt="&amp;#19994;&amp;#21153;&amp;#21151;&amp;#33021;&amp;#19981;&amp;#21463;&amp;#24433;&amp;#21709;&amp;#31034;&amp;#24847;" height="596" src="http://isux.tencent.com/wp-content/uploads/2015/12/20151221161027795.gif" width="410"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;真是一场意外之旅，发现没，面向HTML开发，实际上不是简单推动了HTML5等现代web技术落地实践，对我们的开发流程等也带来了巨大帮助——UI组件可以和业务JavaScript完全分离，可以实现无缝对接。就是因为整个组件体系基于原生HTML开发的设计理念，让UI组件回归了其本质或者说本职作用——UI.&lt;/p&gt;
 &lt;h3&gt;四、优势&lt;/h3&gt;
 &lt;p&gt;下面总结下面向HTML的UI组件开发的优势。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;1. HTML/CSS侧的现代产物落地实践&lt;/strong&gt;  &lt;br /&gt;
基于HTML标准来开发我们的UI组件，通过技术跨越各种兼容问题，使得我们前端技术在HTML层也乘上了现代web技术的快车，标准的HTML5规范和属性提前很多年在广受众的传统PC页面呈现，我觉得是非常有意义的一件事情。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;2. 规避了传统组件的很多问题&lt;/strong&gt;&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;更强的语义化，可访问性，SEO等；&lt;/li&gt;
  &lt;li&gt;学习和使用成本低；&lt;/li&gt;
  &lt;li&gt;专注HTML控件本身，而不是组件；&lt;/li&gt;
  &lt;li&gt;可以一次性全局处理；&lt;/li&gt;
&lt;/ol&gt;
 &lt;div&gt;  &lt;strong&gt;①. 语义化，可访问性&lt;/strong&gt;&lt;/div&gt;
 &lt;p&gt;毕竟是基于原生HTML来开发的，这一块必定杠杠的。&lt;/p&gt;
 &lt;p&gt;例如，时间选择：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;date&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;显然语义要比下面的  &lt;code&gt;text&lt;/code&gt;类型要好：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;text&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;又如基于  &lt;code&gt;checkbox&lt;/code&gt;/  &lt;code&gt;radio&lt;/code&gt;类型的  &lt;code&gt;input&lt;/code&gt;框模拟的单复选框自然要比传统  &lt;code&gt;div&lt;/code&gt;元素模拟的无论是语义、设备可访问性都要高很多。&lt;/p&gt;
 &lt;div&gt;  &lt;strong&gt;②. 更低的学习和使用成本&lt;/strong&gt;&lt;/div&gt;
 &lt;p&gt;不会出现类似  &lt;code&gt;GregorianCalendar&lt;/code&gt;,   &lt;code&gt;GregorianCalendarFormat&lt;/code&gt;一眼不知道干嘛的对象和方法。&lt;/p&gt;
 &lt;p&gt;不需要记住类似  &lt;code&gt;showWeekNumber&lt;/code&gt;,   &lt;code&gt;showClear&lt;/code&gt;,   &lt;code&gt;showToday&lt;/code&gt;,   &lt;code&gt;disabledDate&lt;/code&gt;这样千差万别的JS API名称，记住标准的HTML5属性即可，只要记住一次，终身受用，放心，不会变的，HTML5文案已经定稿了。&lt;/p&gt;
 &lt;p&gt;而学习成本低对于跨团队合作非常有帮助。你说kissy上手快，还是只需要写写标准HTML就OK上手快！&lt;/p&gt;
 &lt;p&gt;其他团队同学乐于使用你的东西，介入快，实现效果好，大家都开心。反之，API千差万别，每次使用都要去翻文档，肯定影响合作。&lt;/p&gt;
 &lt;p&gt;不过，实践下来，有一点学习成本我没考虑到，就是转换思维方式的学习成本。实际上只要面向元素的HTML元素开发就可以了，但是有遇到小伙伴，还是按照老的思维方式，在生成的UI组件元素上做文章。   &lt;img align="absmiddle" alt="" src="http://mat1.gtimg.com/www/mb/images/face/1.gif"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;div&gt;  &lt;strong&gt;③. 专注HTML控件本身，而不是组件&lt;/strong&gt;&lt;/div&gt;
 &lt;p&gt;举个例子，日期选择器，当日期修改了，我们要干嘛干嘛，直接：&lt;/p&gt;
 &lt;pre&gt;$(&amp;quot;input&amp;quot;).change(function() {});&lt;/pre&gt;
 &lt;p&gt;想要修改日期范围，直接：&lt;/p&gt;
 &lt;pre&gt;$(&amp;quot;input&amp;quot;).attr({
  &amp;quot;min&amp;quot;: &amp;quot;2015-12-27&amp;quot;,
  &amp;quot;max&amp;quot;: &amp;quot;2016-12-27&amp;quot;
});&lt;/pre&gt;
 &lt;p&gt;UI组件会自动同步。没有任何组件相关的JS代码，也没有什么故弄玄虚，没有所谓的高屋建瓴，全是很简单基础的HTML操作。是不是这样的开发反而很省心，连小白用户也能上手？&lt;/p&gt;
 &lt;p&gt;于是乎，在多团队联合协作开发的时候，前端开发的进度并不会受UI组件开发影响，面向HTML，专心自身业务开发就可以了。&lt;/p&gt;
 &lt;p&gt;负责组件开发的前端去休陪产假了，负责业务的前端，直接按照标准的HTML控件元素是实现自己的业务逻辑，什么回调啊都直接使用原生的事件和方法。等负责组件开发的前端，回来了，哪怕拖了个把星期，只要组件完成，公共JS一初始化，业务JS没有任何修改，无缝对接。&lt;/p&gt;
 &lt;p&gt;于是乎，实现了一个听上去很了不得的东西：  &lt;strong&gt;前端分离&lt;/strong&gt;。&lt;/p&gt;
 &lt;p&gt;这对于整个开发流程和效率也带来了巨大的提升。&lt;/p&gt;
 &lt;p&gt;不仅如此，厂子里有很多开发，负责内部项目，会写JS擅长业务功能实现，但是，UI这块是个软肋。OK，此时，我们这里面向HTML开发的UI组件体系就是其救星，对吧，直接引入CSS和JS，简单全局初始化一下（可能还有一些简单的微调），结果，页面立马高大上了，是不是很有用！&lt;/p&gt;
 &lt;div&gt;  &lt;strong&gt;④. 可以一次性全局处理&lt;/strong&gt;&lt;/div&gt;
 &lt;p&gt;传统实现，每个具体业务的脚本里面要参与UI组件的具体API参数设置。而面向HTML的实现，API落地与具体的业务页面，于是乎，只要在项目的common.js中全局初始化一下，如下拉  &lt;code&gt;Select.init()&lt;/code&gt;, 具体的业务JS文件（绝大多数情况下）中就无需再出现UI组件相关的JS代码。&lt;/p&gt;
 &lt;p&gt;UI层的JS代码和业务层JS代码分离，实现进一步的「前端分离」，去耦合。对于日后的维护、升级等要比传统组件更轻松。&lt;/p&gt;
 &lt;h3&gt;五、结果&lt;/h3&gt;
 &lt;p&gt;面向HTML的UI组件开发贯穿于整个QQ公众平台UI组件体系。包括上面没出现过的range范围选择，自定义滚动效果等等。&lt;/p&gt;
 &lt;p&gt;从实践的结果来看，前端同事啧啧称赞过（功能层），我们设计中心这边leader希望这套可以推到其他team去（体验层）。&lt;/p&gt;
 &lt;p&gt;大家有兴趣，不妨速度加入QQ公众平台，也来体验下，欢迎反馈以及提出宝贵意见。&lt;/p&gt;
 &lt;h3&gt;六、结语&lt;/h3&gt;
 &lt;p&gt;一个  &lt;code&gt;type=&amp;quot;date&amp;quot;&lt;/code&gt;的  &lt;code&gt;input&lt;/code&gt;框实际上就是一个终极的Web Components，一小段  &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt;就是一个可以被  &lt;code&gt;import&lt;/code&gt;的模块，然后就可以出现界面复杂的组件效果(shadow DOM)，而API就是HTML的原生属性。&lt;/p&gt;
 &lt;p&gt;QQ公众平台UI组件离Web Components到底有多远？如果说传统的web组件距离是1条长安街的话，那QQ公众平台UI组件只有0.5条长安街的距离。&lt;/p&gt;
 &lt;p&gt;HTML和API利用了原生的Web Components模式，非Web Components模式的仅仅是自定义的浮层这一块，但是，设计思想和思路都是朝着Web Components模式前进的。&lt;/p&gt;
 &lt;p&gt;换句话说，虽然无法一步直达Web Components，但是，我们可以利用HTML的发展，通过一些策略和设计，对UI组件进行一些变革，让其在朝着Web Components前进的道路上迈出一大步。&lt;/p&gt;
 &lt;p&gt;本文主讲设计思想，至于具体的技术细节，以后有机会会慢慢分享，能够讲的点非常非常多，越是简单的成品越是需要足够的积累。&lt;/p&gt;
 &lt;p&gt;以上，希望本文的内容能够对大家有一点启示。&lt;/p&gt;
 &lt;p&gt;  &lt;img align="absmiddle" alt="" src="http://mat1.gtimg.com/www/mb/images/face/14.gif"&gt;&lt;/img&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>前端技术 html5 UI web组件</category>
      <guid isPermaLink="true">https://itindex.net/detail/55103-html-%E5%8F%91%E5%B1%95-ui</guid>
      <pubDate>Fri, 22 Jan 2016 17:01:39 CST</pubDate>
    </item>
    <item>
      <title>浅谈移动应用的技术选型</title>
      <link>https://itindex.net/detail/56028-%E7%A7%BB%E5%8A%A8%E5%BA%94%E7%94%A8-%E6%8A%80%E6%9C%AF</link>
      <description>&lt;p&gt;在这个巨变的时代，技术选型是个很难做决定的事情，而移动应用技术领域在几个巨头（Google，Facebook，Apple etc.）的带动下更是日新月异。所以说要选择一个适合业务需求并且匹配开发人员能力的技术方案并不是一件简单的事情。我也只是在移动开发上做过一点微小的工作，此处仅能抛个砖，希望各位有玉的大神尽管砸过来。&lt;/p&gt;
 &lt;p&gt;做移动应用开发，说起来技术方案不外乎HTML5（没错，做Mobile Web其实也算是一种移动应用）、Native（在Android上不管是用Java、Kotlin还是Scala，iOS上不管是用Objective-C还是Swift）和使用原生UI，用JavaScript来实现逻辑的诸如React Native一类的方案。除此之外，还有结合HTML5和Native的Hybird混合方案。不同的技术方案有着不同的适应场景，至于具体如何选择，接下来我简单地谈谈自己的理解。&lt;/p&gt;
 &lt;p&gt;1、HTML5&lt;/p&gt;
 &lt;p&gt;也就是Web App的方案。这种方案最大的优点在于“Write Once, Run Everywhere”，不管你是Android还是iOS，都可以用一套代码搞定，在国内的话还能对接微信公众号，给用户提供一个方便快捷的入口，并且还有版本升级容易的优势（毕竟服务器是受自己控制的）。但是这种方案的缺点也很明显——无法使用系统级API，只能做为一个临时的入口，用户很难留存，并且因为浏览器性能的原因，很难带来很好的用户体验。&lt;/p&gt;
 &lt;p&gt;所以说Web App的主要适用场景还是在于作为对非核心业务在移动端的入口补足，或者是作为用户轻量、低频使用的体验增强。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/1-meituan_guide-1.png"&gt;   &lt;img alt="1-meituan_guide" height="889" src="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/1-meituan_guide-1.png" width="500"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;美团移动网站引导页&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/2-meituan_home-1.png"&gt;   &lt;img alt="2-meituan_home" height="889" src="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/2-meituan_home-1.png" width="500"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;美团移动网站首页&lt;/p&gt;
 &lt;p&gt;美团的移动网页就是很典型的例子，主要还是提供给不经常使用的用户一个入口，网站内部还是在尽量引导用户下载使用客户端。&lt;/p&gt;
 &lt;p&gt;2、Hybird&lt;/p&gt;
 &lt;p&gt;Hybird是一种兼顾Native与HTML的开发模式，但根据实现的不同，还可以再细分为两种实现方案：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;在Native App中使用WebView加载远端Web资源&lt;/li&gt;
  &lt;li&gt;使用Cordova/PhoneGap等框架通过WebView加载本地资源进行页面渲染&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;第一种方案其实已经应用得非常普遍了，很多应用的展示页面都是通过这种方式实现的。因为展示页面需要的正是能够轻易更换内容及布局的格式，并且这种纯展示的页面也并不需要复杂的动画与特效，使用Web页面是一个非常合适的解决方案。&lt;/p&gt;
 &lt;p&gt;而第二种方案前一段时间非常火，因为它在跨平台，在高效开发以及快速发布上有着明显的优势，毕竟Web内容只需要开发一次就可以在各个平台使用。而且将资源打包到本地也可以在一定程度上缓解从远端加载静态资源导致UI展示延迟的问题，并且还可以通过桥接Native和Web来调用一些Device的API。但其劣势也很明显，一是通过WebView执行代码效率较低，很难实现一些炫酷的效果，并且还存在不同设备的兼容性问题；二是如果想调用相关平台的API，需要针对平台单独进行开发，如果在应用中用到了大量的Device API，那么开发的效率将大大降低；三是很难应用到平台相关的新特性，比较难做出有特色的产品。&lt;/p&gt;
 &lt;p&gt;使用HTML页面来实现纯展示页面是非常推荐的一种方案。而Cordova/PhoneGap则更适用于对Mobile预算有限的公司、创业团队，或者对App进行快速的上线验证。&lt;/p&gt;
 &lt;p&gt;正好之前有个项目就用到了这种方案，为一家业务转型的零售商提供了使用一套基本代码来完成Android和iOS两个平台的App和微信公众号的相关页面的技术方案。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/3-jingbao_app-1.png"&gt;   &lt;img alt="3-jingbao_app" height="889" src="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/3-jingbao_app-1.png" width="500"&gt;&lt;/img&gt;&lt;/a&gt;  &lt;a href="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/4-jingbao.png"&gt;   &lt;img alt="4-jingbao" height="889" src="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/4-jingbao.png" width="500"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;零售商Android应用零售商微信端&lt;/p&gt;
 &lt;p&gt;3、React Native&lt;/p&gt;
 &lt;p&gt;把React Native单独拿出来，是因为确实不能简单的将它分到其它任意一种方案里面去。React Native确实是最近最火的跨平台App解决方案了。它脱胎于React，因为React基于Virtual DOM来进行界面渲染，所以用Native的View来替换掉原本React的HTML DOM就顺理成章的引出了React Native的概念。&lt;/p&gt;
 &lt;p&gt;它与之前的跨平台方案有一个本质的区别，在于：其它方案都在追求写一次code解决所有平台的问题，而React Native的理念在于“Learn Once, Write Anywhere”。虽然大部分代码是平台无关的，但是平台相关的代码都需要单独实现，这虽然对跨平台带来了不便，但是引入的好处也是显而易见的，View层的部分通过原生组件实现，性能比其他WebView的方案不知道高到哪去了。而且React Native整套的逻辑代码都通过JavaScript实现，这样就让跨平台应用能够方便的复用逻辑代码。另外虽然React Native没有支持使用CSS来实现样式，但是提供了类似CSS的样式表支持，有过UI开发经验的人都能够非常快的上手。由于前端React也是非常的火，很多React社区的很多产出都可以在React Native上借鉴使用。&lt;/p&gt;
 &lt;p&gt;React Native对于没有复杂动画效果的一般应用来说不失为一个很好的解决方案。而且对于一些小型的企业级应用也是非常适用的。但是，React Native对于Android平台的支持度是不如iOS平台的，而且现有的非常成熟的应用也较少，所以说如果要在一些面向用户量很大，讲求用户体验的App中使用还是要慎重考虑的。&lt;/p&gt;
 &lt;p&gt;但是，其实Facebook已经在自家的App上用起来了，而且实测效果还是很好的。不过呢，人家毕竟是自家维护的，所以说真正要在项目上用可能还是得试了才知道效果。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/5-facebook.png"&gt;   &lt;img alt="5-facebook" height="856" src="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/5-facebook.png" width="500"&gt;&lt;/img&gt;&lt;/a&gt;  &lt;a href="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/6-facebook_ios.jpeg"&gt;   &lt;img alt="6-facebook_ios" height="696" src="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/6-facebook_ios.jpeg" width="392"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;facebook Androidfacebook iOS&lt;/p&gt;
 &lt;p&gt;4、原生应用&lt;/p&gt;
 &lt;p&gt;原生应用的开发真的是让人又爱又恨。爱在于你可以在它上面施展拳脚、使用新特性、实现炫酷的效果。而恨则在于它跨平台性几乎为零，除了资源外几乎没有可重用的东西，即使是相似架构上的逻辑你也得再实现一遍。使用原生开发，能够方便地添加动画效果，调用底层硬件，所有的限制仅仅是来自平台的限制。但是正常情况下需要对不同的平台搭配不同的开发人员，而且如果要追求良好的用户体验，整个应用的设计还得满足相应平台的设计规范，这不仅是对Dev的考验，也是对UX的考验。不过如果真的对App的质量有很高的要求，我觉得这一切的付出也还是都是值得的。&lt;/p&gt;
 &lt;p&gt;如果针对的是要求硬件性能、讲究动画效果、追求用户体验的应用，还是建议分平台单独设计，并且都使用原生的技术方案来实现。其实这也是目前市面上大部分企业做出的选择。&lt;/p&gt;
 &lt;p&gt;使用原生开发我个人还有一个观点，就是  &lt;strong&gt;设计上要尽量遵守原生应用的设计规范，如果想要一套设计通吃所有平台，最终只会搞一个不伦不类的应用出来&lt;/strong&gt;。知乎算是国内在这方面做得比较好的应用了，也取得了不错的效果。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/7-zhihu.png"&gt;   &lt;img alt="7-zhihu" height="889" src="http://insights.thoughtworkers.org/wp-content/uploads/2016/09/7-zhihu.png" width="500"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;知乎&lt;/p&gt;
 &lt;p&gt;其实，在真正启动项目之前，在进行技术选型时，除了要考虑更符合业务的架构外，还要考虑开发人员的能力及技术栈。毕竟最后App还是由Dev们开发的。如果仅仅考虑业务而不考虑开发人员的技术能力来选择技术方案，不仅有一种钦定的感觉，而且最后往往坑到的还是自己。&lt;/p&gt;
 &lt;p&gt;我们常说：工具是死的，人是活的。考虑多种因素，在技术选型上做出更充分的考量，才是真正正确的选择。所以说又回到那句老话上：“It depends…”&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;

 &lt;p&gt;  &lt;a href="http://blog.jobbole.com/106157/"&gt;浅谈移动应用的技术选型&lt;/a&gt;，首发于  &lt;a href="http://blog.jobbole.com"&gt;文章 - 伯乐在线&lt;/a&gt;。&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>IT技术 HTML5 移动应用</category>
      <guid isPermaLink="true">https://itindex.net/detail/56028-%E7%A7%BB%E5%8A%A8%E5%BA%94%E7%94%A8-%E6%8A%80%E6%9C%AF</guid>
      <pubDate>Tue, 11 Oct 2016 12:05:21 CST</pubDate>
    </item>
    <item>
      <title>玩转HTML5移动页面（动效篇）</title>
      <link>https://itindex.net/detail/53313-html5-%E7%A7%BB%E5%8A%A8-%E9%A1%B5%E9%9D%A2</link>
      <description>&lt;p&gt;作为一名前端，在拿到设计稿时你有两种选择：&lt;/p&gt;
 &lt;div&gt;1.快速输出静态页面&lt;/div&gt;
 &lt;div&gt;2.加上高级大气上档次狂拽炫酷屌炸天的动画让页面动起来&lt;/div&gt;
 &lt;div&gt;作为一个有志向的前端，当然是选2啦！可是需求时间又很短很短，怎么办呢？&lt;/div&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;div&gt;这次就来谈谈一些动画设计的小技巧，能在你时间不多又没有动画想法的时候瞬间让页面增色不少。&lt;/div&gt;
 &lt;div&gt;同时也会谈及移动端H5页面的优化细节与关键点，因此本文章将分为  &lt;strong&gt;动效篇&lt;/strong&gt;和  &lt;a href="http://isux.tencent.com/play-with-html5-optimize.html" target="_blank" title="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;"&gt;   &lt;strong&gt;优化篇&lt;/strong&gt;&lt;/a&gt;。&lt;/div&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;div&gt;====前方高能====&lt;/div&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;div&gt;（1）  CSS3时序错开渐显动画&lt;/div&gt;
 &lt;div&gt;这是一种比较常用的动画，它的优点是节奏感强，做法就是先让每个元素隐藏，然后当页面呈现后每个元素错开时间出现。&lt;/div&gt;
 &lt;div&gt;例子（忽略兼容前缀和无关属性）：&lt;/div&gt;
 &lt;div&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326235946454.png" target="_blank"&gt;   &lt;img alt="code1" height="49" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326235946454-590x49.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
 &lt;div&gt;  &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/2015032623594763.png" target="_blank"&gt;   &lt;img alt="code2" height="257" src="http://isux.tencent.com/wp-content/uploads/2015/03/2015032623594763-590x257.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
 &lt;div&gt;
  &lt;p&gt;效果就是两个元素分别从上面掉下来，这里有个小细节（keyframes），为了让掉下来的动画生动点，应该是在90%的时候先掉下一点点，然后瞬间在100%时回跳5px。&lt;/p&gt;
  &lt;p&gt;还有个细节，安卓2.3.*不能良好支持-webkit-animation-fill-mode，也就是渐变动画不能停止在最后一帧。有这样一个解决方案：&lt;/p&gt;
  &lt;p&gt;1.用   &lt;a href="http://modernizr.com/" target="_blank"&gt;Modernizr&lt;/a&gt;去检测是否支持这个属性，加上识别类.no-animation-fill-mode；&lt;/p&gt;
  &lt;p&gt;2.根据识别类采取以下措施：   &lt;br /&gt;
（1）用js模拟同样效果；   &lt;br /&gt;
（2）用css屏蔽掉动画；   &lt;br /&gt;
（3）或者直接全部都用transition来做（不要keyframes）。&lt;/p&gt;
  &lt;p&gt;示例页面如下（   &lt;a href="http://m.isux.us/qz-act/vip/20140903-qzonev5/m-index.html" target="_blank"&gt;查看DEMO&lt;/a&gt;）：&lt;/p&gt;
  &lt;p&gt;   &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222456182.gif" target="_blank"&gt;    &lt;img alt="qzone5_1" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222456182.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;     &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/2015032622245783.png" target="_blank"&gt;    &lt;img alt="qzone5_1_qrcode" height="168" src="http://isux.tencent.com/wp-content/uploads/2015/03/2015032622245783.png" width="169"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;div&gt;
   &lt;div&gt;（2） CSS3细节强调动画&lt;/div&gt;
   &lt;div&gt;一些局部细节如果还是渐现显示，会枯燥没什么感觉，例如标题、按钮等，需要一种强调。&lt;/div&gt;
   &lt;p&gt; &lt;/p&gt;
   &lt;div&gt;分两种情况：&lt;/div&gt;
   &lt;div&gt;1.如果时间允许的话，基本做法是先把一个元素切成不同的块状，例如小人的手脚都切成不同图片，然后让它们重新组合，再通过赋予不同的CSS动画来让它生动起来，这里引用个webank的例子：&lt;/div&gt;
   &lt;div&gt;    &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222500244.gif" target="_blank"&gt;     &lt;img alt="webank" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222500244.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;      &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222500772.png" target="_blank"&gt;     &lt;img alt="webank_qrcode" height="174" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222500772.png" width="173"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
   &lt;div&gt;（    &lt;a href="http://sunnyzhen.github.io/course/demo/motorcycle/index.html" target="_blank"&gt;查看DEMO&lt;/a&gt;）&lt;/div&gt;
   &lt;p&gt; &lt;/p&gt;
   &lt;div&gt;
    &lt;div&gt;2.如果时间紧凑，又不像桑尼一样擅长于动画细节，可以使用一些辅助工具：&lt;/div&gt;
    &lt;div&gt;     &lt;a href="http://daneden.github.io/animate.css/" target="_blank"&gt;Animate.css&lt;/a&gt;，通过直接预览选择想要的动效，然后下载它的CSS把对应的keyframe扒下来就好了（引用整个CSS是资源浪费）。&lt;/div&gt;
    &lt;p&gt; &lt;/p&gt;
    &lt;div&gt;
     &lt;div&gt;（3）SVG动画&lt;/div&gt;
     &lt;div&gt;SVG技术越来越不陌生，使用门槛也渐渐降低，而且SVG动画还可以使用CSS控制。&lt;/div&gt;
     &lt;div&gt;先看个生日页面，是个SVG的蛋糕：&lt;/div&gt;
     &lt;div&gt;      &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222454666.gif" target="_blank"&gt;       &lt;img alt="cyy" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222454666.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;        &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222455593.png" target="_blank"&gt;       &lt;img alt="cyy_qrcode" height="158" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222455593.png" width="164"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
     &lt;div&gt;
      &lt;div&gt;（       &lt;a href="http://cyyis.me/" target="_blank"&gt;查看DEMO&lt;/a&gt;）&lt;/div&gt;
      &lt;p&gt; &lt;/p&gt;
      &lt;div&gt;可见SVG是很强大的！弥补了CSS3的不足。&lt;/div&gt;
      &lt;div&gt;
       &lt;div&gt;然而这种动画也是略耗时，但有一种比较常用的，就是线条的描绘动画，CSS3比较难实现，这里可以用SVG，看图：&lt;/div&gt;
       &lt;div&gt;&lt;/div&gt;
       &lt;div&gt;        &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222821628.gif" target="_blank"&gt;         &lt;img alt="linkline" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222821628.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
       &lt;p&gt; &lt;/p&gt;
       &lt;div&gt;
        &lt;div&gt;介绍一个PS插件         &lt;a href="http://share.weiyun.com/d82e75215ed601986a63e16c6b6fc56a?g_f=&amp;srctype=&amp;ticket=" target="_blank"&gt;svgArtisan&lt;/a&gt;（目前还未有主页），这个工具可以直接根据PSD的路径图层生成SVG图形。&lt;/div&gt;
        &lt;div&gt;接下来就简单了，将设计稿上的路径图形用插件生成对应的SVG，例如是这样的：&lt;/div&gt;
        &lt;div&gt;（注意，其中的foreignObject标签内是不支持svg的浏览器会看到一张.m3-svg-nosupport标签下的图片。）&lt;/div&gt;
        &lt;p&gt;         &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326231605887.png" target="_blank"&gt;          &lt;img alt="svg1" height="192" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326231605887-590x192.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
        &lt;p&gt;再使用CSS3的animation控制stroke-dashoffset：&lt;/p&gt;
        &lt;p&gt;         &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326231606519.png" target="_blank"&gt;          &lt;img alt="svg2" height="96" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326231606519-590x96.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
        &lt;p&gt;效果不难吧！SVG还有各种用途，例如制作ICONFONT等，可以深入挖掘。&lt;/p&gt;
        &lt;div&gt;（4） 重力陀螺仪&lt;/div&gt;
        &lt;div&gt;想让页面更有层次感，不妨让设计提供一些碎片元素，例如彩花，星星之类，然后把它们单独切出来放画面前景，使用陀螺仪伴随着手机运动碎片也跟着运动，多么好玩！&lt;/div&gt;
        &lt;div&gt;这里提供一个工具可以轻松实现陀螺仪重力效果的：         &lt;a href="http://matthew.wagerfield.com/parallax/" target="_blank"&gt;parallax.js&lt;/a&gt;&lt;/div&gt;
        &lt;div&gt;用法简单，定义一个parallax-obj的父类，把需要动的元素加上layer的类，然后设置动的范围data-depth：&lt;/div&gt;
        &lt;div&gt;         &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326232342992.png" target="_blank"&gt;          &lt;img alt="parallax" height="130" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326232342992-590x130.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;p&gt; &lt;/p&gt;
        &lt;div&gt;
         &lt;div&gt;（5） 背景音乐&amp;amp;音效&lt;/div&gt;
         &lt;div&gt;H5页面要炫酷，画面生动还是不够的，一定要配合生动的音乐。因此可以主动跟设计或产品沟通，让他们可以提供音乐资源，分分钟导致UV猛涨有木有！&lt;/div&gt;
         &lt;p&gt; &lt;/p&gt;
         &lt;div&gt;当然，有了音乐，前端也不是直接引用的，还是有点要求：&lt;/div&gt;
         &lt;div&gt;1.音乐不宜过长，30s为佳，而且音乐要加上渐现渐隐效果，方便循环播放；&lt;/div&gt;
         &lt;div&gt;2.音乐体积要小，音质和流量，在手机上还是优先考虑流量吧。&lt;/div&gt;
         &lt;div&gt;一般背景音乐体积可以接受的范围是200K以下，若太大，可以使用格式工厂等软件，降低它的比特率和声道来改变体积。&lt;/div&gt;
         &lt;p&gt; &lt;/p&gt;
         &lt;div&gt;接着，只需要简单引用：&lt;/div&gt;
         &lt;div&gt;          &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326235947764.png" target="_blank"&gt;           &lt;img alt="code3" height="44" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326235947764-590x44.png" width="590"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
         &lt;div&gt;这里有个问题，IOS是不能自动播放音乐的，一定要触发一个用户交互事件，例如点击。&lt;/div&gt;
         &lt;div&gt;但是有一种hack的方法可以让IOS微信侧页面自动播放（SAFARI依旧无效）：&lt;/div&gt;
         &lt;div&gt;通过new一张图片，监听一张图片的onload事件，结束后回调执行音频播放audio.play()即可，原理估计是动了dom结构，相当于执行了一次交互。（有人也用过createEvent模拟，原理也是动了dom。）&lt;/div&gt;
         &lt;div&gt;因此，记得暴露一个音乐关闭/打开的按钮，不然肯定被用户骂死。&lt;/div&gt;
         &lt;p&gt; &lt;/p&gt;
         &lt;div&gt;（6）有趣的loading&lt;/div&gt;
         &lt;div&gt;Loading页还是要有的，万一用户网速慢呢？&lt;/div&gt;
         &lt;div&gt;以上做了那么多事，如果没有资源加载都是玩不来的，因此还需要一个loading的支持。一般情况下页面体积大于3m则要加上loading页。&lt;/div&gt;
         &lt;p&gt; &lt;/p&gt;
         &lt;div&gt;然而loading还是可以做得很有趣的，一般的做法是：&lt;/div&gt;
         &lt;div&gt;1.引入品牌，例如APP宣传页；&lt;/div&gt;
         &lt;div&gt;2.引入有趣动画，放一个贱贱的人物跳舞给你看；&lt;/div&gt;
         &lt;div&gt;3.一切从简，用CSS3简单动画。&lt;/div&gt;
         &lt;p&gt;====最后总结====&lt;/p&gt;
         &lt;div&gt;最后，给一个例子结尾吧。&lt;/div&gt;
         &lt;div&gt;
          &lt;div&gt;这是空间5.0预约页第二版，使用了以上的若干方法论，例如loading动画，CSS3动画，SVG星空连线，首屏星球重力感应，音乐（这里使用开启按钮后播放）等等。&lt;/div&gt;
          &lt;div&gt;（由于活动已结束，很多运营处都被删掉从简了，忽略那些细节）&lt;/div&gt;
          &lt;div&gt;&lt;/div&gt;
          &lt;div&gt;           &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222457610.gif" target="_blank"&gt;            &lt;img alt="qzone5_2" height="561" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222457610.gif" width="316"&gt;&lt;/img&gt;&lt;/a&gt;             &lt;a href="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222458446.png" target="_blank"&gt;            &lt;img alt="qzone5_2_qrcode" height="171" src="http://isux.tencent.com/wp-content/uploads/2015/03/20150326222458446.png" width="173"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div&gt;（           &lt;a href="http://qzs.qq.com/qzone/qzact/act/qzapp/qzone5.0/mobile/index.html" target="_blank"&gt;查看DEMO&lt;/a&gt;）&lt;/div&gt;
          &lt;p&gt; &lt;/p&gt;
          &lt;div&gt;当然，真正要做到高效制作动态H5页面，还是靠积累，因此平时做好的细节动画自己都积累起来，下次分分钟就能用得上。&lt;/div&gt;
          &lt;div&gt;&lt;/div&gt;
          &lt;div&gt;请继续阅读《           &lt;a href="http://isux.tencent.com/play-with-html5-optimize.html" target="_blank" title="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;"&gt;玩转HTML5移动页面（优化篇）&lt;/a&gt;》。&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>前端技术 html5 动画 效果 移动端</category>
      <guid isPermaLink="true">https://itindex.net/detail/53313-html5-%E7%A7%BB%E5%8A%A8-%E9%A1%B5%E9%9D%A2</guid>
      <pubDate>Tue, 28 Apr 2015 10:32:55 CST</pubDate>
    </item>
    <item>
      <title>玩转HTML5移动APP页面（优化篇）</title>
      <link>https://itindex.net/detail/53307-html5-%E7%A7%BB%E5%8A%A8-app</link>
      <description>&lt;p&gt;承接上文《  &lt;a href="http://www.shejidaren.com/html5-animate-page.html"&gt;玩转HTML5移动APP页面（动效篇）&lt;/a&gt;》，上次说的是让页面动起来的一些小技巧。  &lt;br /&gt;
而页面动起来的根基是功能可用的页面，因此有必要分享一些优化细节的技巧和方向，熟悉掌握一些方法论还是会对页面开发大大提高效率的，并且也能防止疏忽缺漏。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="cover-01" height="360" src="http://images.shejidaren.com/wp-content/uploads/2015/04/034816e5f.jpg" width="630"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;====前方高能====&lt;/p&gt;
 &lt;h3&gt;（1） 动画雪碧图&lt;/h3&gt;
 &lt;p&gt;涉及的动画十分多，用的元素也十分多，请务必使用雪碧图（Sprite）！  &lt;br /&gt;
网上的工具有一些可以帮助你生成雪碧图的工具，例如  &lt;a href="http://www.99css.com/tag/cssgaga/" target="_blank"&gt;CssGaga&lt;/a&gt;，  &lt;a href="http://isux.tencent.com/alloyteam.github.io/gopng" target="_blank"&gt;GoPng&lt;/a&gt;等等，自动化构建工具Grunt和Gulp也提供了相应插件。  &lt;br /&gt;
特别地，如果单张雪碧图面积实在太大，可以拆分雪碧图，例如拆分成2-4张，因为现代浏览器都支持4-6个同源请求下载，若资源实在太多，也可以考虑把静态资源放在不同源域名下去请求，这里牺牲多几个请求换来图片同时加载比一张图片慢慢加载要好，当然，这需要具体情况去衡量。&lt;/p&gt;
 &lt;p&gt;顺便提一下，我写动画的一个小技巧是把每一页的动画分在一个import.css里面，然后最后在主样式中import进去，这样方便调试动画，也容易维护，例如：&lt;/p&gt;
 &lt;pre&gt;//style.css
@import url(&amp;quot;reset.import.css&amp;quot;);
@import url(&amp;quot;loading.import.css&amp;quot;);
@import url(&amp;quot;m-animate-1.import.css&amp;quot;);
@import url(&amp;quot;m-animate-2.import.css&amp;quot;);
@import url(&amp;quot;m-animate-3.import.css&amp;quot;);&lt;/pre&gt;
 &lt;p&gt;当然，import不是原生支持的，这里需要一些流程化工具让import的页面在输出之前经过组装-压缩的步骤。&lt;/p&gt;
 &lt;h3&gt;（2）图片压缩&lt;/h3&gt;
 &lt;p&gt;图片压缩是老生常谈，但是仍然有不少人忘记压缩，那可是活生生的带宽和流量的浪费啊…&lt;/p&gt;
 &lt;p&gt;压缩图片需要有好工具，有  &lt;a href="http://zhitu.tencent.com/" target="_blank"&gt;智图&lt;/a&gt;，  &lt;a href="https://tinypng.com/" target="_blank"&gt;TinyPNG&lt;/a&gt;，  &lt;a href="http://www.jpegmini.com/" target="_blank"&gt;JPEGmini&lt;/a&gt;等等。&lt;/p&gt;
 &lt;p&gt;依靠工具外，还有以下方式可以优化图片：&lt;/p&gt;
 &lt;p&gt;1.尽量避免用PNG24。如果图片色彩要求不高，请使用PNG8；  &lt;br /&gt;
2.使用新格式，WEBP和BPG等新格式的到来，在不用考虑兼容的情况下请大胆尝试；  &lt;br /&gt;
3.用SVG和ICONFONT代替简单的图标；  &lt;br /&gt;
4.用FUFU的  &lt;a href="http://isux.tencent.com/font-spider.html" target="_blank"&gt;字蛛&lt;/a&gt;来代替艺术字体切图。&lt;/p&gt;
 &lt;h3&gt;（3）多终端兼容&lt;/h3&gt;
 &lt;p&gt;多终端兼容是一切的根基，要知道有人拿着肾6+，有人拿着肾4，大则414×736，小则320×416（IPHONE4在SAFARI保留上下端导航），因此多终端兼容是十分必要的。  &lt;br /&gt;
曾经有一种派系为320派系，就是大部分页面都是320宽度，因此干脆直接用320的容器来包一切页面，那样也简单，然而IPHOEN6和IPHONE6+的出现简直是灭了这个派系。&lt;/p&gt;
 &lt;p&gt;那么到底要如何兼容呢？  &lt;br /&gt;
这里我分了三个时期来说说：  &lt;br /&gt;
A.设计初期。先审视设计稿，因为320派系的原因，大部分设计稿只考虑到IPHONE5来设计，因此很多背景元素是只有320px宽度（页面实际渲染宽度），例如下图。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;" height="521" src="http://images.shejidaren.com/wp-content/uploads/2015/04/034816MQF.jpg" width="439"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;那么，这时候就需要设计提供一个较长的延伸背景了，最好是可以重复的，用background-repeat可以减少图片大小。&lt;/p&gt;
 &lt;p&gt;B.设计中期。也就是具体的兼容方法，可以使用CSS3 Media Query和类覆盖。&lt;/p&gt;
 &lt;p&gt;1.CSS3 Media Query，按范围兼容机型。&lt;/p&gt;
 &lt;pre&gt;/*iphone6*/
@media only screen
and (min-device-width : 375px)
and (max-device-width : 667px)
and (orientation : portrait)
and (-webkit-min-device-pixel-ratio : 2)
{
.page6 .ele-building{top: 69px;}
.page6 .ele-runner{top: 100px;}
.page6 .ele-pophome{top: 16px;}
}&lt;/pre&gt;
 &lt;p&gt;2.类覆盖，这种方式适合直接为小屏或大屏做整体兼容。  &lt;br /&gt;
首先，为小屏（大屏）加一个识别类，这里小于420表示为小屏幕（IPHONE4有上下导航栏）：&lt;/p&gt;
 &lt;pre&gt;var bh = $(window).height();
// 480 - 64 = 416 iphone4
if(bh&amp;amp;lt;420){
$(&amp;apos;body&amp;apos;).addClass(&amp;apos;low-screen&amp;apos;);
}&lt;/pre&gt;
 &lt;p&gt;然后，对应识别类加上要变动的元素覆盖，例如：&lt;/p&gt;
 &lt;pre&gt;.page6 .ele-bg{top: 10px;}
.low-screen .page6 .ele-bg{top: 0px;}&lt;/pre&gt;
 &lt;p&gt;C.设计后期。这是最后一步，整体检查和体验，这里面会暴露一些问题，例如元素在IPHONE6P显得小了或者元素在IPHONE4挤不下了，可以来最后大招解决：&lt;/p&gt;
 &lt;p&gt;1.大屏适当用zoom:(倍率)或者transform:scale(倍率)来增大元素，实测失真根本看不出来，设计师也满意（毕竟不用多做一张图！）；  &lt;br /&gt;
2.小屏适当去掉一些元素，例如一些翻页提示，一些多余图标，可以让优雅降级，把它们 display:none掉。&lt;/p&gt;
 &lt;p&gt;有以上几步，基本就能兼容大部分机器了。兼容一直是个苦活，但是这是前端必修课，多练就会发觉其实也没有那么难嘛。&lt;/p&gt;
 &lt;h3&gt;（4）交互提示&lt;/h3&gt;
 &lt;p&gt;前面说了，加了音效就要加上音乐切换开关的按钮，不然会被用户骂死。还有其他，例如如果你的页面不能兼容横屏，请监听横屏状态，然后加上适当的横屏提示。&lt;/p&gt;
 &lt;p&gt;例如：&lt;/p&gt;
 &lt;pre&gt;// 横屏监听
var updateOrientation = function(){
if(window.orientation==&amp;apos;-90&amp;apos; || window.orientation==&amp;apos;90&amp;apos;){
$(&amp;apos;.landscape-wrap&amp;apos;).removeClass(&amp;apos;hide&amp;apos;);
console.log(&amp;apos;为了更好的体验，请将手机/平板竖过来！&amp;apos;);
}else{
$(&amp;apos;.landscape-wrap&amp;apos;).addClass(&amp;apos;hide&amp;apos;);
console.log(&amp;apos;竖屏状态&amp;apos;);
}
};
window.onorientationchange = updateOrientation;&lt;/pre&gt;
 &lt;p&gt;提示越多，界面越友好，有时候设计师会漏掉一些可能出现的页面情况。  &lt;br /&gt;
作为有态度的前端，请好好把关，让用户有好的体验。&lt;/p&gt;
 &lt;h3&gt;（5）分享接口&lt;/h3&gt;
 &lt;p&gt;H5做好了，要传播分享才能展示你的牛逼轰轰。  &lt;br /&gt;
然而分享其实是个坑，分享到微信、手Q等都有各种问题。&lt;/p&gt;
 &lt;p&gt;A.微信&lt;/p&gt;
 &lt;p&gt;旧微信会使用WeixinJSBridge来声明分享的缩略图、标题、正文等，比较方便。例如：  &lt;br /&gt;
  &lt;img alt="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;" height="287" src="http://images.shejidaren.com/wp-content/uploads/2015/04/0348166Q1.png" width="590"&gt;&lt;/img&gt;  &lt;br /&gt;
而最新的微信提供了新的微信SDK，需要在公众账号绑定所属域名之后调用SDK作分享，可以说分享功能会更加强大，坑也会更加少。&lt;/p&gt;
 &lt;p&gt;B.手Q&lt;/p&gt;
 &lt;p&gt;手Q支持声明meta标签的的分享方式，例如：  &lt;br /&gt;
  &lt;img alt="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;" height="96" src="http://images.shejidaren.com/wp-content/uploads/2015/04/034817fAl.png" width="590"&gt;&lt;/img&gt;  &lt;br /&gt;
而若在qq.com域名下也支持api的定义方式。&lt;/p&gt;
 &lt;p&gt;C.一般化分享&lt;/p&gt;
 &lt;p&gt;在默认兼容旧版微信、手Q或者各种浏览器，平台，可以用这样的方法：  &lt;br /&gt;
写h1做标题，p做内容，img做缩略图，只需要把h1隐藏掉就好，这里的缩略图最好要大于200x200px。&lt;/p&gt;
 &lt;p&gt;例如：  &lt;br /&gt;
  &lt;img alt="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;" height="120" src="http://images.shejidaren.com/wp-content/uploads/2015/04/034817G6h.png" width="590"&gt;&lt;/img&gt;  &lt;br /&gt;
当然，这样也有利于搜索引擎拉取信息。&lt;/p&gt;
 &lt;p&gt;分享的坑还有更多，例如不同浏览器例如QQ浏览器、Chrome也会有自己的默认拉取方式（部分截图作缩略图），需要多加测试优化。&lt;/p&gt;
 &lt;h3&gt;（5）SEO搜索引擎优化&lt;/h3&gt;
 &lt;p&gt;SEO（搜索引擎优化）的基本做法是把页面结构写好，这包括：&lt;/p&gt;
 &lt;p&gt;1.定义精确的网页标题。你的标题应该有概括性，能明确告知搜索引擎和用户你的网站大概内容和目的，可以是当前页面标题-所属类型-产品名，例如“全民来猜歌-年费黄钻-QQ空间”。&lt;/p&gt;
 &lt;p&gt;2.针对页面内容补充description和keywords的meta标签。你需要简短总结页面的主要目标，然后补充description，以及根据关键词补充keywords。&lt;/p&gt;
 &lt;p&gt;3.优化你的超链接和图片。包括优化超链接显示的文本，要具有语义性也要跟超链接的网页具有相关性，例如“空间主页”就不要链接到“www.qq.com”。同时，要补充”title”和”alt”属性，例如“&amp;lt;img src=’images/apple.jpg’ title=’苹果示例图’ alt=’苹果示例图’ /&amp;gt;”。&lt;/p&gt;
 &lt;p&gt;4.建立良好的网站导航和sitemap。网站需要有一个良好的导航，控制根目录和各子目录的关键，通过sitemap可以帮助网站主了解网站结构，也方便搜索引擎收录整个站点。&lt;/p&gt;
 &lt;p&gt;5.优化目录结构和URL。你的URL应该有语义性，简短易懂，例如http://www.apple.com/macbook-air/，而且每一层级都要有它对应的页面展示以及语义。&lt;/p&gt;
 &lt;p&gt;6.善用h1-h6的标题结构树。合理的标题可以强调文字，也能让搜索引擎更加了解到各标题的重要性，因此建立良好的标题树十分有意义。&lt;/p&gt;
 &lt;p&gt;7.不断致力于提供优质的内容。社交化分享是网站曝光最快的因素，因此不断提供了优质原创内容才能真正提高你的网站曝光权重。&lt;/p&gt;
 &lt;h3&gt;（6）无障碍&lt;/h3&gt;
 &lt;p&gt;无障碍的普及是一件好事，这让互联网真正地为所有人可用。因此我们也应该为之而努力，无障碍的根基是你页面强壮的语义性和结构性，具体可以参考《  &lt;a href="http://www.qq.com/demo/accessibility.htm" target="_blank"&gt;腾讯网无障碍说明&lt;/a&gt;》了解无障碍的优化手段。&lt;/p&gt;
 &lt;p&gt;最后，罗嗦了这么多，只是我自己的一些小经验，请轻拍砖，多交流。&lt;/p&gt;
 &lt;p&gt;腾讯ISUX (  &lt;a href="http://isux.tencent.com/play-with-html5-optimize.html" rel="nofollow" target="_blank"&gt;http://isux.tencent.com/play-with-html5-optimize.html&lt;/a&gt;)&lt;/p&gt;
 &lt;hr&gt;&lt;/hr&gt;Copyright ©2010-2014 ¦  &lt;a href="http://www.shejidaren.com/feed" target="_blank" title="RSS&amp;#35746;&amp;#38405;"&gt;RSS订阅&lt;/a&gt; ¦  &lt;a href="http://weibo.com/shejidaren888" target="_blank" title="&amp;#26032;&amp;#28010;&amp;#24494;&amp;#21338;"&gt;新浪微博&lt;/a&gt; ¦  &lt;a href="http://www.shejidaren.com/html5-app-page-optimize.html" target="_blank" title="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;APP&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;"&gt;本文链接&lt;/a&gt; ¦  &lt;a href="http://www.shejidaren.com/html5-app-page-optimize.html#respond" target="_blank" title="&amp;#29609;&amp;#36716;HTML5&amp;#31227;&amp;#21160;APP&amp;#39029;&amp;#38754;&amp;#65288;&amp;#20248;&amp;#21270;&amp;#31687;&amp;#65289;&amp;#30340;&amp;#35780;&amp;#35770;"&gt;添加评论&lt;/a&gt;  &lt;br /&gt;交流：UI设计交流群：59300679，与500名设计师交流设计，分享素材。&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>HTML &amp; CSS 前端开发 HTML5</category>
      <guid isPermaLink="true">https://itindex.net/detail/53307-html5-%E7%A7%BB%E5%8A%A8-app</guid>
      <pubDate>Tue, 28 Apr 2015 12:10:42 CST</pubDate>
    </item>
    <item>
      <title>【译】Hybrid移动应用：用网页技术提供Native体验</title>
      <link>https://itindex.net/detail/52872-hybrid-%E7%A7%BB%E5%8A%A8%E5%BA%94%E7%94%A8-%E7%BD%91%E9%A1%B5</link>
      <description>&lt;p&gt;原文：  &lt;a href="http://www.smashingmagazine.com/2014/10/21/providing-a-native-experience-with-web-technologies/"&gt;http://www.smashingmagazine.com/2014/10/21/providing-a-native-experience-with-web-technologies/&lt;/a&gt;  &lt;br /&gt;
翻译：  &lt;a href="http://weibo.com/4eversai"&gt;叮当当咚当当小胖妞呀&lt;/a&gt;   &lt;a href="http://weibo.com/back2black"&gt;杀手爱elva&lt;/a&gt;   &lt;a href="http://weibo.com/blueed"&gt;Ivan_z3&lt;/a&gt; 肖弦&lt;/p&gt;
 &lt;p&gt;根据最近的一篇  &lt;a href="http://www.visionmobile.com/product/developer-economics-q3-2014/"&gt;报告&lt;/a&gt;显示，HTML是移动应用开发人员使用最多的语言，开发人员对于选择哪种网页技术考虑的最主要因素，是代码的跨平台便携性和开发的低成本性。我们常常听说，hybrid app使用起来非常慢，而且设计也很糟糕，让我们看看是否有可能又有原生应用的形，又有我们习惯使用的感。&lt;/p&gt;
 &lt;p&gt;这篇文章会提供很多关于如何构建良好的hybrid移动应用的线索、代码片段和经验。我将会大致介绍一下hybrid移动应用的开发，包括它的优点和缺点。然后，我会分享一下过去两年我在开发Hojoki和CatchApp时积累的经验，这两个项目都运行在主流的移动平台，并且是由HTML、CSS和Javascript建成的。最后，我们会介绍一下打包代码到原生app的一些比较好的工具。  &lt;br /&gt;
&lt;/p&gt;
 &lt;h2&gt;什么是混合模式移动应用&lt;/h2&gt;
 &lt;p&gt;移动app可以大致被分为三种，native、hybrid和web app。如果使用native app，你可以使用设备和操作系统的所有能力，同时，平台的性能负荷最小。然而，构建web app可以让你的代码跨平台，使得开发时间和成本大大减少。而hybrid app把这两者的优点都结合起来，使用一套共同代码，在许多不同的平台上部署类似原生的app。&lt;/p&gt;
 &lt;p&gt;有两种构建hybrid app的方法：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;Webview app：HTML,CSS和Javascript基础代码在一个内部的浏览器（叫做WebView）中运行，这个浏览器打包在一个原生的app中，一些原生的API可以通过这个包被Javascript获得，比如   &lt;a href="http://phonegap.com"&gt;Adobe PhoneGap&lt;/a&gt;和   &lt;a href="https://trigger.io"&gt;Trigger.io&lt;/a&gt;。&lt;/li&gt;
  &lt;li&gt;被编译的hybrid app：用一种语言编写代码（如C#或者Javascript），对于每一种支持的平台都把代码编译进原生代码中，这样做的结果是，每一个平台都有一个原生的app，但是在开发过程中少了一些自由空间。可以看一下这些例子，   &lt;a href="https://xamarin.com/"&gt;Xamarin&lt;/a&gt;，   &lt;a href="http://www.appcelerator.com/titanium/"&gt;Appcelerator Titanium&lt;/a&gt;，   &lt;a href="http://www.embarcadero.com/products/rad-studio/firemonkey"&gt;Embarcadero FireMonkey&lt;/a&gt;。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;这两种方法都被广泛使用，存在即合理，  &lt;strong&gt;不过今天我们只关注WebView app&lt;/strong&gt;，因为WebView app可以让开发人员平衡他们现有的网页技术。我们来看一下hybrid app相对于native app和web app的各种优点和缺点。&lt;/p&gt;
 &lt;h3&gt;优点&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;开发人员可以使用现有的网页技术&lt;/li&gt;
  &lt;li&gt;对于多种平台使用一套基础代码&lt;/li&gt;
  &lt;li&gt;减少开发时间和成本&lt;/li&gt;
  &lt;li&gt;使用响应式网页设计可以非常简便的设计出多样的元素（包括平板）&lt;/li&gt;
  &lt;li&gt;一些设备和操作系统特征的访问&lt;/li&gt;
  &lt;li&gt;高级的离线特性&lt;/li&gt;
  &lt;li&gt;可见度上升，因为app可以原生发布（通过app store），也可以发布给移动端浏览器（通过搜索引擎）&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;缺点&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;某些特定app的性能问题（那些依赖于复杂的原生功能或者繁重的过渡动画的app，如3D游戏）&lt;/li&gt;
  &lt;li&gt;为了模拟native app的UI和感官所增加的时间和精力&lt;/li&gt;
  &lt;li&gt;并不完全支持所有的设备和操作系统&lt;/li&gt;
  &lt;li&gt;如果app的体验并不够原生化，有被Apple拒绝的风险（比如说一个简单的网站）&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;这些缺点比较显著，不能忽略，它们告诉我们，并不是所有的app都适合混合模式，你需要小心的预计你的目标用户、他们对平台的选择和对app的需求。对于许多app来说，好处都是大于坏处的，比如内容驱动的app。&lt;/p&gt;
 &lt;p&gt;Hojoki和CatchApp都是内容驱动的app，所以我们一开始觉得它们非常适合混合模式的开发方式。我们之前提到的好处中的前三点对于我们构建Hojoki的移动app帮助很大，不过也仅仅是4周的时间而已。显而易见，Hojoki的第一个版本缺失了很多重要的东西，接下来的时间里，我们都把精力扑在提升性能、对每一个平台制作自定义的UI和利用不同设备的高级特性上。那个时候积累的那些经验对于让app形似并神似native app很重要，下面我会尽可能多的分享一下我的经验。&lt;/p&gt;
 &lt;p&gt;那么，   &lt;strong&gt;怎么能让你的app形似并神似一个原生的app呢？&lt;/strong&gt;对于一个移动网页开发人员来说，能够使用设备和操作系统的能力，能够打包他们的app，这些都听上去很棒。然后，如果要用户相信这是一个native app，那么它就必须长得像并且表现的像。如何完成这一点对于混合模式移动开发人员来说仍然是最大的挑战之一。&lt;/p&gt;
 &lt;h2&gt;让你的用户宾至如归&lt;/h2&gt;
 &lt;p&gt;虽然我们只写一套基础代码，但这并不意味着多种不同平台上的感官都要完全一样，你们用户根本不在乎什么潜在的跨平台技术，他们只想要app根据他们的期望来展现，他们想要“宾至如归”。你的第一步应该是为每一个平台做设计概览：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;“   &lt;a href="https://developer.apple.com/library/ios/navigation/"&gt;IOS设计资源&lt;/a&gt;”, IOS开发人员库&lt;/li&gt;
  &lt;li&gt;“   &lt;a href="http://developer.android.com/design/index.html"&gt;Android设计&lt;/a&gt;”, Android开发人员&lt;/li&gt;
  &lt;li&gt;“   &lt;a href="https://dev.windowsphone.com/design"&gt;设计&lt;/a&gt;”, Windows开发中心&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;虽然这些概览并不能完美适应全部的app，但是它们仍然提供了一套非常全面和标准的界面和体验，每一种平台的用户都会希望得到这样的体验。&lt;/p&gt;
 &lt;h3&gt;DIY VS. UI框架&lt;/h3&gt;
 &lt;p&gt;如果你一个人实施这些组件、样式和动画，这是个很大的挑战，现在有各种各样的UI框架来帮助你，从商业（  &lt;a href="http://www.telerik.com/kendo-ui1"&gt;Kendo UI&lt;/a&gt;）的到开放（  &lt;a href="http://ionicframework.com"&gt;lonic&lt;/a&gt;）的，从共同UI（  &lt;a href="http://jquerymobile.com"&gt;JQuery Mobile&lt;/a&gt;和  &lt;a href="http://onsen.io"&gt;Onsen UI&lt;/a&gt;）到许多有平台针对性的UI（  &lt;a href="http://www.sencha.com/products/touch/"&gt;Sencha Touch&lt;/a&gt;和  &lt;a href="http://chocolatechip-ui.com"&gt;ChocolateChip-UI&lt;/a&gt;）。有些能够很好的提供精确到像素的布局，有些则相对粗糙，这些各式各样的框架能够很方便的让使用者定义一个web app。然而，就我的观念而言，框架最主要的缺点关乎性能，因为大多数UI框架都尽量“海纳百川”，要根据自己的情况在设备上试试demo后再决定是否要使用。&lt;/p&gt;
 &lt;p&gt;在制作Hojoki的时候，我们尝试自己用CSS3和极少的Javascript来创建所有的组件，这样做的好处是能够帮助我们控制性能，减少负荷。当然，我们也会使用一些别人使用过的较小的库来解决一下复杂的任务。&lt;/p&gt;
 &lt;h3&gt;自定义UI组件&lt;/h3&gt;
 &lt;p&gt;自定义UI组件也有很多很好的使用例子，你需要根据你的目标用户来决定使用平台的UI还是自定义UI，如果你想要单干，你需要对UX设计有很深的理解，因为之前的那些概览都是专家们为了迎合他们平台用户的需求而制作的。&lt;/p&gt;
 &lt;p&gt;不管你是决定坚持使用平台的UI概览还是自己做自定义的组件，你都必须知道，有一些特定的设计样式是用户每天使用并热爱的。通常我们如何把一个app介绍给用户呢？通过幻灯片讲演或者教学覆盖。用户如何导航？如果标签栏或者  &lt;a href="https://github.com/jakiestfu/Snap.js"&gt;侧边栏&lt;/a&gt;。用户如何快速加载或者刷新数据？下拉刷新。（在接下来的文章中会讲到类似原生的滚动）&lt;/p&gt;
 &lt;h3&gt;移动端UI设计的资源&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;“   &lt;a href="http://sixrevisions.com/user-interface/mobile-ui-design-patterns-inspiration/"&gt;移动端UI设计样式：10几个灵感迸发的网站&lt;/a&gt;”，Jacob Gube，Six Revisions&lt;/li&gt;
  &lt;li&gt;“   &lt;a href="http://c2prods.com/2013/cloning-the-ui-of-ios-7-with-html-css-and-javascript/"&gt;用HTML、CSS和Javascript克隆IOS 7的UI&lt;/a&gt;“，Côme Courteault&lt;/li&gt;
  &lt;li&gt;“   &lt;a href="http://de.slideshare.net/yaelsahar/tapping-into-mobile-ui-with-html5"&gt;用HTML5点进移动端UI&lt;/a&gt;”（幻灯片），Luke Melia and Yael Sahar, Slideshare&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;设计一个看起来原生的标题栏&lt;/h2&gt;
 &lt;p&gt;在UI中，标题栏是一个很重要的部分，包括它的标题、导航元素、尤其是前进和后退按钮。对于我来说，许多流行框架在提供HTML和CSS解决方案方面，相比一些原生的app是失败的，而为每个平台用最小的DOM和最少行的css代码来仿照这个UI部分其实相当的简单.&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;html   &lt;br /&gt;
&amp;lt;header&amp;gt;   &lt;br /&gt;
&amp;lt;button class=&amp;quot;back&amp;quot;&amp;gt;Feed&amp;lt;/button&amp;gt;   &lt;br /&gt;
&amp;lt;h1&amp;gt;Details&amp;lt;/h1&amp;gt;   &lt;br /&gt;
&amp;lt;!-- more actions (e.g. a search button on the right side) --&amp;gt;   &lt;br /&gt;
&amp;lt;/header&amp;gt;&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;在JSFiddle中查看“  &lt;a href="http://ued.ctrip.com/(http://jsfiddle.net/prud/dnebx02p/)"&gt;IOS、Android和Windows Phone中看起来原生的标题栏&lt;/a&gt;”的完整代码，下面是我的成果：&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://www.smashingmagazine.com/wp-content/uploads/2013/05/02-html-header-new-opt.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;em&gt;用html5和css做成的看起来原生的标题栏&lt;/em&gt;&lt;/p&gt;
 &lt;p&gt;在不同的平台上使用相同的DOM更为便利，因为代码整洁而且易于维护，我发现这样做对于许多IOS和Android上的UI组件都适用(包括标题栏、标签栏、定制的导航菜单、设置页面、浮层，还有很多其他的东西)。然而，想要更多的支持Windows Phone变得更加困难，因为它带来了许多非常不一样的设计模块。&lt;/p&gt;
 &lt;h2&gt;支持高分辨率屏幕&lt;/h2&gt;
 &lt;p&gt;现如今，高分辨率的智能手机和平板构成了巨大的移动设备市场，在  &lt;a href="http://david-smith.org/iosversionstats/#retina"&gt;ios设备中占有率超过80%&lt;/a&gt;，在  &lt;a href="http://developer.android.com/about/dashboards/index.html#Screens"&gt;android设备中占有率超过70%&lt;/a&gt;。为了让你设备上的图片展现得更清晰，你通常不得不将其尺寸放大到超过它原本大小的两倍，因此现在响应式网站设计中，如何针对所有不同的分辨率提供适合尺寸的图片，成为了现在热议的话题之一。现在有非常多的途径解决，每一种的优点和缺点都与带宽、代码易维护性和浏览器的兼容性有关，现在让我们来快速的回顾一下当下最流行的方法，顺序不分先后：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;服务端的调整和传输&lt;/li&gt;
  &lt;li&gt;客户端通过javascript的检测和替换&lt;/li&gt;
  &lt;li&gt;html5的picture元素&lt;/li&gt;
  &lt;li&gt;html5 的srcset属性&lt;/li&gt;
  &lt;li&gt;css image-set属性&lt;/li&gt;
  &lt;li&gt;css media queries&lt;/li&gt;
  &lt;li&gt;可伸缩矢量图形(SVG)&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;一直以来，针对响应式图片都没有一个完美的方法，这主要还是取决于图片的类型和它们在app上的展现使用方式。如果是静态图片(比如logo和教程图片)，我尽量使用SVG，它们能不费吹灰之力的完美缩放，并且  &lt;a href="http://caniuse.com/#feat=svg"&gt;只要你是Android 3+就能获得很好的浏览器支持&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;当你不能选择SVG的时候，  &lt;a href="http://responsiveimages.org/"&gt;html5的picture元素和srcset属性&lt;/a&gt;一定会成为日后前端开发人员的首选。当下，它们最大的不足就是在浏览器上的支持太局限，因此他们需要一些插件.&lt;/p&gt;
 &lt;p&gt;同时，  &lt;a href="http://www.uifuel.com/hd-retina-display-media-queries/"&gt;css背景图片和media queries&lt;/a&gt;是比较可靠的解决方案:&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;css   &lt;br /&gt;
/* Normal-resolution CSS */   &lt;br /&gt;
.logo {   &lt;br /&gt;
width: 120px;   &lt;br /&gt;
background: url(logo.png) no-repeat 0 0;   &lt;br /&gt;
}   &lt;br /&gt;
/* HD and Retina CSS */   &lt;br /&gt;
@media   &lt;br /&gt;
only screen and (-webkit-min-device-pixel-ratio: 1.25),   &lt;br /&gt;
only screen and ( min--moz-device-pixel-ratio: 1.25),   &lt;br /&gt;
only screen and ( -o-min-device-pixel-ratio: 1.25/1),   &lt;br /&gt;
only screen and ( min-device-pixel-ratio: 1.25),   &lt;br /&gt;
only screen and ( min-resolution: 200dpi),   &lt;br /&gt;
only screen and ( min-resolution: 1.25dppx) {   &lt;br /&gt;
.logo {   &lt;br /&gt;
background: url(logo@2x.png) no-repeat 0 0;   &lt;br /&gt;
background-size: 120px; /* Equal to normal logo width */   &lt;br /&gt;
}   &lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;但是，你的app也许已经包含了许多内容(比如新闻文章)，要调整所有的图片标签或者用css替代会让我们筋疲力竭，在这种情况下，服务端解决方案就会是最好的选择。&lt;/p&gt;
 &lt;p&gt;从去年开始，越来越多的android系统已经离XXHDPI(超高分辨率)屏幕又进了一步。不论上面提到的哪种方案更适合你的需要，你要记住的是你需要用到三倍于原图大小的图片来支持android的最新的设备。&lt;/p&gt;
 &lt;h2&gt;使用系统字体&lt;/h2&gt;
 &lt;p&gt;使用系统字体是一种让用户体感到宾至如归的一种简单但是重要的方法。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://www.smashingmagazine.com/wp-content/uploads/2013/05/03-native-fonts-new-opt.png"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;em&gt;   &lt;a href="http://iosfonts.com/"&gt;ios&lt;/a&gt;、   &lt;a href="http://developer.android.com/design/style/typography.html"&gt;android&lt;/a&gt;和   &lt;a href="http://msdn.microsoft.com/library/windows/apps/hh700394.aspx#ux_font_choice"&gt;windows&lt;/a&gt;的原生字体&lt;/em&gt;&lt;/p&gt;
 &lt;p&gt;主流平台上，我比较推荐这些字体样式：&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;/* iOS */   &lt;br /&gt;
font-family: &amp;apos;Helvetica Neue&amp;apos;, Helvetica, Arial, sans-serif;&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;/* Android */   &lt;br /&gt;
font-family: &amp;apos;RobotoRegular&amp;apos;, &amp;apos;Droid Sans&amp;apos;, sans-serif;   &lt;br /&gt;
&lt;/code&gt;  &lt;br /&gt;
  &lt;code&gt;/* Windows Phone */   &lt;br /&gt;
font-family: &amp;apos;Segoe UI&amp;apos;, Segoe, Tahoma, Geneva, sans-serif;   &lt;br /&gt;
&lt;/code&gt;  &lt;br /&gt;
此外，ios7提供了一些有趣的预处理，这些预处理可以自动的设置正确的字体、文字大小和行高，在普通文本中应用  &lt;code&gt;font:-apple-system-body&lt;/code&gt;,在标题中使用  &lt;code&gt;font:-apple-system-headline&lt;/code&gt;，这样不仅简化了文字的声明，而且还提升了  &lt;a href="http://support.apple.com/kb/HT5956"&gt;动态类型&lt;/a&gt;（这是Apple系统范围的字号设置）的可访问性，你可以在  &lt;a href="http://mir.aculo.us/2013/09/16/how-to-create-a-web-app-that-looks-like-a-ios7-native-app-part-1/"&gt;Thomas Fuchs的文章&lt;/a&gt;中了解到更多关于ios7的字体预处理。&lt;/p&gt;
 &lt;h2&gt;一个图标胜过千言万语&lt;/h2&gt;
 &lt;p&gt;图像学在所有主流移动平台的用户体验上是一个重要的部分。相比字体，你一定更愿意使用用户已知的icon，回顾一下我之前说过的高分辨率屏幕，要确保你的icon的大小是可调节的，将它们作为字体通过css的  &lt;code&gt;@font-face&lt;/code&gt;来实现，浏览器会有很好的兼容性支持，你甚至可以通过css改变icon的样式（比如颜色、阴影和透明度)。以下是我的推荐:&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;获取多个平台的icon字体   &lt;a href="http://ionicons.com"&gt;Ionicons&lt;/a&gt;是我们的基本设置，因为它几乎包含了所有我们需要的东西。除了他们常用的一些icon之外，还包含了ios和android的一些特殊的icon，其余的来源于   &lt;a href="http://ios7-icon-font-demo.herokuapp.com/"&gt;ios&lt;/a&gt;、Android   &lt;a href="http://www.spiderflyapps.com/downloads/android-developer-icons-the-font/"&gt;set 1&lt;/a&gt;和   &lt;a href="https://github.com/Turbo87/Android-Action-Bar-Icon-Pack-Font"&gt;set 2&lt;/a&gt;以及   &lt;a href="http://modernuiicons.com/"&gt;Windows Phone&lt;/a&gt;的特殊icon字体.&lt;/li&gt;
  &lt;li&gt;将它们用icon字体生产器结合起来用不同的icon字体让我们感觉非常混乱，还会迅速的增加文件大小，这就是我们为什么使用   &lt;a href="http://fontello.com/"&gt;Fontello&lt;/a&gt;来结合不同字体、调整代码和针对每个平台输出的原因。这样的结果就是   &lt;code&gt;&amp;lt;span class=&amp;quot;icon&amp;quot;&amp;gt;s&amp;lt;/span&amp;gt;&lt;/code&gt;在IOS、Android和Windows Phone中看起来是一个搜索图标。同时，还可以了解一些其他比较流行的方案，比如   &lt;a href="https://icomoon.io/app/"&gt;IcoMoon&lt;/a&gt;和   &lt;a href="http://fontastic.me/"&gt;Fontastic&lt;/a&gt;。&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;在 Windows Phone上,你还可以  &lt;a href="http://msdn.microsoft.com/library/windows/apps/jj841126.aspx"&gt;脱离Native&lt;/a&gt;  &lt;code&gt;font-family: &amp;apos;Segoe UI Symbol&amp;apos;&lt;/code&gt;。&lt;/p&gt;
 &lt;h2&gt;性能优化&lt;/h2&gt;
 &lt;p&gt;性能经常被认为是hybrid移动app中一个主要的缺陷，尤其当你的app有大量的动画，包含大量的滚动列表并且需要在旧设备上运行的时候，缺点会越发的明显。然而，如果你觉得能够接受只支持一些比较新的平台版本(Android 4+,iOS 7+和Windows Phone 8+)的话，那你应该就会看到满意的效果。最终的问题就在于你在优化DOM和CSS选择器、书写高性能的Javascript、减少渲染时间和最少化重排重绘上花了多少工夫。关于移动网页性能的文章和教程一大把，以下是我最喜欢的一些:&lt;/p&gt;
 &lt;p&gt;“  &lt;a href="http://www.tricedesigns.com/2013/03/11/performance-ux-considerations-for-successful-phonegap-apps/"&gt;成功PhoneGap App的性能和UX考虑因素&lt;/a&gt;”，Andrew Trice  &lt;br /&gt;
“  &lt;a href="http://estelle.github.io/mobileperf/#slide1"&gt;移动：网页性能&lt;/a&gt;” (幻灯片)，Estelle Weyl  &lt;br /&gt;
“  &lt;a href="http://www.smashingmagazine.com/2012/11/05/writing-fast-memory-efficient-javascript/"&gt;书写快速、内存高效的Javascript&lt;/a&gt;,” Addy Osmani, Smashing Magazine  &lt;br /&gt;
“  &lt;a href="https://developers.google.com/speed/articles/reflow"&gt;浏览器重排最少化&lt;/a&gt;,” Lindsey Simon, Google Developers  &lt;br /&gt;
“  &lt;a href="http://www.smashingmagazine.com/2013/04/03/build-fast-loading-mobile-website/"&gt;如何让你的网站在移动设备上运行更快&lt;/a&gt;,” Johan Johansson, Smashing Magazine&lt;/p&gt;
 &lt;p&gt;此外，随着每天都有新的设备推出，移动硬件和渲染引擎都在以一个非常迅猛的速度提升，开发者能够做到使iPhone5系列、Android手机与Nexus4和5的纯原生App的性能上基本一致。&lt;/p&gt;
 &lt;h2&gt;提升感知速度&lt;/h2&gt;
 &lt;p&gt;构建高效的app是一回事而，让app感觉上运行很快又是另一回事儿。无论你的app是否需要一些时间来完成某项任务(比如一些复杂的计算或者客户端和服务器端的交流)，实时反馈对于提供流畅和响应式体验至关重要。一个比较常用的方法是，在用户还不需要某些功能的时候推迟加载，对用户接下来可能进行的操作作预估和预加载。Instagram有一个著名的例子，当用户忙于添加标签和分享的时候，  &lt;a href="http://www.cultofmac.com/164285/the-clever-trick-instagram-uses-to-upload-photos-so-quickly/"&gt;在后台上传图片&lt;/a&gt;。感知速度和真正的速度是不一样的，让我们合理运用它。这里有一些非常简单的例子：&lt;/p&gt;
 &lt;h3&gt;消除触屏设备上点击的延迟&lt;/h3&gt;
 &lt;p&gt;触屏设备中的一个普通Javascript点击事件，从点击的最开始到得到响应会有轻微的延迟(大约300毫秒)，浏览器的这种行为是在判断用户是单击还是双击，如果你不需要“双击以放大”特性，你可以安全的消除这300毫秒从而换取更多响应操作，我最喜欢的解决方案是  &lt;a href="https://github.com/ftlabs/fastclick"&gt;FastClick&lt;/a&gt;库，你可以把它用在除了IE的所有浏览器上：&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;js   &lt;br /&gt;
if (&amp;apos;ontouchstart&amp;apos; in window) {   &lt;br /&gt;
window.addEventListener(&amp;apos;load&amp;apos;, function() {   &lt;br /&gt;
FastClick.attach(document.body);   &lt;br /&gt;
}, false);   &lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;IE10以上比较容易解决,你只需要添加一些css代码:&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;css   &lt;br /&gt;
html {   &lt;br /&gt;
-ms-touch-action: manipulation; /* IE 10 */   &lt;br /&gt;
touch-action: manipulation; /* IE 11+ */   &lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
 &lt;h3&gt;设计点击状态的样式&lt;/h3&gt;
 &lt;p&gt;只要用户点击一些可操作的元素（例如按钮或者链接），app检测到以后应该马上给他们一些回应。就像在台式机上表现不错的css的伪类  &lt;code&gt;:hover&lt;/code&gt;，在移动端你需要换成  &lt;code&gt;:active&lt;/code&gt;或者一些javascript解决方案。我曾经在JSFiddle上比较过三种  &lt;a href="http://jsfiddle.net/prud/x9y6cfhg/"&gt;点击状态的方案&lt;/a&gt;，你可以根据你的实际情况使用。&lt;/p&gt;
 &lt;p&gt;还有，记得在调整移动端点击状态的时候清楚默认点击高亮的样式，此外我建议禁用用户在一些活动的元素上选择，因为如果用户不小心点击按钮的时间过长，出现的选择菜单会很烦人。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;iOS and Android:&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;css   &lt;br /&gt;
button {   &lt;br /&gt;
outline: 0;   &lt;br /&gt;
-webkit-tap-highlight-color: rgba(0,0,0,0);   &lt;br /&gt;
-webkit-tap-highlight-color: transparent;   &lt;br /&gt;
-webkit-touch-callout: none;   &lt;br /&gt;
-webkit-user-select: none;   &lt;br /&gt;
-moz-user-select: none;   &lt;br /&gt;
-ms-user-select: none;   &lt;br /&gt;
user-select: none;   &lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;Windows Phone 8+:&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;html   &lt;br /&gt;
&amp;lt;meta name=&amp;quot;msapplication-tap-highlight&amp;quot; content=&amp;quot;no&amp;quot;&amp;gt;&lt;/code&gt;&lt;/p&gt;
 &lt;h3&gt;提示加载&lt;/h3&gt;
 &lt;p&gt;你的app总是需要一些时间来完成动作，即使只有一秒，所以要考虑添加加载提示，否则用户就可能认为有时候app卡住了，或者在不应该点击的时候乱点，甚至他们可能会乱砸东西并且归责于你的app。根据我的经验，移动端浏览器运用gif动画不是一个好方法。一旦CPU上有一个加载项，gif卡住了，那么这个GIF对用户的加载提示就完全没有作用了。我更喜欢  &lt;a href="http://fgnass.github.io/spin.js/"&gt;Spin.js&lt;/a&gt;，因为可以自己配置并且运用简单，当然，还有一些其他的方法：  &lt;a href="http://www.queness.com/post/9150/9-javascript-and-animated-gif-loading-animation-solutions"&gt;javascript解决方案&lt;/a&gt;和  &lt;a href="http://tympanus.net/codrops/2012/11/14/creative-css-loading-animations/"&gt;css加载方案&lt;/a&gt;。&lt;/p&gt;
 &lt;p&gt;一些跨平台的工具比如PhoneGap和Trigger.io也提供一些原生的加载状态，对于全屏动画加载的展现很棒。&lt;/p&gt;
 &lt;h2&gt;正确设置滚动&lt;/h2&gt;
 &lt;p&gt;滚动在许多app中是决定用户体验的最重要因素之一，它让人又爱又恨，因为要实现这一点取决于你应用依赖的滚动细节以及需要手机系统支持。&lt;/p&gt;
 &lt;p&gt;几乎所有的app都使用了可滚动内容和固定头部和/或底部。通常有两个CSS方法来实现：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;在   &lt;code&gt;body&lt;/code&gt;上启用滚动，在header上增加   &lt;code&gt;position: fixed&lt;/code&gt;；&lt;/li&gt;
  &lt;li&gt;在   &lt;code&gt;body&lt;/code&gt;上禁用滚动，在内容上增加   &lt;code&gt;overflow: scroll&lt;/code&gt;；&lt;/li&gt;
  &lt;li&gt;在   &lt;code&gt;body&lt;/code&gt;上禁用滚动，在内容上增加JavaScript默认滚动。&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;虽然第一种方法有一些优点（例如IOS的原生滚动到顶部动作以及简洁的代码结构），我强烈推荐第二种方法：  &lt;code&gt;overflow: scroll&lt;/code&gt;。这个方法  &lt;a href="http://remysharp.com/2012/05/24/issues-with-position-fixed-scrolling-on-ios/"&gt;渲染问题更少&lt;/a&gt;（虽然还是比较多），现代平台上的浏览器支持更好（Android 4+，IOS 5+和Windows Phone 8+)，对于低版本浏览器有  &lt;a href="https://github.com/filamentgroup/Overthrow#browser-support"&gt;方便的小插件&lt;/a&gt;。另外，你可以把  &lt;code&gt;overflow: scroll&lt;/code&gt;换成自定义的滚动库（第三种选择），例如  &lt;a href="http://iscrolljs.com/"&gt;iScroll&lt;/a&gt;。虽然这些JavaScript解决方案使得特性更加灵活（例如，带动量效果的滚动位置，事件处理，可定制的效果和滚动条等），但它们通常会影响性能。当你在内容里用了许多DOM节点和/或CSS效果（例如  &lt;code&gt;box-shadow&lt;/code&gt;，  &lt;code&gt;text-shadow&lt;/code&gt;,  &lt;code&gt;opacity&lt;/code&gt;和  &lt;code&gt;rgba&lt;/code&gt;)时会很危险。&lt;/p&gt;
 &lt;p&gt;让我们来看一些基本的滚动特性。&lt;/p&gt;
 &lt;h3&gt;动量效果&lt;/h3&gt;
 &lt;p&gt;触摸友好的动量效果使得用户在大块内容区域的快速滚动显得很直观。通过一些简单的CSS就能在IOS 5+以及Android上一些版本的Chrome中激活。在IOS上，这也会使得内容不溢出顶部和底部边界。&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;css   &lt;br /&gt;
overflow-y: scroll;   &lt;br /&gt;
-webkit-overflow-scrolling: touch;&lt;/code&gt;&lt;/p&gt;
 &lt;h3&gt;下拉刷新&lt;/h3&gt;
 &lt;p&gt;网页上有许多实现这个效果的方法，例如  &lt;a href="http://damien.antipa.at/2012/10/16/ios-pull-to-refresh-in-mobile-safari-with-native-scrolling/"&gt;Damien Antipa&lt;/a&gt;写的一种。这个方法在IOS和Windows Phone中效果和体验很相似，Android最近发布它特有的结构（如下）。我们通过一些JavaScript和CSS keyframes在CatchApp里实现了这个效果。（我还没有总结好放到Github上，所以还在调整！）&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://www.smashingmagazine.com/wp-content/uploads/2013/05/04-pull-ios-opt.jpg"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;em&gt;IOS中的下拉刷新。 (图片属于:    &lt;a href="http://damien.antipa.at/2012/10/16/ios-pull-to-refresh-in-mobile-safari-with-native-scrolling/"&gt;Damien Antipa&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://www.smashingmagazine.com/wp-content/uploads/2013/05/05-pull-wp-opt.gif"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;em&gt;Android中的下拉刷新。 (图片属于:    &lt;a href="http://androidwidgetcenter.com/android-tips/how-to-refresh-gmail-on-android/"&gt;Android Widget Center&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://www.smashingmagazine.com/wp-content/uploads/2013/05/06-pull-android-opt.jpg"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;em&gt;Windows Phone中的下拉刷新。 (图片属于:    &lt;a href="http://dwcares.com/pull-to-refresh-2/"&gt;David Washington&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
 &lt;h3&gt;滚动回到顶部&lt;/h3&gt;
 &lt;p&gt;不幸的是，在  &lt;code&gt;body&lt;/code&gt;上禁用滚动的同时会破坏IOS中允许用户通过点击状态栏快速回到页面顶部的原生特性。我写了一小段可以添加在任何元素上的脚本来使用JavaScript解决  &lt;a href="https://github.com/prud/ios-overflow-scroll-to-top"&gt;滚动到顶部的问题&lt;/a&gt;，即便内容当前处于动量效果中。把它添加到手机端网页头部或通过原生插件添加到状态栏上（例如，PhoneGap）。&lt;/p&gt;
 &lt;p&gt;许多其他滚动的特性可以通过原生  &lt;code&gt;overflow: scroll&lt;/code&gt;实现，例如关闭特定元素或只是无限滚动。如果需求更加复杂，一定考虑使用JavaScript方法。&lt;/p&gt;
 &lt;h2&gt;让点击更容易&lt;/h2&gt;
 &lt;p&gt;用户触摸时，很容易跟目标偏差几个像素，尤其是点击小按钮时（例如IOS顶部条上的按钮）。开发者可以在保证设计的情况下通过在小目标周围开启不可见触摸区域来使用户体验更好。&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;html   &lt;br /&gt;
&amp;lt;button&amp;gt;   &lt;br /&gt;
&amp;lt;div class=&amp;quot;innerButton&amp;quot;&amp;gt;Click me!&amp;lt;/div&amp;gt;   &lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;你需要在按钮元素上绑定事件处理器，同时用  &lt;code&gt;div.innerButton&lt;/code&gt;定义样式。在JSFiddle上查看  &lt;a href="http://jsfiddle.net/prud/r7kqr1a3/"&gt;完整的，含有CSS&lt;/a&gt;的例子。&lt;/p&gt;
 &lt;h2&gt;使用触摸手势&lt;/h2&gt;
 &lt;p&gt;智能手机的精髓就是触摸和手势。在和触摸设备交互时，我们总是滑动，按压，缩放，拖动和长按。所以，为什么不提供相同的方式来让用户控制你的hybird应用呢？  &lt;a href="http://quojs.tapquo.com/"&gt;QuoJS&lt;/a&gt;和  &lt;a href="http://hammerjs.github.io/"&gt;Hammer.js&lt;/a&gt;是广为人知的支持所有手势类型的库。如果你想要更多选择，看一下Kevin Liew对”  &lt;a href="http://www.queness.com/post/11755/11-multi-touch-and-touch-events-javascript-libraries"&gt;11个多点触摸和触摸事件JavaScript库&lt;/a&gt;“的比较。&lt;/p&gt;
 &lt;h2&gt;不要忘了原生功能&lt;/h2&gt;
 &lt;p&gt;用网页技术构建你的应用并不意味着你不能用原生特性。事实上，所有主要的跨平台开发工具提供了提供了内置的对重要功能的接口。其中有许多API包括调用设备数据，文件系统，网络连接，地理位置定位，加速度传感器，提示（包括推送）等等。&lt;/p&gt;
 &lt;p&gt;通常，你甚至可以通过构建自定义插件来扩展开发工具。在Hojoki,我们加入了许多缺失的特性，包括读取用户对于我们app的推送提示的设置，读取用户时区，检查是否安装第三方APP并启动。让我们来看两个关于用原生插件实现的效果的例子。首先，让我们对IOS 6+里的input启动JavaScript  &lt;code&gt;focus（）&lt;/code&gt;：&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;js   &lt;br /&gt;
if ([[[UIDevice currentDevice] systemVersion] floatValue] &amp;gt;= 6) {   &lt;br /&gt;
[YourWebView setKeyboardDisplayRequiresUserAction:NO];   &lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
 &lt;p&gt;下面是在IOS上把给定字符串复制到设备剪贴板里的代码：&lt;/p&gt;
 &lt;p&gt;  &lt;code&gt;[[UIPasteboard generalPasteboard] setString:@&amp;quot;Your copied string&amp;quot;];&lt;/code&gt;&lt;/p&gt;
 &lt;h2&gt;总要留有出口&lt;/h2&gt;
 &lt;p&gt;网页开发者经常忽视如何处理hybird应用中的糟糕情况（例如，连接超时，错误输入，时间问题等等）。hybird应用从根本上区别于网站，主要因为它没有全局刷新按钮，在一些移动端操作系统里应用很容易在后台运行数周。如果用户死机了，他们唯一的选择是重启应用，这势必要强制退出然后重启。许多人甚至不知道怎样重启，尤其是在Android 2.x上（它深深隐藏在app设置里）和IOS 6及以下版本上（你需要双击home键，长按图标并且关闭它）。&lt;/p&gt;
 &lt;p&gt;所以，在开发中先不要觉得有刷新按钮就万事大吉而不考虑出错的情况，我们应该做的是遇到问题就立即解决。对于其他所有意外的情况，例如包含客户端-服务端的通信，准备好应对错误情况，给用户提供一个出口。可以简单得显示一个全屏的错误信息-“欧！出了些问题。请检查你的连接并再次尝试”-下面放一个大大的“重新载入”按钮。&lt;/p&gt;
 &lt;h2&gt;如何打包&lt;/h2&gt;
 &lt;p&gt;开发hybrid移动app就需要用到通常开发（移动）网站一样的工具，开发流程也一样。虽然这么说，我真正喜欢hybrid的地方是你能比较轻松地使用HTML、CSSS和JavaScript来部署移动web app。确保对原生特性实现回退，或在完全不支持该特性的情况下找到优雅的解决方案。大多数移动开发者更喜欢让用户群留在原生app上，甚至可以向使用移动网站的用户宣传这个app。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="Native WebView wrapper around a HTML/CSS/JavaScript code base." src="http://www.smashingmagazine.com/wp-content/uploads/2013/05/07-hybrid-app-opt.jpg"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;em&gt;基于HTML、CSSS和JavaScript的原生WebView打包器&lt;/em&gt;&lt;/p&gt;
 &lt;p&gt;那原生部分怎样呢？移动web app（纯的HTML、CSSS和JavaScript）将加载到一个WebView中。作为一个内部浏览器引擎，WebView会按照设备的默认浏览器渲染网页的方式渲染app（可能会存在细微差别——你遇到的情况可能有所不同）。而且，原生“应用开发平台”用来暴露设备和操作系统的特性，而JavaScript能通过API调用到这些特性。这个API通常包含有调用特性的接口，比如设备摄像头、通讯录、地理位置、文件系统和原生事件（比如通过Android的硬件按钮）等特性。&lt;/p&gt;
 &lt;p&gt;有一些跨平台的开发工具提供了原生应用开发平台，简化了整个打包流程。下面深入研究部分工具。&lt;/p&gt;
 &lt;h3&gt;PHONEGAP和APACHE CORDOVA&lt;/h3&gt;
 &lt;p&gt;  &lt;a href="http://phonegap.com/"&gt;PhoneGap&lt;/a&gt;绝对是一个最流行的跨平台开发工具之一，它的名字本身经常被当作hybrid移动app开发的同义词。&lt;/p&gt;
 &lt;p&gt;关于它的名字以及与  &lt;a href="http://cordova.io/"&gt;Apache Cordova&lt;/a&gt;的关系存在的  &lt;a href="http://phonegap.com/2012/03/19/phonegap-cordova-and-what%E2%80%99s-in-a-name/"&gt;一些误解&lt;/a&gt;是可以理解的。后者是顶级Apache项目，曾用名就是PhoneGap。它提供了一套设备API，并通过运行在WebView中的HTML、CSSS和JavaScript调用原生的功能。现在，Adobe PhoneGap是Cordova的一个分支——与Chrome使用Webkit作为其引擎没有什么不同。&lt;/p&gt;
 &lt;p&gt;两者都是开源和免费的，支持所有主流平台，拥有一个开发各类插件和扩展的活跃社区。&lt;/p&gt;
 &lt;p&gt;PhoneGap对塑造hybrid贡献巨大，涌现出的很多新的工具提供了  &lt;strong&gt;附加功能&lt;/strong&gt;，使开发流程简单。这些工具带来了很多便利：通过在云端构建app，免去了在本地安装所有不同平台的SDK和工具的工作。每个工具都有不同的关注点、平台支持度和价钱：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;a href="https://build.phonegap.com/"&gt;PhoneGap Build&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.telerik.com/appbuilder"&gt;Telerik AppBuilder&lt;/a&gt;（前身是Icenium）&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://www.appgyver.com/"&gt;AppGyver Steroids&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://appery.io/"&gt;Appery.io&lt;/a&gt;（前身是Tiggzi）&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://monaca.mobi/"&gt;Monaca&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;a href="https://software.intel.com/html5/tools"&gt;Intel XDK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;SENCHA TOUCH&lt;/h3&gt;
 &lt;p&gt;  &lt;a href="http://www.sencha.com/products/touch/"&gt;Sencha Touch&lt;/a&gt;最初是一个针对移动web的UI框架，存在有几年了。过去，开发者使用Sencha构建app需同时使用其他如PhoneGap这样的服务来部署成hybrid app。现在Sencha内置了这种功能，可免费使用。支持的平台有iOS和Android（都需要通过Sencha自有的原生打包工具），BlackBerry、Windows 8等更多（通过PhoneGap Build）。&lt;/p&gt;
 &lt;h3&gt;TRIGGER.IO&lt;/h3&gt;
 &lt;p&gt;在Hojoki，我们在两年半前开始用  &lt;a href="https://trigger.io/"&gt;Trigger.io&lt;/a&gt;，因为当时想找一个比PhoneGap轻量级的替代品。虽然它只支持iOS和Android平台，但它提供了一套很不错的原生API、自定义插件和第三方集成（包括Parse消息推送服务、Flurry分析器以及部分Facebook的SDK）。通过Trigger.io的命令行工具，可以将app打包集成到  &lt;a href="http://gruntjs.com/"&gt;Grunt&lt;/a&gt;的构建过程。如果喜欢自动化，这一点很棒。&lt;/p&gt;
 &lt;p&gt;它的一个重要特性是  &lt;a href="https://trigger.io/reload/"&gt;Reload&lt;/a&gt;，该特性能使开发者推送HTML、CSSS和JavaScript的更新到运行中的app。与PhoneGap Build的  &lt;a href="http://docs.build.phonegap.com/en_US/tools_hydration.md.html"&gt;Hydration&lt;/a&gt;不同，Reload专门为开发和生产app设计。这样就使得合法绕过Apple的提交流程去提交bug解决方案和用A/B测试快速迭代就成为可能。&lt;/p&gt;
 &lt;p&gt;对很多开发者来说，一旦14天的试用期结束，Trigger.io  &lt;a href="https://trigger.io/pricing/"&gt;极高的价格&lt;/a&gt;可能就是它最大的缺点。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://www.mosync.com/"&gt;MoSync&lt;/a&gt;似乎是另一种不与PhoneGap有瓜葛的工具，但不太确定当下它的开发活跃度怎样。&lt;/p&gt;
 &lt;h3&gt;在真机上测试&lt;/h3&gt;
 &lt;p&gt;显然，用web技术构建移动app会诱使我们在web浏览器上做大部分的测试。在开发非原生特性时还算说得过去，但在发布时一定要避免。提交app之前，要在尽量多的生产商、平台和各种机型各种版本上测试。Android的机型和版本太多，在浏览器渲染、特性支不支持和生产商更改上会千差万别。虽然iOS渲染的差异好很多，但Apple生产的不同尺寸、分辨率和像素密度的设备越来越多。想了解更多请点击查看“  &lt;a href="http://www.smashingmagazine.com/2014/07/14/testing-and-responsive-web-design/"&gt;设备优先级：测试和响应式web设计&lt;/a&gt;”。&lt;/p&gt;
 &lt;p&gt;在2012年，Facebook放弃绝大部分HTML5开发转向原生开发，其中一个主要原因是“  &lt;a href="http://lists.w3.org/Archives/Public/public-coremob/2012Sep/0021.html"&gt;缺少调试工具和开发者API&lt;/a&gt;”。半年后，  &lt;a href="http://venturebeat.com/2013/04/17/linkedin-mobile-web-breakup/"&gt;LinkedIn得出同样的结论&lt;/a&gt;，声称HTML5本身准备好了，但基础工具和生态系统还没来得及支持它。从我的角度来说，情况正变得越来越好：Android 4.4+支持WebView的远程调试；各平台的开发工具越来越多：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;“   &lt;a href="https://developer.apple.com/safari/tools/"&gt;Web检测器&lt;/a&gt;”，Safari（iOS）&lt;/li&gt;
  &lt;li&gt;“   &lt;a href="https://developer.chrome.com/devtools/docs/remote-debugging"&gt;使用Chrome在Android上远程调试&lt;/a&gt;”&lt;/li&gt;
  &lt;li&gt;“   &lt;a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh441472.aspx"&gt;在Visual Studio里调试商店app&lt;/a&gt;” (Windows Phone 8.1), Windows Dev Center&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://people.apache.org/~pmuellr/weinre/"&gt;Weinre&lt;/a&gt;（针对所有平台），Patrick Mueller&lt;/li&gt;
  &lt;li&gt;   &lt;a href="http://html.adobe.com/edge/inspect/"&gt;Edge Inspect&lt;/a&gt;（针对iOS和Android），Adobe&lt;/li&gt;
&lt;/ul&gt;
 &lt;h3&gt;开始考虑硬发布&lt;/h3&gt;
 &lt;p&gt;为web浏览器构建app时，为用户部署修复程序是简单的一步，这意味着测试会失去其重要性。当通过app商店发布app，这就需要重新考虑了。把它想成上世纪90年代的软件开发：你现在就生活在硬发布的世界里。&lt;/p&gt;
 &lt;p&gt;那么，为什么这很糟糕？首先，提交过程随便就是一两周（寨见，Apple！）。其次，即使修复程序很快发布，也不能保证用户在短时间更新app。以下是我的建议：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;测试的优先级要高。&lt;/li&gt;
  &lt;li&gt;有类似“强制更新”的逻辑来放弃旧有客户端版本。&lt;/li&gt;
  &lt;li&gt;使用类似Trigger.io的   &lt;a href="https://trigger.io/reload/"&gt;Reload&lt;/a&gt;的机制来修复运行中的代码。&lt;/li&gt;
  &lt;li&gt;如果想快点，申请   &lt;a href="https://developer.apple.com/appstore/contact/appreviewteam/index.html"&gt;紧急app审核&lt;/a&gt;。&lt;/li&gt;
&lt;/ol&gt;
 &lt;h3&gt;发布到商店&lt;/h3&gt;
 &lt;p&gt;上面提到的工具会为每个平台生成一个版本，然后将这些版本提交到相应的商店。从这点，过程和发布一个“普通”的原生app几乎一样。在这方面，有些已讨论过的工具可能有更好的文档。尽管这样，以下是官方指南：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;“   &lt;a href="https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/Introduction/Introduction.html"&gt;App分发指南&lt;/a&gt;”，Apple&lt;/li&gt;
  &lt;li&gt;“   &lt;a href="http://developer.android.com/distribute/googleplay/start.html"&gt;发布入门手册&lt;/a&gt;”和“   &lt;a href="http://developer.android.com/distribute/tools/launch-checklist.html"&gt;发布清单&lt;/a&gt;”，Android开发者&lt;/li&gt;
  &lt;li&gt;“   &lt;a href="http://msdn.microsoft.com/library/windows/apps/jj206736.aspx"&gt;Windows Phone发布&lt;/a&gt;”，Windows研发中心&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;结论&lt;/h2&gt;
 &lt;p&gt;既然开发的hybrid移动app在Apple的App商店和Google Play已经上线两年了，这里我就总结下在本文开头提到的一些优点和缺点。&lt;/p&gt;
 &lt;p&gt;对于我们这样一个资源有限、没有原生iOS和Android开发经验的创业公司，要在短短的几周内构建一个多平台的app是不可能的。选择hybrid，我们就能复用很多web app的代码，根据用户反馈迭代速度就快。我们已经成功发布了支持桌面Windows 8和微软Surface的原生app，支持Mac OS X的app也使用了基本一样的代码。移植到另一个平台的工作量很大程度上取决于给定浏览器与设备的能力和所需要的原生功能的水平高低。我们需要消息推送、app内置购买、获取用户联系方式，以及其他功能。根据你的需求，很多原生功能会使你很依赖于所选择的原生打包工具。&lt;/p&gt;
 &lt;p&gt;最后，我们来看看hybrid app是否真的能给出一个原生的感官享受。以下精选了来自app商店的用户评论。积极和消极的评论都有，其中很多消极的评论来自早期版本——各平台UI一样，性能相对较慢。&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;评论略去&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;的确，我们正远离特定平台的app开发而面向不断涌现的很多新技术。去年的Google I/O大会上被问到关于web的未来，  &lt;a href="http://youtu.be/9pmPa_KxsAM?t=2h56m6s"&gt;Larry Page说&lt;/a&gt;：&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;在很长一段时间，我不认为作为开发者的你会考虑是否为这个平台或那个平台或其他类似平台在开发。我认为你应该在更高的层次上工作，你所写的软件能在每个平台运行起来，而且是很容易地运行起来。&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;在这方面，（移动）web取得了很大的成功。使用这个平台而且仍然能在所有商店分发app是向前迈出的巨大一步。未来会发生什么敬请期待。无论发生什么，使用  &lt;a href="http://en.wikipedia.org/wiki/List_of_countries_by_number_of_Internet_users"&gt;世界上1/3人口&lt;/a&gt;（其中超过2/3来自欧洲和美国）依赖的技术大概不会是一个坏的选择。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>前端开发 html5 web 翻译</category>
      <guid isPermaLink="true">https://itindex.net/detail/52872-hybrid-%E7%A7%BB%E5%8A%A8%E5%BA%94%E7%94%A8-%E7%BD%91%E9%A1%B5</guid>
      <pubDate>Wed, 04 Mar 2015 10:21:47 CST</pubDate>
    </item>
    <item>
      <title>H5 缓存机制浅析 移动端 Web 加载性能优化</title>
      <link>https://itindex.net/detail/54832-h5-%E7%BC%93%E5%AD%98-%E7%A7%BB%E5%8A%A8</link>
      <description>&lt;p&gt;腾讯Bugly特约作者：贺辉超&lt;/p&gt;
 &lt;h3&gt;1 H5 缓存机制介绍&lt;/h3&gt;
 &lt;p&gt;H5，即 HTML5，是新一代的 HTML 标准，加入很多新的特性。离线存储（也可称为缓存机制）是其中一个非常重要的特性。H5 引入的离线存储，这意味着 web 应用可进行缓存，并可在没有因特网连接时进行访问。&lt;/p&gt;
 &lt;p&gt;H5 应用程序缓存为应用带来三个优势：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;p&gt;离线浏览 用户可在应用离线时使用它们&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;速度 已缓存资源加载得更快&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;减少服务器负载 浏览器将只从服务器下载更新过或更改过的资源。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;根据标准，到目前为止，H5 一共有6种缓存机制，有些是之前已有，有些是 H5 才新加入的。&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;浏览器缓存机制&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;Dom Storgage（Web Storage）存储机制&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;Web SQL Database 存储机制&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;Application Cache（AppCache）机制&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;Indexed Database （IndexedDB）&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;File System API&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;下面我们首先分析各种缓存机制的原理、用法及特点；然后针对 Anroid 移动端 Web 性能加载优化的需求，看如果利用适当缓存机制来提高 Web 的加载性能。&lt;/p&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;2 H5 缓存机制原理分析&lt;/h3&gt;
 &lt;h4&gt;2.1 浏览器缓存机制&lt;/h4&gt;
 &lt;p&gt;浏览器缓存机制是指通过 HTTP 协议头里的 Cache-Control（或 Expires）和 Last-Modified（或 Etag）等字段来控制文件缓存的机制。这应该是 WEB 中最早的缓存机制了，是在 HTTP 协议中实现的，有点不同于 Dom Storage、AppCache 等缓存机制，但本质上是一样的。可以理解为，一个是协议层实现的，一个是应用层实现的。&lt;/p&gt;
 &lt;p&gt;Cache-Control 用于控制文件在本地缓存有效时长。最常见的，比如服务器回包：Cache-Control:max-age=600 表示文件在本地应该缓存，且有效时长是600秒（从发出请求算起）。在接下来600秒内，如果有请求这个资源，浏览器不会发出 HTTP 请求，而是直接使用本地缓存的文件。&lt;/p&gt;
 &lt;p&gt;Last-Modified 是标识文件在服务器上的最新更新时间。下次请求时，如果文件缓存过期，浏览器通过 If-Modified-Since 字段带上这个时间，发送给服务器，由服务器比较时间戳来判断文件是否有修改。如果没有修改，服务器返回304告诉浏览器继续使用缓存；如果有修改，则返回200，同时返回最新的文件。&lt;/p&gt;
 &lt;p&gt;Cache-Control 通常与 Last-Modified 一起使用。一个用于控制缓存有效时间，一个在缓存失效后，向服务查询是否有更新。&lt;/p&gt;
 &lt;p&gt;Cache-Control 还有一个同功能的字段：Expires。Expires 的值一个绝对的时间点，如：Expires: Thu, 10 Nov 2015 08:45:11 GMT，表示在这个时间点之前，缓存都是有效的。&lt;/p&gt;
 &lt;p&gt;Expires 是 HTTP1.0 标准中的字段，Cache-Control 是 HTTP1.1 标准中新加的字段，功能一样，都是控制缓存的有效时间。当这两个字段同时出现时，Cache-Control 是高优化级的。&lt;/p&gt;
 &lt;p&gt;Etag 也是和 Last-Modified 一样，对文件进行标识的字段。不同的是，Etag 的取值是一个对文件进行标识的特征字串。在向服务器查询文件是否有更新时，浏览器通过 If-None-Match 字段把特征字串发送给服务器，由服务器和文件最新特征字串进行匹配，来判断文件是否有更新。没有更新回包304，有更新回包200。Etag 和 Last-Modified 可根据需求使用一个或两个同时使用。两个同时使用时，只要满足基中一个条件，就认为文件没有更新。&lt;/p&gt;
 &lt;p&gt;另外有两种特殊的情况：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;   &lt;p&gt;手动刷新页面（F5)，浏览器会直接认为缓存已经过期（可能缓存还没有过期），在请求中加上字段：Cache-Control:max-age=0，发包向服务器查询是否有文件是否有更新。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;强制刷新页面（Ctrl+F5)，浏览器会直接忽略本地的缓存（有缓存也会认为本地没有缓存），在请求中加上字段：Cache-Control:no-cache（或 Pragma:no-cache），发包向服务重新拉取文件。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;下面是通过 Google Chrome 浏览器（用其他浏览器+抓包工具也可以）自带的开发者工具，对一个资源文件不同情况请求与回包的截图。&lt;/p&gt;
 &lt;p&gt;首次请求：200&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/Vh8bpPi.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;缓存有效期内请求：200(from cache)&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/q36bsW4.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;缓存过期后请求：304（Not Modified)&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/xKsdLUS.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;一般浏览器会将缓存记录及缓存文件存在本地 Cache 文件夹中。Android 下 App 如果使用 Webview，缓存的文件记录及文件内容会存在当前 app 的 data 目录中。&lt;/p&gt;
 &lt;p&gt;分析：Cache-Control 和 Last-Modified 一般用在 Web 的静态资源文件上，如 JS、CSS 和一些图像文件。通过设置资源文件缓存属性，对提高资源文件加载速度，节省流量很有意义，特别是移动网络环境。但问题是：缓存有效时长该如何设置？如果设置太短，就起不到缓存的使用；如果设置的太长，在资源文件有更新时，浏览器如果有缓存，则不能及时取到最新的文件。 &lt;/p&gt;
 &lt;p&gt;Last-Modified 需要向服务器发起查询请求，才能知道资源文件有没有更新。虽然服务器可能返回304告诉没有更新，但也还有一个请求的过程。对于移动网络，这个请求可能是比较耗时的。有一种说法叫“消灭304”，指的就是优化掉304的请求。&lt;/p&gt;
 &lt;p&gt;抓包发现，带 if-Modified-Since 字段的请求，如果服务器回包304，回包带有 Cache-Control:max-age 或 Expires 字段，文件的缓存有效时间会更新，就是文件的缓存会重新有效。304回包后如果再请求，则又直接使用缓存文件了，不再向服务器查询文件是否更新了，除非新的缓存时间再次过期。&lt;/p&gt;
 &lt;p&gt;另外，Cache-Control 与 Last-Modified 是浏览器内核的机制，一般都是标准的实现，不能更改或设置。以 QQ 浏览器的 X5为例，Cache-Control 与 Last-Modified 缓存不能禁用。缓存容量是12MB，不分HOST，过期的缓存会最先被清除。如果都没过期，应该优先清最早的缓存或最快到期的或文件大小最大的；过期缓存也有可能还是有效的，清除缓存会导致资源文件的重新拉取。&lt;/p&gt;
 &lt;p&gt;还有，浏览器，如 X5，在使用缓存文件时，是没有对缓存文件内容进行校验的，这样缓存文件内容被修改的可能。&lt;/p&gt;
 &lt;p&gt;分析发现，浏览器的缓存机制还不是非常完美的缓存机制。完美的缓存机制应该是这样的：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;缓存文件没更新，尽可能使用缓存，不用和服务器交互；&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;缓存文件有更新时，第一时间能使用到新的文件；&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;缓存的文件要保持完整性，不使用被修改过的缓存文件；&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;缓存的容量大小要能设置或控制，缓存文件不能因为存储空间限制或过期被清除。    &lt;br /&gt;以X5为例，第1、2条不能同时满足，第3、4条都不能满足。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;在实际应用中，为了解决 Cache-Control 缓存时长不好设置的问题，以及为了”消灭304“，Web前端采用的方式是：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;在要缓存的资源文件名中加上版本号或文件 MD5值字串，如 common.d5d02a02.js，common.v1.js，同时设置 Cache-Control:max-age=31536000，也就是一年。在一年时间内，资源文件如果本地有缓存，就会使用缓存；也就不会有304的回包。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;如果资源文件有修改，则更新文件内容，同时修改资源文件名，如 common.v2.js，html页面也会引用新的资源文件名。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;通过这种方式，实现了：缓存文件没有更新，则使用缓存；缓存文件有更新，则第一时间使用最新文件的目的。即上面说的第1、2条。第3、4条由于浏览器内部机制，目前还无法满足。&lt;/p&gt;
 &lt;h4&gt;2.2 Dom Storage 存储机制&lt;/h4&gt;
 &lt;p&gt;DOM 存储是一套在 Web Applications 1.0 规范中首次引入的与存储相关的特性的总称，现在已经分离出来，单独发展成为独立的 W3C Web 存储规范。 DOM 存储被设计为用来提供一个更大存储量、更安全、更便捷的存储方法，从而可以代替掉将一些不需要让服务器知道的信息存储到 cookies 里的这种传统方法。&lt;/p&gt;
 &lt;p&gt;上面一段是对 Dom Storage 存储机制的官方表述。看起来，Dom Storage 机制类似 Cookies，但有一些优势。 &lt;/p&gt;
 &lt;p&gt;Dom Storage 是通过存储字符串的 Key/Value 对来提供的，并提供 5MB （不同浏览器可能不同，分 HOST)的存储空间（Cookies 才 4KB)。另外 Dom Storage 存储的数据在本地，不像 Cookies，每次请求一次页面，Cookies 都会发送给服务器。&lt;/p&gt;
 &lt;p&gt;DOM Storage 分为 sessionStorage 和 localStorage。localStorage 对象和 sessionStorage 对象使用方法基本相同，它们的区别在于作用的范围不同。sessionStorage 用来存储与页面相关的数据，它在页面关闭后无法使用。而 localStorage 则持久存在，在页面关闭后也可以使用。&lt;/p&gt;
 &lt;p&gt;Dom Storage 提供了以下的存储接口：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;interface Storage { 
readonly attribute unsigned long length; 
[IndexGetter] DOMString key(in unsigned long index); 
[NameGetter] DOMString getItem(in DOMString key); 
[NameSetter] void setItem(in DOMString key, in DOMString data); 
[NameDeleter] void removeItem(in DOMString key); 
void clear();
};&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;sessionStorage 是个全局对象，它维护着在页面会话(page session)期间有效的存储空间。只要浏览器开着，页面会话周期就会一直持续。当页面重新载入(reload)或者被恢复(restores)时，页面会话也是一直存在的。每在新标签或者新窗口中打开一个新页面，都会初始化一个新的会话。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;
 // 当页面刷新时，从sessionStorage恢复之前输入的内容
 window.onload = function(){
    if (window.sessionStorage) {
        var name = window.sessionStorage.getItem(&amp;quot;name&amp;quot;);
        if (name != &amp;quot;&amp;quot; || name != null){
            document.getElementById(&amp;quot;name&amp;quot;).value = name;
         }
     }
 };

 // 将数据保存到sessionStorage对象中
 function saveToStorage() {
    if (window.sessionStorage) {
        var name = document.getElementById(&amp;quot;name&amp;quot;).value;
        window.sessionStorage.setItem(&amp;quot;name&amp;quot;, name);
        window.location.href=&amp;quot;session_storage.html&amp;quot;;
     }
 }
 &amp;lt;/script&amp;gt;

&amp;lt;form action=&amp;quot;./session_storage.html&amp;quot;&amp;gt;
    &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;quot;name&amp;quot; id=&amp;quot;name&amp;quot;/&amp;gt;
    &amp;lt;input type=&amp;quot;button&amp;quot; value=&amp;quot;Save&amp;quot; onclick=&amp;quot;saveToStorage()&amp;quot;/&amp;gt;
&amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;当浏览器被意外刷新的时候，一些临时数据应当被保存和恢复。sessionStorage 对象在处理这种情况的时候是最有用的。比如恢复我们在表单中已经填写的数据。&lt;/p&gt;
 &lt;p&gt;把上面的代码复制到 session_storage.html（也可以从附件中直接下载）页面中，用 Google Chrome 浏览器的不同 PAGE 或 WINDOW 打开，在输入框中分别输入不同的文字，再点击“Save”，然后分别刷新。每个 PAGE 或 WINDOW 显示都是当前PAGE输入的内容，互不影响。关闭 PAGE，再重新打开，上一次输入保存的内容已经没有了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/F3p7KoF.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/FTSyNzK.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;Local Storage 的接口、用法与 Session Storage 一样，唯一不同的是：Local Storage 保存的数据是持久性的。当前 PAGE 关闭（Page Session 结束后），保存的数据依然存在。重新打开PAGE，上次保存的数据可以获取到。另外，Local Storage 是全局性的，同时打开两个 PAGE 会共享一份存数据，在一个PAGE中修改数据，另一个 PAGE 中是可以感知到的。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;script&amp;gt;
  //通过localStorage直接引用key, 另一种写法，等价于：
  //localStorage.getItem(&amp;quot;pageLoadCount&amp;quot;);
  //localStorage.setItem(&amp;quot;pageLoadCount&amp;quot;, value);
  if (!localStorage.pageLoadCount)
localStorage.pageLoadCount = 0;
     localStorage.pageLoadCount = parseInt(localStorage.pageLoadCount) + 1;
     document.getElementById(&amp;apos;count&amp;apos;).textContent = localStorage.pageLoadCount;
&amp;lt;/script&amp;gt;

&amp;lt;p&amp;gt;
    You have viewed this page
    &amp;lt;span id=&amp;quot;count&amp;quot;&amp;gt;an untold number of&amp;lt;/span&amp;gt;
    time(s).
&amp;lt;/p&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;将上面代码复制到 local_storage.html 的页面中，用浏览器打开，pageLoadCount 的值是1；关闭 PAGE 重新打开，pageLoadCount 的值是2。这是因为第一次的值已经保存了。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/gX0nhDe.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/VsSJUCN.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;用两个 PAGE 同时打开 local_storage.html，并分别交替刷新，发现两个 PAGE 是共享一个 pageLoadCount 的。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/K3d9gc0.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/cWePbMp.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;分析：Dom Storage 给 Web 提供了一种更录活的数据存储方式，存储空间更大（相对 Cookies)，用法也比较简单，方便存储服务器或本地的一些临时数据。&lt;/p&gt;
 &lt;p&gt;从 DomStorage 提供的接口来看，DomStorage 适合存储比较简单的数据，如果要存储结构化的数据，可能要借助 JASON了，将要存储的对象转为 JASON 字串。不太适合存储比较复杂或存储空间要求比较大的数据，也不适合存储静态的文件等。&lt;/p&gt;
 &lt;p&gt;在 Android 内嵌 Webview 中，需要通过 Webview 设置接口启用 Dom Storage。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setDomStorageEnabled(true);
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;拿 Android 类比的话，Web 的 Dom Storage 机制类似于 Android 的 SharedPreference 机制。&lt;/p&gt;
 &lt;h4&gt;2.3 Web SQL Database存储机制&lt;/h4&gt;
 &lt;p&gt;H5 也提供基于 SQL 的数据库存储机制，用于存储适合数据库的结构化数据。根据官方的标准文档，Web SQL Database 存储机制不再推荐使用，将来也不再维护，而是推荐使用 AppCache 和 IndexedDB。&lt;/p&gt;
 &lt;p&gt;现在主流的浏览器（点击查看浏览器支持情况）都还是支持 Web SQL Database 存储机制的。Web SQL Database 存储机制提供了一组 API 供 Web App 创建、存储、查询数据库。&lt;/p&gt;
 &lt;p&gt;下面通过简单的例子，演示下 Web SQL Database 的使用。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;script&amp;gt;
    if(window.openDatabase){
      //打开数据库，如果没有则创建
      var db = openDatabase(&amp;apos;mydb&amp;apos;, &amp;apos;1.0&amp;apos;, &amp;apos;Test DB&amp;apos;, 2 * 1024);

       //通过事务，创建一个表，并添加两条记录
      db.transaction(function (tx) {
           tx.executeSql(&amp;apos;CREATE TABLE IF NOT EXISTS LOGS (id unique, log)&amp;apos;);
           tx.executeSql(&amp;apos;INSERT INTO LOGS (id, log) VALUES (1, &amp;quot;foobar&amp;quot;)&amp;apos;);
           tx.executeSql(&amp;apos;INSERT INTO LOGS (id, log) VALUES (2, &amp;quot;logmsg&amp;quot;)&amp;apos;);
       });

      //查询表中所有记录，并展示出来
     db.transaction(function (tx) {
         tx.executeSql(&amp;apos;SELECT * FROM LOGS&amp;apos;, [], function (tx, results) {
             var len = results.rows.length, i;
             msg = &amp;quot;&amp;lt;p&amp;gt;Found rows: &amp;quot; + len + &amp;quot;&amp;lt;/p&amp;gt;&amp;quot;;
             for(i=0; i&amp;lt;len; i++){
                 msg += &amp;quot;&amp;lt;p&amp;gt;&amp;quot; + results.rows.item(i).log + &amp;quot;&amp;lt;/p&amp;gt;&amp;quot;;
             }
             document.querySelector(&amp;apos;#status&amp;apos;).innerHTML =  msg;
             }, null);
      });
}

&amp;lt;/script&amp;gt;

&amp;lt;div id=&amp;quot;status&amp;quot; name=&amp;quot;status&amp;quot;&amp;gt;Status Message&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;将上面代码复制到 sql_database.html 中，用浏览器打开，可看到下面的内容。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/ZSA5PB2.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;官方建议浏览器在实现时，对每个 HOST 的数据库存储空间作一定限制，建议默认是 5MB（分 HOST）的配额；达到上限后，可以申请更多存储空间。另外，现在主流浏览器 SQL Database 的实现都是基于 SQLite。&lt;/p&gt;
 &lt;p&gt;分析：SQL Database 的主要优势在于能够存储结构复杂的数据，能充分利用数据库的优势，可方便对数据进行增加、删除、修改、查询。由于 SQL 语法的复杂性，使用起来麻烦一些。SQL Database 也不太适合做静态文件的缓存。&lt;/p&gt;
 &lt;p&gt;在 Android 内嵌 Webview 中，需要通过 Webview 设置接口启用 SQL Database，同时还要设置数据库文件的存储路径。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setDatabaseEnabled(true);
final String dbPath = getApplicationContext().getDir(&amp;quot;db&amp;quot;, Context.MODE_PRIVATE).getPath();
webSettings.setDatabasePath(dbPath); 
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;Android 系统也使用了大量的数据库用来存储数据，比如联系人、短消息等；数据库的格式也 SQLite。Android 也提供了 API 来操作 SQLite。Web SQL Database 存储机制就是通过提供一组 API，借助浏览器的实现，将这种 Native 的功能提供给了 Web App。&lt;/p&gt;
 &lt;h4&gt;2.4 Application Cache 机制&lt;/h4&gt;
 &lt;p&gt;Application Cache（简称 AppCache)似乎是为支持 Web App 离线使用而开发的缓存机制。它的缓存机制类似于浏览器的缓存（Cache-Control  和 Last-Modified）机制，都是以文件为单位进行缓存，且文件有一定更新机制。但 AppCache 是对浏览器缓存机制的补充，不是替代。&lt;/p&gt;
 &lt;p&gt;先拿 W3C 官方的一个例子，说下 AppCache 机制的用法与功能。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html manifest=&amp;quot;demo_html.appcache&amp;quot;&amp;gt;
&amp;lt;body&amp;gt;

&amp;lt;script src=&amp;quot;demo_time.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;

&amp;lt;p id=&amp;quot;timePara&amp;quot;&amp;gt;&amp;lt;button onclick=&amp;quot;getDateTime()&amp;quot;&amp;gt;Get Date and Time&amp;lt;/button&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;&amp;lt;img src=&amp;quot;img_logo.gif&amp;quot; width=&amp;quot;336&amp;quot; height=&amp;quot;69&amp;quot;&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Try opening &amp;lt;a href=&amp;quot;tryhtml5_html_manifest.htm&amp;quot; target=&amp;quot;_blank&amp;quot;&amp;gt;this page&amp;lt;/a&amp;gt;, then go offline, and reload the page. The script and the image should still work.&amp;lt;/p&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;上面 HTML 文档，引用外部一个 JS 文件和一个 GIF 图片文件，在其 HTML 头中通过 manifest 属性引用了一个 appcache 结尾的文件。&lt;/p&gt;
 &lt;p&gt;我们在 Google Chrome 浏览器中打开这个 HTML 链接，JS 功能正常，图片也显示正常。禁用网络，关闭浏览器重新打开这个链接，发现 JS 工作正常，图片也显示正常。当然也有可能是浏览缓存起的作用，我们可以在文件的浏览器缓存过期后，禁用网络再试，发现 HTML 页面也是正常的。&lt;/p&gt;
 &lt;p&gt;通过 Google Chrome 浏览器自带的工具，我们可以查看已经缓存的 AppCache（分 HOST)。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/hq9dR63.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;上面截图中的缓存，就是我们刚才打开 HTML 的页面 AppCache。从截图中看，HTML 页面及 HTML 引用的 JS、GIF 图像文件都被缓存了；另外 HTML 头中 manifest 属性引用的 appcache 文件也缓存了。&lt;/p&gt;
 &lt;p&gt;AppCache 的原理有两个关键点：manifest 属性和 manifest 文件。&lt;/p&gt;
 &lt;p&gt;HTML 在头中通过 manifest 属性引用 manifest 文件。manifest 文件，就是上面以 appcache 结尾的文件，是一个普通文件文件，列出了需要缓存的文件。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/bMFTDmR.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;上面截图中的 manifest 文件，就 HTML 代码引用的 manifest 文件。文件比较简单，第一行是关键字，第二、三行就是要缓存的文件路径（相对路径）。这只是最简单的 manifest 文件，完整的还包括其他关键字与内容。引用 manifest 文件的 HTML 和 manifest 文件中列出的要缓存的文件最终都会被浏览器缓存。&lt;/p&gt;
 &lt;p&gt;完整的 manifest 文件，包括三个 Section，类型 Windows 中 ini 配置文件的 Section，不过不要中括号。&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;CACHE MANIFEST - Files listed under this header will be cached after they are downloaded for the first time&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;NETWORK - Files listed under this header require a connection to the server, and will never be cached&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;FALLBACK - Files listed under this header specifies fallback pages if a page is inaccessible&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;完整的 manifest 文件，如：&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;CACHE MANIFEST
# 2012-02-21 v1.0.0
/theme.css
/logo.gif
/main.js

NETWORK:
login.asp

FALLBACK:
/html/ /offline.html 
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;总的来说，浏览器在首次加载 HTML 文件时，会解析 manifest 属性，并读取 manifest 文件，获取 Section：CACHE MANIFEST 下要缓存的文件列表，再对文件缓存。&lt;/p&gt;
 &lt;p&gt;AppCache 的缓存文件，与浏览器的缓存文件分开存储的，还是一份？应该是分开的。因为 AppCache 在本地也有 5MB（分 HOST）的空间限制。&lt;/p&gt;
 &lt;p&gt;AppCache 在首次加载生成后，也有更新机制。被缓存的文件如果要更新，需要更新 manifest 文件。因为浏览器在下次加载时，除了会默认使用缓存外，还会在后台检查 manifest 文件有没有修改（byte by byte)。发现有修改，就会重新获取 manifest 文件，对 Section：CACHE MANIFEST 下文件列表检查更新。manifest 文件与缓存文件的检查更新也遵守浏览器缓存机制。&lt;/p&gt;
 &lt;p&gt;如用用户手动清了 AppCache 缓存，下次加载时，浏览器会重新生成缓存，也可算是一种缓存的更新。另外， Web App 也可用代码实现缓存更新。&lt;/p&gt;
 &lt;p&gt;分析：AppCache 看起来是一种比较好的缓存方法，除了缓存静态资源文件外，也适合构建 Web 离线 App。在实际使用中有些需要注意的地方，有一些可以说是”坑“。&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;要更新缓存的文件，需要更新包含它的 manifest 文件，那怕只加一个空格。常用的方法，是修改 manifest 文件注释中的版本号。如：# 2012-02-21 v1.0.0&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;被缓存的文件，浏览器是先使用，再通过检查 manifest 文件是否有更新来更新缓存文件。这样缓存文件可能用的不是最新的版本。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;在更新缓存过程中，如果有一个文件更新失败，则整个更新会失败。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;manifest 和引用它的HTML要在相同 HOST。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;manifest 文件中的文件列表，如果是相对路径，则是相对 manifest 文件的相对路径。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;manifest 也有可能更新出错，导致缓存文件更新失败。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;没有缓存的资源在已经缓存的 HTML 中不能加载，即使有网络。例如：    &lt;a href="http://appcache-demo.s3-website-us-east-1.amazonaws.com/without-network/"&gt;http://appcache-demo.s3-website-us-east-1.amazonaws.com/without-network/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;manifest 文件本身不能被缓存，且 manifest 文件的更新使用的是浏览器缓存机制。所以 manifest 文件的 Cache-Control 缓存时间不能设置太长。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;另外，根据官方文档，AppCache 已经不推荐使用了，标准也不会再支持。现在主流的浏览器都是还支持 AppCache的，以后就不太确定了。 &lt;/p&gt;
 &lt;p&gt;在Android 内嵌 Webview中，需要通过 Webview 设置接口启用 AppCache，同时还要设置缓存文件的存储路径，另外还可以设置缓存的空间大小。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setAppCacheEnabled(true);
final String cachePath = getApplicationContext().getDir(&amp;quot;cache&amp;quot;, Context.MODE_PRIVATE).getPath();
webSettings.setAppCachePath(cachePath);
webSettings.setAppCacheMaxSize(5*1024*1024);
&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;2.5 Indexed Database&lt;/h4&gt;
 &lt;p&gt;IndexedDB 也是一种数据库的存储机制，但不同于已经不再支持的 Web SQL Database。IndexedDB 不是传统的关系数据库，可归为 NoSQL 数据库。IndexedDB 又类似于 Dom Storage 的 key-value 的存储方式，但功能更强大，且存储空间更大。           &lt;/p&gt;
 &lt;p&gt;IndexedDB 存储数据是 key-value 的形式。Key 是必需，且要唯一；Key 可以自己定义，也可由系统自动生成。Value 也是必需的，但 Value 非常灵活，可以是任何类型的对象。一般 Value 都是通过 Key 来存取的。&lt;/p&gt;
 &lt;p&gt;IndexedDB 提供了一组 API，可以进行数据存、取以及遍历。这些 API 都是异步的，操作的结果都是在回调中返回。 &lt;/p&gt;
 &lt;p&gt;下面代码演示了 IndexedDB 中 DB 的打开（创建）、存储对象(可理解成有关系数据的”表“）的创建及数据存取、遍历基本功能。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;

var db;

window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;

//浏览器是否支持IndexedDB
if (window.indexedDB) {
   //打开数据库，如果没有，则创建
   var openRequest = window.indexedDB.open(&amp;quot;people_db&amp;quot;, 1);

   //DB版本设置或升级时回调
   openRequest.onupgradeneeded = function(e) {
       console.log(&amp;quot;Upgrading...&amp;quot;);

       var thisDB = e.target.result;
       if(!thisDB.objectStoreNames.contains(&amp;quot;people&amp;quot;)) {
           console.log(&amp;quot;Create Object Store: people.&amp;quot;);

           //创建存储对象，类似于关系数据库的表
           thisDB.createObjectStore(&amp;quot;people&amp;quot;, { autoIncrement:true });

          //创建存储对象， 还创建索引
          //var objectStore = thisDB.createObjectStore(&amp;quot;people&amp;quot;,{ autoIncrement:true });
         // //first arg is name of index, second is the path (col);
        //objectStore.createIndex(&amp;quot;name&amp;quot;,&amp;quot;name&amp;quot;, {unique:false});
       //objectStore.createIndex(&amp;quot;email&amp;quot;,&amp;quot;email&amp;quot;, {unique:true});
     }
}

//DB成功打开回调
openRequest.onsuccess = function(e) {
    console.log(&amp;quot;Success!&amp;quot;);

    //保存全局的数据库对象，后面会用到
    db = e.target.result;

   //绑定按钮点击事件
     document.querySelector(&amp;quot;#addButton&amp;quot;).addEventListener(&amp;quot;click&amp;quot;, addPerson, false);

    document.querySelector(&amp;quot;#getButton&amp;quot;).addEventListener(&amp;quot;click&amp;quot;, getPerson, false);

    document.querySelector(&amp;quot;#getAllButton&amp;quot;).addEventListener(&amp;quot;click&amp;quot;, getPeople, false);

    document.querySelector(&amp;quot;#getByName&amp;quot;).addEventListener(&amp;quot;click&amp;quot;, getPeopleByNameIndex1, false);
}

  //DB打开失败回调
  openRequest.onerror = function(e) {
      console.log(&amp;quot;Error&amp;quot;);
      console.dir(e);
   }

}else{
    alert(&amp;apos;Sorry! Your browser doesn\&amp;apos;t support the IndexedDB.&amp;apos;);
}

//添加一条记录
function addPerson(e) {
    var name = document.querySelector(&amp;quot;#name&amp;quot;).value;
    var email = document.querySelector(&amp;quot;#email&amp;quot;).value;

    console.log(&amp;quot;About to add &amp;quot;+name+&amp;quot;/&amp;quot;+email);

    var transaction = db.transaction([&amp;quot;people&amp;quot;],&amp;quot;readwrite&amp;quot;);
var store = transaction.objectStore(&amp;quot;people&amp;quot;);

   //Define a person
   var person = {
       name:name,
       email:email,
       created:new Date()
   }

   //Perform the add
   var request = store.add(person);
   //var request = store.put(person, 2);

   request.onerror = function(e) {
       console.log(&amp;quot;Error&amp;quot;,e.target.error.name);
       //some type of error handler
   }

   request.onsuccess = function(e) {
      console.log(&amp;quot;Woot! Did it.&amp;quot;);
   }
}

//通过KEY查询记录
function getPerson(e) {
    var key = document.querySelector(&amp;quot;#key&amp;quot;).value;
    if(key === &amp;quot;&amp;quot; || isNaN(key)) return;

    var transaction = db.transaction([&amp;quot;people&amp;quot;],&amp;quot;readonly&amp;quot;);
    var store = transaction.objectStore(&amp;quot;people&amp;quot;);

    var request = store.get(Number(key));

    request.onsuccess = function(e) {
        var result = e.target.result;
        console.dir(result);
        if(result) {
           var s = &amp;quot;&amp;lt;p&amp;gt;&amp;lt;h2&amp;gt;Key &amp;quot;+key+&amp;quot;&amp;lt;/h2&amp;gt;&amp;lt;/p&amp;gt;&amp;quot;;
           for(var field in result) {
               s+= field+&amp;quot;=&amp;quot;+result[field]+&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;;
           }
           document.querySelector(&amp;quot;#status&amp;quot;).innerHTML = s;
         } else {
            document.querySelector(&amp;quot;#status&amp;quot;).innerHTML = &amp;quot;&amp;lt;h2&amp;gt;No match!&amp;lt;/h2&amp;gt;&amp;quot;;
         }
     }
}

//获取所有记录
function getPeople(e) {

    var s = &amp;quot;&amp;quot;;

     db.transaction([&amp;quot;people&amp;quot;], &amp;quot;readonly&amp;quot;).objectStore(&amp;quot;people&amp;quot;).openCursor().onsuccess = function(e) {
        var cursor = e.target.result;
        if(cursor) {
            s += &amp;quot;&amp;lt;p&amp;gt;&amp;lt;h2&amp;gt;Key &amp;quot;+cursor.key+&amp;quot;&amp;lt;/h2&amp;gt;&amp;lt;/p&amp;gt;&amp;quot;;
            for(var field in cursor.value) {
                s+= field+&amp;quot;=&amp;quot;+cursor.value[field]+&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;;
            }
            s+=&amp;quot;&amp;lt;/p&amp;gt;&amp;quot;;
            cursor.continue();
         }
         document.querySelector(&amp;quot;#status2&amp;quot;).innerHTML = s;
     }
}

//通过索引查询记录
function getPeopleByNameIndex(e)
{
    var name = document.querySelector(&amp;quot;#name1&amp;quot;).value;

    var transaction = db.transaction([&amp;quot;people&amp;quot;],&amp;quot;readonly&amp;quot;);
    var store = transaction.objectStore(&amp;quot;people&amp;quot;);
    var index = store.index(&amp;quot;name&amp;quot;);

    //name is some value
    var request = index.get(name);

    request.onsuccess = function(e) {
       var result = e.target.result;
       if(result) {
           var s = &amp;quot;&amp;lt;p&amp;gt;&amp;lt;h2&amp;gt;Name &amp;quot;+name+&amp;quot;&amp;lt;/h2&amp;gt;&amp;lt;p&amp;gt;&amp;quot;;
           for(var field in result) {
               s+= field+&amp;quot;=&amp;quot;+result[field]+&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;;
           }
           s+=&amp;quot;&amp;lt;/p&amp;gt;&amp;quot;;
    } else {
        document.querySelector(&amp;quot;#status3&amp;quot;).innerHTML = &amp;quot;&amp;lt;h2&amp;gt;No match!&amp;lt;/h2&amp;gt;&amp;quot;;
     }
   }
}

//通过索引查询记录
function getPeopleByNameIndex1(e)
{
    var s = &amp;quot;&amp;quot;;

    var name = document.querySelector(&amp;quot;#name1&amp;quot;).value;

    var transaction = db.transaction([&amp;quot;people&amp;quot;],&amp;quot;readonly&amp;quot;);
    var store = transaction.objectStore(&amp;quot;people&amp;quot;);
    var index = store.index(&amp;quot;name&amp;quot;);

    //name is some value
    index.openCursor().onsuccess = function(e) {
        var cursor = e.target.result;
        if(cursor) {
            s += &amp;quot;&amp;lt;p&amp;gt;&amp;lt;h2&amp;gt;Key &amp;quot;+cursor.key+&amp;quot;&amp;lt;/h2&amp;gt;&amp;lt;/p&amp;gt;&amp;quot;;
            for(var field in cursor.value) {
                s+= field+&amp;quot;=&amp;quot;+cursor.value[field]+&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;;
            }
            s+=&amp;quot;&amp;lt;/p&amp;gt;&amp;quot;;
            cursor.continue();
         }
         document.querySelector(&amp;quot;#status3&amp;quot;).innerHTML = s;
     }
}

&amp;lt;/script&amp;gt;

&amp;lt;p&amp;gt;添加数据&amp;lt;br/&amp;gt;
&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;name&amp;quot; placeholder=&amp;quot;Name&amp;quot;&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;input type=&amp;quot;email&amp;quot; id=&amp;quot;email&amp;quot; placeholder=&amp;quot;Email&amp;quot;&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;button id=&amp;quot;addButton&amp;quot;&amp;gt;Add Data&amp;lt;/button&amp;gt;
&amp;lt;/p&amp;gt;

&amp;lt;p&amp;gt;根据Key查询数据&amp;lt;br/&amp;gt;
&amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;key&amp;quot; placeholder=&amp;quot;Key&amp;quot;&amp;gt;&amp;lt;br/&amp;gt;
&amp;lt;button id=&amp;quot;getButton&amp;quot;&amp;gt;Get Data&amp;lt;/button&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;div id=&amp;quot;status&amp;quot; name=&amp;quot;status&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;p&amp;gt;获取所有数据&amp;lt;br/&amp;gt;
&amp;lt;button id=&amp;quot;getAllButton&amp;quot;&amp;gt;Get EveryOne&amp;lt;/button&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;div id=&amp;quot;status2&amp;quot; name=&amp;quot;status2&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;p&amp;gt;根据索引:Name查询数据&amp;lt;br/&amp;gt;
    &amp;lt;input type=&amp;quot;text&amp;quot; id=&amp;quot;name1&amp;quot; placeholder=&amp;quot;Name&amp;quot;&amp;gt;&amp;lt;br/&amp;gt;
    &amp;lt;button id=&amp;quot;getByName&amp;quot;&amp;gt;Get ByName&amp;lt;/button&amp;gt;
&amp;lt;/p&amp;gt;
&amp;lt;div id=&amp;quot;status3&amp;quot; name=&amp;quot;status3&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;将上面的代码复制到 indexed_db.html 中，用 Google Chrome 浏览器打开，就可以添加、查询数据。在 Chrome 的开发者工具中，能查看创建的 DB 、存储对象(可理解成表）以及表中添加的数据。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/EauZGwV.png" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;IndexedDB 有个非常强大的功能，就是 index（索引）。它可对 Value 对象中任何属性生成索引，然后可以基于索引进行 Value 对象的快速查询。&lt;/p&gt;
 &lt;p&gt;要生成索引或支持索引查询数据，需求在首次生成存储对象时，调用接口生成属性的索引。可以同时对对象的多个不同属性创建索引。如下面代码就对name 和 email 两个属性都生成了索引。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;var objectStore = thisDB.createObjectStore(&amp;quot;people&amp;quot;,{ autoIncrement:true });
//first arg is name of index, second is the path (col);
objectStore.createIndex(&amp;quot;name&amp;quot;,&amp;quot;name&amp;quot;, {unique:false});
objectStore.createIndex(&amp;quot;email&amp;quot;,&amp;quot;email&amp;quot;, {unique:true});
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;生成索引后，就可以基于索引进行数据的查询。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;function getPeopleByNameIndex(e)
{
var name = document.querySelector(&amp;quot;#name1&amp;quot;).value;

var transaction = db.transaction([&amp;quot;people&amp;quot;],&amp;quot;readonly&amp;quot;);
var store = transaction.objectStore(&amp;quot;people&amp;quot;);
var index = store.index(&amp;quot;name&amp;quot;);

//name is some value
var request = index.get(name);
request.onsuccess = function(e) {
    var result = e.target.result;
    if(result) {
        var s = &amp;quot;&amp;lt;p&amp;gt;&amp;lt;h2&amp;gt;Name &amp;quot;+name+&amp;quot;&amp;lt;/h2&amp;gt;&amp;lt;p&amp;gt;&amp;quot;;
        for(var field in result) {
            s+= field+&amp;quot;=&amp;quot;+result[field]+&amp;quot;&amp;lt;br/&amp;gt;&amp;quot;;
        }
        s+=&amp;quot;&amp;lt;/p&amp;gt;&amp;quot;;
    } else {
        document.querySelector(&amp;quot;#status3&amp;quot;).innerHTML = &amp;quot;&amp;lt;h2&amp;gt;No match!&amp;lt;/h2&amp;gt;&amp;quot;;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;分析：IndexedDB 是一种灵活且功能强大的数据存储机制，它集合了 Dom Storage 和 Web SQL Database 的优点，用于存储大块或复杂结构的数据，提供更大的存储空间，使用起来也比较简单。可以作为 Web SQL Database 的替代。不太适合静态文件的缓存。&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;以key-value 的方式存取对象，可以是任何类型值或对象，包括二进制。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;可以对对象任何属性生成索引，方便查询。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;较大的存储空间，默认推荐250MB(分 HOST)，比 Dom Storage 的5MB 要大的多。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;通过数据库的事务（tranction）机制进行数据操作，保证数据一致性。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;异步的 API 调用，避免造成等待而影响体验。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;Android 在4.4开始加入对 IndexedDB 的支持，只需打开允许 JS 执行的开关就好了。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;WebView myWebView = (WebView) findViewById(R.id.webview);
WebSettings webSettings = myWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
&lt;/code&gt;&lt;/pre&gt;
 &lt;h4&gt;2.6 File System API&lt;/h4&gt;
 &lt;p&gt;File System API 是 H5 新加入的存储机制。它为 Web App 提供了一个虚拟的文件系统，就像 Native App 访问本地文件系统一样。由于安全性的考虑，这个虚拟文件系统有一定的限制。Web App 在虚拟的文件系统中，可以进行文件（夹）的创建、读、写、删除、遍历等操作。&lt;/p&gt;
 &lt;p&gt;File System API 也是一种可选的缓存机制，和前面的 SQLDatabase、IndexedDB 和 AppCache 等一样。File System API 有自己的一些特定的优势：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;   &lt;p&gt;可以满足大块的二进制数据（ large binary blobs）存储需求。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;可以通过预加载资源文件来提高性能。&lt;/p&gt;&lt;/li&gt;
  &lt;li&gt;   &lt;p&gt;可以直接编辑文件。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt;浏览器给虚拟文件系统提供了两种类型的存储空间：临时的和持久性的。临时的存储空间是由浏览器自动分配的，但可能被浏览器回收；持久性的存储空间需要显示的申请，申请时浏览器会给用户一提示，需要用户进行确认。持久性的存储空间是 WebApp 自己管理，浏览器不会回收，也不会清除内容。持久性的存储空间大小是通过配额来管理的，首次申请时会一个初始的配额，配额用完需要再次申请。 &lt;/p&gt;
 &lt;p&gt;虚拟的文件系统是运行在沙盒中。不同 WebApp 的虚拟文件系统是互相隔离的，虚拟文件系统与本地文件系统也是互相隔离的。&lt;/p&gt;
 &lt;p&gt;File System API 提供了一组文件与文件夹的操作接口，有同步和异步两个版本，可满足不同的使用场景。下面通过一个文件创建、读、写的例子，演示下简单的功能与用法。&lt;/p&gt;
 &lt;pre&gt;  &lt;code&gt;&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;

window.requestFileSystem = window.requestFileSystem || window.webkitRequestFileSystem;

//请求临时文件的存储空间
if (window.requestFileSystem) {
     window.requestFileSystem(window.TEMPORARY, 5*1024*1024, initFS, errorHandler);
}else{
  alert(&amp;apos;Sorry! Your browser doesn\&amp;apos;t support the FileSystem API&amp;apos;);
}

//请求成功回调
function initFS(fs){

  //在根目录下打开log.txt文件，如果不存在就创建
  //fs就是成功返回的文件系统对象，fs.root代表根目录
  fs.root.getFile(&amp;apos;log.txt&amp;apos;, {create: true}, function(fileEntry) {

  //fileEntry是返回的一个文件对象，代表打开的文件

  //向文件写入指定内容
  writeFile(fileEntry);

  //将写入的内容又读出来，显示在页面上
  readFile(fileEntry);

  }, errorHandler);
}

//读取文件内容
function readFile(fileEntry)
{
    console.log(&amp;apos;readFile&amp;apos;);

   // Get a File object representing the file,
   // then use FileReader to read its contents.
   fileEntry.file(function(file) {

     console.log(&amp;apos;createReader&amp;apos;);

      var reader = new FileReader();

      reader.onloadend = function(e) {

        console.log(&amp;apos;onloadend&amp;apos;);

        var txtArea = document.createElement(&amp;apos;textarea&amp;apos;);
        txtArea.value = this.result;
        document.body.appendChild(txtArea);
      };

      reader.readAsText(file);
   }, errorHandler);
}

//向文件写入指定内容
function writeFile(fileEntry)
{
    console.log(&amp;apos;writeFile&amp;apos;);

    // Create a FileWriter object for our FileEntry (log.txt).
    fileEntry.createWriter(function(fileWriter) {

      console.log(&amp;apos;createWriter&amp;apos;);

      fileWriter.onwriteend = function(e) {
        console.log(&amp;apos;Write completed&amp;apos;);
      };

        fileWriter.onerror = function(e) {
          console.log(&amp;apos;Write failed: &amp;apos; + e.toString());
        };

        // Create a new Blob and write it to log.txt.
        var blob = new Blob([&amp;apos;Hello, World!&amp;apos;], {type: &amp;apos;text/plain&amp;apos;});

        fileWriter.write(blob);

     }, errorHandler);
}

function errorHandler(err){
 var msg = &amp;apos;An error occured: &amp;apos; + err;
 console.log(msg);
};

 &amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
 &lt;p&gt;将上面代码复制到 file_system_api.html 文件中，用 Google Chrome 浏览器打开（现在 File System API 只有 Chrome 43+、Opera 32+ 以及 Chrome for Android 46+ 这三个浏览器支持）。由于 Google Chrome 禁用了本地 HTML 文件中的 File System API功能，在启动 Chrome 时，要加上”—allow-file-access-from-files“命令行参数。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/1MmrSvq.gif" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;上面截图，左边是 HTML 运行的结果，右边是 Chrome 开发者工具中看到的 Web 的文件系统。基本上 H5的几种缓存机制的数据都能在这个开发者工具看到，非常方便。&lt;/p&gt;
 &lt;p&gt;分析：File System API 给 Web App 带来了文件系统的功能，Native 文件系统的功能在 Web App 中都有相应的实现。任何需要通过文件来管理数据，或通过文件系统进行数据管理的场景都比较适合。&lt;/p&gt;
 &lt;p&gt;到目前，Android 系统的 Webview 还不支持 File System API。&lt;/p&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;3 移动端 Web 加载性能（缓存）优化&lt;/h3&gt;
 &lt;p&gt;分析完 H5提供的各种缓存机制，回到移动端（针对 Android，可能也适用于 iOS）的场景。现在 Android App（包括手 Q 和 WX）大多嵌入了 Webview 的组件（系统 Webview 或 QQ 游览器的 X5组件），通过内嵌Webview 来加载一些H5的运营活动页面或资讯页。这样可充分发挥Web前端的优势：快速开发、发布，灵活上下线。但 Webview 也有一些不可忽视的问题，比较突出的就是加载相对较慢，会相对消耗较多流量。&lt;/p&gt;
 &lt;p&gt;通过对一些 H5页面进行调试及抓包发现，每次加载一个 H5页面，都会有较多的请求。除了 HTML 主 URL 自身的请求外，HTML外部引用的 JS、CSS、字体文件、图片都是一个独立的 HTTP 请求，每一个请求都串行的（可能有连接复用）。这么多请求串起来，再加上浏览器解析、渲染的时间，Web 整体的加载时间变得较长；请求文件越多，消耗的流量也会越多。我们可综合使用上面说到几种缓存机制，来帮助我们优化 Web 的加载性能。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" src="http://i.imgur.com/vS0E15b.png" title=""&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;结论：综合各种缓存机制比较，对于静态文件，如 JS、CSS、字体、图片等，适合通过浏览器缓存机制来进行缓存，通过缓存文件可大幅提升 Web 的加载速度，且节省流量。但也有一些不足：缓存文件需要首次加载后才会产生；浏览器缓存的存储空间有限，缓存有被清除的可能；缓存的文件没有校验。要解决这些不足，可以参考手 Q 的离线包，它有效的解决了这些不足。&lt;/p&gt;
 &lt;p&gt;对于 Web 在本地或服务器获取的数据，可以通过 Dom Storage 和 IndexedDB 进行缓存。也在一定程度上减少和 Server 的交互，提高加载速度，同时节省流量。&lt;/p&gt;
 &lt;p&gt;当然 Web 的性能优化，还包括选择合适的图片大小，避免 JS 和 CSS 造成的阻塞等。这就需要 Web 前端的同事根据一些规范和一些调试工具进行优化了。&lt;/p&gt;
 &lt;h4&gt;想了解更多干货，请搜索关注公众号：腾讯Bulgy，或搜索微信号：weixinBugly，关注我们&lt;/h4&gt;
 &lt;hr&gt;&lt;/hr&gt;
 &lt;h3&gt;腾讯Bugly&lt;/h3&gt;
 &lt;p&gt;Bugly是腾讯内部产品质量监控平台的外发版本，支持iOS和Android两大主流平台,其主要功能是App发布以后，对用户侧发生的crash以及卡顿现象进行监控并上报，让开发同学可以第一时间了解到app的质量情况，及时修改。目前腾讯内部所有的产品，均在使用其进行线上产品的崩溃监控。&lt;/p&gt;
 &lt;p&gt;腾讯内部团队4年打磨，目前腾讯内部所有的产品都在使用，基本覆盖了中国市场的移动设备以及网络环境，可靠性有保证。使用Bugly，你就使用了和手机QQ、QQ空间、手机管家相同的质量保障手段&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>html5</category>
      <guid isPermaLink="true">https://itindex.net/detail/54832-h5-%E7%BC%93%E5%AD%98-%E7%A7%BB%E5%8A%A8</guid>
      <pubDate>Fri, 11 Dec 2015 15:07:56 CST</pubDate>
    </item>
    <item>
      <title>移动web问题小结</title>
      <link>https://itindex.net/detail/53907-%E7%A7%BB%E5%8A%A8-web-%E9%97%AE%E9%A2%98</link>
      <description>&lt;h3&gt;  &lt;strong&gt;Meta标签：&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;&amp;lt;meta content=&amp;quot;width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0;&amp;quot; name=&amp;quot;viewport&amp;quot; /&amp;gt;&lt;/pre&gt; &lt;p&gt;这个想必大家都知道，当页面在手机上显示时，增加这个meta可以让页面强制让文档的宽度与设备的宽度保持1:1，并且文档最大的宽度比例是1.0，且不允许用户点击屏幕放大浏览。&lt;/p&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;&amp;lt;meta content=&amp;quot;telephone=no&amp;quot; name=&amp;quot;format-detection&amp;quot; /&amp;gt;
&amp;lt;meta content=&amp;quot;email=no&amp;quot; name=&amp;quot;format-detection&amp;quot; /&amp;gt;&lt;/pre&gt; &lt;p&gt;这两个属性分别对ios上自动识别电话和android上自动识别邮箱做了限制。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt; 获取滚动条的值：&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;window.scrollY  window.scrollX&lt;/pre&gt; &lt;p&gt;桌面浏览器中想要获取滚动条的值是通过document.scrollTop和document.scrollLeft得到的，但在iOS中你会发现这两个属性是未定义的，为什么呢？因为在iOS中没有滚动条的概念，在Android中通过这两个属性可以正常获取到滚动条的值，那么在iOS中我们该如何获取滚动条的值呢？就是上面两个属性，但是事实证明android也支持这属性，所以索性都用woindow.scroll.&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;禁止选择文本：&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;-webkit-user-select:none&lt;/pre&gt; &lt;p&gt;禁止用户选择文本，ios和android都支持&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;屏蔽阴影：&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;-webkit-appearance:none&lt;/pre&gt; &lt;p&gt;亲测，可以同时屏蔽输入框怪异的内阴影，解决iOS下无法修改按钮样式，测试还发现一个小问题就是，加了上面的属性后，iOS下默认还是带有圆角的，不过可以使用 border-radius属性修改。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt; css之border-box：&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;element{
        width: 100%;
        padding-left: 10px;
        box-sizing:border-box;
        -webkit-box-sizing:border-box;
        border: 1px solid blue;
}&lt;/pre&gt; &lt;p&gt;那我想要一个元素100%显示，又必须有一个固定的padding-left／padding-right，还有1px的边框，怎么办？这样编写代码必然导致出现横向滚动条，肿么办？要相信问题就是用来解决的。这时候伟大的css3为我们提供了box-sizing属性，对于这个属性的具体解释不做赘述（想深入了解的同学可以到w3school查看，要知道自己动手会更容易记忆）。让我们看看如何解决上面的问题：&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt; css3多文本换行：&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;p {
    overflow : hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}&lt;/pre&gt; &lt;p&gt;Webkit支持一个名为-webkit-line-clamp的属性，参见  &lt;a href="http://developer.apple.com/safari/library/documentation/AppleApplications/Reference/SafariCSSRef/Articles/StandardCSSProperties.html#//apple_ref/doc/uid/TP30001266-UnsupportedProperties"&gt;链接&lt;/a&gt;，也就是说这个属性并不是标准的一部分，可能是Webkit内部使用的，或者被弃用的属性。需要注意的是display需要设置成box，-webkit-line-clamp表示需要显示几行。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt; Retina屏幕高清图片：&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;selector {
  background-image: url(no-image-set.png);
  background: image-set(url(foo-lowres.png) 1x,url(foo-highres.png) 2x) center;
}&lt;/pre&gt; &lt;p&gt;image-set的语法，类似于不同的文本，图像也会显示成不同的：&lt;/p&gt;
 &lt;ol&gt;
  &lt;li&gt;    &lt;strong&gt;不支持image-set&lt;/strong&gt;：在不支持image-set的浏览器下，他会支持background-image图像，也就是说不支持image-set的浏览器下，他们解析background-image中的背景图像；&lt;/li&gt;
  &lt;li&gt;    &lt;strong&gt;支持image-set&lt;/strong&gt;：如果你的浏览器支持image-sete，而且是普通显屏下，此时浏览器会选择image-set中的@1x背景图像；&lt;/li&gt;
  &lt;li&gt;    &lt;strong&gt;Retina屏幕下的image-set&lt;/strong&gt;：如果你的浏览器支持image-set，而且是在Retina屏幕下，此时浏览器会选择image-set中的@2x背景图像。&lt;/li&gt;
&lt;/ol&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt; &lt;/strong&gt;&lt;/h3&gt;
 &lt;h3&gt;  &lt;strong&gt; html5重力感应事件：&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;if (window.DeviceMotionEvent) { 
                 window.addEventListener(&amp;apos;devicemotion&amp;apos;,deviceMotionHandler, false);  
        } 
        var speed = 30;//speed
        var x = y = z = lastX = lastY = lastZ = 0;
        function deviceMotionHandler(eventData) {  
          var acceleration =event.accelerationIncludingGravity;
                x = acceleration.x;
                y = acceleration.y;
                z = acceleration.z;
                if(Math.abs(x-lastX) &amp;gt; speed || Math.abs(y-lastY) &amp;gt; speed || Math.abs(z-lastZ) &amp;gt; speed) {
                    //简单的摇一摇触发代码
                    alert(1);
                }
                lastX = x;
                lastY = y;
                lastZ = z;
        }&lt;/pre&gt; &lt;p&gt;关于deviceMotionEvent是HTML5新增的事件，用来检测手机重力感应效果具体可参考  &lt;a href="http://w3c.github.io/deviceorientation/spec-source-orientation.html" target="_blank"&gt;http://w3c.github.io/deviceorientation/spec-source-orientation.html&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;移动端touch事件：&lt;/strong&gt;&lt;/h3&gt;
 &lt;ul&gt;
  &lt;li&gt;touchstart //当手指接触屏幕时触发&lt;/li&gt;
  &lt;li&gt;touchmove //当已经接触屏幕的手指开始移动后触发&lt;/li&gt;
  &lt;li&gt;touchend //当手指离开屏幕时触发&lt;/li&gt;
  &lt;li&gt;touchcancel//当某种touch事件非正常结束时触发&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;这4个事件的触发顺序为：&lt;/p&gt;
 &lt;p&gt;touchstart -&amp;gt; touchmove -&amp;gt;  touchend -&amp;gt;touchcancel&lt;/p&gt;
 &lt;p&gt;对于某些android系统touch的bug:&lt;/p&gt;
 &lt;p&gt;比如手指在屏幕由上向下拖动页面时，理论上是会触发 一个 touchstart ，很多次 touchmove ，和最终的 touchend ，可是在android 4.0上，touchmove只被触发一次，触发时间和touchstart 差不多，而touchend直接没有被触发。这是一个非常严重的bug，在  &lt;a href="http://code.google.com/p/android/issues/detail?id=19827" target="_blank"&gt;google Issue&lt;/a&gt;已有不少人提出 ,这个很蛋疼的bug是在模拟下拉刷新是遇到的尤其当touchmove的dom节点数量变多时比出现，当时解决办法就是用settimeout来稀释touchmove。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;单击延迟：&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;click 事件因为要等待双击确认，会有 300ms 的延迟，体验并不是很好。&lt;/p&gt;
 &lt;p&gt;开发者大多数会使用封装的 tap 事件来代替click 事件，所谓的 tap 事件由 touchstart 事件 + touchmove 判断 + touchend 事件封装组成。&lt;/p&gt;
 &lt;p&gt;  &lt;a href="https://developers.google.com/mobile/articles/fast_buttons?hl=de-DE" title="article5"&gt;Creating Fast Buttons for Mobile Web Applications&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://stackoverflow.com/questions/12238587/eliminate-300ms-delay-on-click-events-in-mobile-safari" title="article5"&gt;Eliminate 300ms delay on click events in mobile Safari&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;IOS里面fixed的文本框焦点居中&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;&lt;/p&gt; &lt;pre&gt;&amp;lt;!DOCTYPE html&amp;gt;
    &amp;lt;head&amp;gt;
    input {
       position:fixed;
       top:0;left:0;
    }
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;div class=&amp;quot;header&amp;quot;&amp;gt;
            &amp;lt;form action=&amp;quot;&amp;quot;&amp;gt;
                &amp;lt;label&amp;gt;Testfield: &amp;lt;input type=&amp;quot;text&amp;quot; /&amp;gt;&amp;lt;/label&amp;gt;
            &amp;lt;/form&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/pre&gt; &lt;p&gt;在ios里面，当一个文本框的样式为fixed时候，如果这个文本框获得焦点，它的位置就会乱掉，由于ios里面做了自适应居中，这个fixed的文本框会跑到页面中间。类似：&lt;/p&gt;
 &lt;p&gt;  &lt;a href="http://www.nihaoshijie.com.cn/wordpress/wp-content/uploads/2014/10/QQ%E5%9B%BE%E7%89%8720141203214548.png"&gt;   &lt;img alt="QQ&amp;#22270;&amp;#29255;20141203214548" src="http://www.nihaoshijie.com.cn/wordpress/wp-content/uploads/2014/10/QQ%E5%9B%BE%E7%89%8720141203214548.png"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;解决办法有两个：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;可以在文本框获得焦点的时候将fixed改为absolute，失去焦点时在改回fixed，但是这样会让屏幕有上下滑动的体验不太好。&lt;/p&gt; &lt;pre&gt;.fixfixed {
position:absolute;
}
$(document)
    .on(&amp;apos;focus&amp;apos;, &amp;apos;input&amp;apos;, function(e) {
        $this.addClass(&amp;apos;fixfixed&amp;apos;);
    })
    .on(&amp;apos;blur&amp;apos;, &amp;apos;input&amp;apos;, function(e) {
        $this.removeClass(&amp;apos;fixfixed&amp;apos;);
    });&lt;/pre&gt; &lt;p&gt; &lt;/p&gt;
 &lt;p&gt;还有一种就是用一个假的fixed的文本框放在页面顶部，一个absolute的文本框隐藏在页面顶部，当fixed的文本框获得焦点时候将其隐藏，然后显示absolute的文本框，当失去焦点时，在把absolute的文本框隐藏，fixed的文本框显示。&lt;/p&gt; &lt;pre&gt;.fixfixed {
position:absolute;
}
$(document)
    .on(&amp;apos;focus&amp;apos;, &amp;apos;input&amp;apos;, function(e) {
        $absolute..show();
        $this.hide();
    })
    .on(&amp;apos;blur&amp;apos;, &amp;apos;input&amp;apos;, function(e) {
         $fixed..show();
        $this.hide();
    });&lt;/pre&gt; &lt;p&gt; &lt;/p&gt;
 &lt;p&gt;最后一种就是顶部的input不参与滚动，只让其下面滚动。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h3&gt;  &lt;strong&gt;   &lt;strong&gt;position:sticky&lt;/strong&gt;&lt;/strong&gt;&lt;/h3&gt;
 &lt;p&gt;position:sticky是一个新的css3属性，它的表现类似position:relative和position:fixed的合体，在目标区域在屏幕中可见时，它的行为就像position:relative; 而当页面滚动超出目标区域时，它的表现就像position:fixed，它会固定在目标位置。&lt;/p&gt; &lt;pre&gt;.sticky { 
position: -webkit-sticky; 
position:sticky; 
top: 15px; 
}&lt;/pre&gt; &lt;p&gt;  &lt;strong&gt;浏览器兼容性&lt;/strong&gt;：&lt;/p&gt;
 &lt;p&gt;由于这是一个全新的属性，以至于到现在都没有一个规范，W3C也刚刚开始讨论它，而现在只有webkit nightly版本和chrome 开发版(Chrome 23.0.1247.0+ Canary)才开始支持它。&lt;/p&gt;
 &lt;p&gt;另外需要注意的是，如果同时定义了left和right值，那么left生效，right会无效，同样，同时定义了top和bottom，top赢～～&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;移动端点透事件&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;简单的说，由于在移动端我们经常会使用tap(touchstart)事件来替换掉click事件，那么就会有一种场景是：&lt;/p&gt; &lt;pre&gt;&amp;lt;div id=&amp;quot;mengceng&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;a href=&amp;quot;www.qq.com&amp;quot;&amp;gt;www.qq.com&amp;lt;/a&amp;gt;&lt;/pre&gt; &lt;p&gt;div是绝对定位的蒙层z-index高于a，而a标签是页面中的一个链接，我们给div绑定tap事件：&lt;/p&gt; &lt;pre&gt;$(&amp;apos;#mengceng&amp;apos;).on(&amp;apos;tap&amp;apos;,function(){
$(&amp;apos;#mengceng&amp;apos;).hide();
});&lt;/pre&gt; &lt;p&gt;我们点击蒙层时 div正常消失，但是当我们在a标签上点击蒙层时，发现a链接被触发，这就是所谓的点透事件。&lt;/p&gt;
 &lt;p&gt;原因：&lt;/p&gt;
 &lt;p&gt;touchstart 早于 touchend 早于 click。亦即click的触发是有延迟的，这个时间大概在300ms左右，也就是说我们tap触发之后蒙层隐藏，此时click还没有触发，300ms之后由于蒙层隐藏，我们的click触发到了下面的a链接上。&lt;/p&gt;
 &lt;p&gt;解决办法：&lt;/p&gt;
 &lt;p&gt;1 尽量都使用touch事件来替换click事件。&lt;/p&gt;
 &lt;p&gt;2 阻止a链接的click的preventDefault&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;base64编码图片替换url图片&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;u在移动端，网络请求是很珍贵的资源，尤其在2g或者3g网络下，所以能不发请求的资源都尽量不要发，对于一些小图片icon之类的，可以将图片用base64编码，来减少网络请求。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h4&gt;  &lt;strong&gt;手机拍照和上传图片&lt;/strong&gt;&lt;/h4&gt;
 &lt;p&gt;&amp;lt;input type=”file”&amp;gt;的accept 属性&lt;/p&gt; &lt;pre&gt;&amp;lt;!-- 选择照片 --&amp;gt;
&amp;lt;input type=file accept=&amp;quot;image/*&amp;quot;&amp;gt;
&amp;lt;!-- 选择视频 --&amp;gt;
&amp;lt;input type=file accept=&amp;quot;video/*&amp;quot;&amp;gt;&lt;/pre&gt; &lt;p&gt; &lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;动画效果时开启硬件加速&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;我们在制作动画效果时经常会想要改版元素的top或者left来让元素动起来，在pc端还好但是移动端就会有较大的卡顿感，这么我们需要使用css3的  transform: translate3d;来替换，&lt;/p&gt;
 &lt;p&gt;此效果可以让浏览器开启  &lt;a href="http://www.cnblogs.com/PeunZhang/p/3510083.html"&gt;gpu&lt;/a&gt;加速，渲染更流畅，但是笔着实验时在ios上体验良好，但在一些低端android机型可能会出现意想不到的效果。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;h4&gt;快速回弹滚动&lt;/h4&gt;
 &lt;p&gt;在iOS上如果你想让一个元素拥有像 Native 的滚动效果，你可以这样做：&lt;/p&gt; &lt;pre&gt;.div {
        overflow: auto;
        -webkit-overflow-scrolling: touch;
    }&lt;/pre&gt; &lt;p&gt;经笔着测试，此效果在不同的ios系统表现不一致，&lt;/p&gt;
 &lt;p&gt;对于局部滚动，ios8以上，不加此效果，滚动的超级慢，ios8一下，不加此效果，滚动还算比较流畅&lt;/p&gt;
 &lt;p&gt;对于body滚动，ios8以上，不加此效果同样拥有弹性滚动效果。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;p&gt;持续更新中。。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
 &lt;p&gt;参考资料：  &lt;a href="http://www.nihaoshijie.com.cn/index.php/archives/455"&gt;http://www.nihaoshijie.com.cn/index.php/archives/455&lt;/a&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>CSS3 HTML5 Web开发 经验心得</category>
      <guid isPermaLink="true">https://itindex.net/detail/53907-%E7%A7%BB%E5%8A%A8-web-%E9%97%AE%E9%A2%98</guid>
      <pubDate>Sun, 14 Jun 2015 19:29:21 CST</pubDate>
    </item>
    <item>
      <title>【译文】Top 10：HTML5、JavaScript 3D游戏引擎和框架</title>
      <link>https://itindex.net/detail/53748-%E8%AF%91%E6%96%87-top-html5</link>
      <description>&lt;p&gt;  &lt;img alt="best-3d-javascript-game-engines-frameworks-webgl-html5" src="http://ido321.qiniudn.com/qiniu/1599/image/4056fbf291c8f7e871c3f62b1d87271b.png" title=""&gt;&lt;/img&gt;
&lt;/p&gt; &lt;p&gt;由于很多人都在用JavaScript、HTML5和WebGL技术创建基于浏览器的3D游戏，所有JavaScript 3D游戏引擎是一个人们主题。基于浏览器的游戏最棒的地方是平台独立，它们能在iOS、Android、Windows或其他任何平台上运行。&lt;/p&gt;
 &lt;p&gt;有很多的JavaScript能够用于创建基于浏览器、使用HTML5和WebGL的3D游戏。然后，选择一个合适的游戏引擎是一个不小的挑战，它有时能帮你完成项目或突破项目瓶颈。&lt;/p&gt;
 &lt;p&gt;为了让你的选择变的容易，我们已经通过分析大多数JavaScript 3D游戏引擎在今天的市场并列出了十大游戏引擎来帮助您用JavaScript创建非常棒的HTML5,WebGL游戏。&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://www.babylonjs.com/" target="_blank"&gt;1. Babylon.js&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;毫无疑问，Babylon.JS是最好的JavaScript3D游戏引擎，它能创建可以出售的专业级游戏。   &lt;br /&gt;Babylon.JS是David Catuhe对3D游戏引擎热爱的结果，他在用DirectX, OpenGL, 和Silverlight创建3D游戏引擎方面是经验丰富，并最终自己完成了一个游戏引擎。   &lt;br /&gt;Babylon.js的一些核心功能包含了场景图与灯光、摄像机、材料和网格、碰撞引擎、物理引擎、音频引擎和优化引擎。   &lt;br /&gt;这是一个  &lt;a href="http://www.babylonjs.com/playground" target="_blank"&gt;Babylon.js&lt;/a&gt;试验场，你可以拿你手边的游戏来试试这个游戏引擎。&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://threejs.org/" target="_blank"&gt;2.Three.js&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;Three.js是另一个广泛应用并且功能强大的JavaScript 3D库，从创建简单的3D动画到创建交互的3D游戏， 它都能实现。   &lt;br /&gt;Threejs带来的不仅是支持WebGL渲染，也支持SVG、Canvas和CSS3D渲染。然而，从游戏的角度来看，你可以只关注Threejs的WebGL渲染。   &lt;br /&gt;获取Three.js 3D引擎的源代码—  &lt;a href="https://github.com/mrdoob/three.js/" target="_blank"&gt;github&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://biz.turbulenz.com/developers" target="_blank"&gt;3. Turbulenz&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;Turbulenz是最好的游戏引擎之一，在2009年，当HTML5和WebGL还在酝酿时，它已经被推出。直到2013年，Turbulenz才基于MIT协议拥抱开源。   &lt;br /&gt;Turbulenz包含了很多功能，例如2d物理、3d物理、声音、视频和其他服务,如排行榜、multichat,支付和用户数据。   &lt;br /&gt;了解更多：  &lt;a href="http://biz.turbulenz.com/developers" target="_blank"&gt;biz.turbulenz.com&lt;/a&gt;   &lt;br /&gt;获取源代码：  &lt;a href="https://github.com/turbulenz/turbulenz_engine" target="_blank"&gt;turbulenz_engine&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://famo.us/" target="_blank"&gt;4. Famo.us&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;在HTML5 3D发展的市场中，Famo.us占据了非常重要的地位，并且它是最好的JavaScript 3D开源框架之一。对于famo.us，最好的事情就是包装了3D布局引擎，其完全继承了3D物理驱动的动画引擎。   &lt;br /&gt;了解更多—  &lt;a href="http://famo.us/docs/" target="_blank"&gt;famo.us/docs&lt;/a&gt;   &lt;br /&gt;获取源代码—  &lt;a href="https://github.com/Famous/famous" target="_blank"&gt;famous&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="https://playcanvas.com/" target="_blank"&gt;5. PlayCanvas.js&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;PlayCanvas是一个基于  &lt;strong&gt;WebGL游戏引擎&lt;/strong&gt;的企业级开源JavaScript框架，它有许多的开发工具能帮你快速创建3D游戏。PlayCanvas.js由一个专业社区创建，最初并不是开源的，但现在你可以在github上fork PlayCanvas.js，然后在你的下一个3D游戏项目中免费使用。   &lt;br /&gt;它还提供了能在浏览器中云心的云编辑器，开始使用PalyCanvas和导航到编辑器的URL一样容易。   &lt;br /&gt;了解更多—  &lt;a href="https://playcanvas.com/" target="_blank"&gt;playcanvas.com&lt;/a&gt;   &lt;br /&gt;获取源代码—  &lt;a href="https://github.com/playcanvas/engine" target="_blank"&gt;playcanvas/engine&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://www.goocreate.com/" target="_blank"&gt;6. Goo Engine&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;来自于GOO技术家族，Goo引擎有一组功能强大的JavaScript API，可通过使用HTML5和WebGL创建任何3D事物。有一个在线的编辑器goocreate，可以运行在Goo引擎上，并封装了一些功能，例如视觉三维编辑器,材质编辑器、脚本和容易发布选项等。   &lt;br /&gt;你可以通过支付一些相关的许可费用，在浏览器中使用在线编辑器。   &lt;br /&gt;尽管编辑器需要一些费用，但是Goo引擎是绝对免费的，你可以下载它并在你的3D项目中使用。   &lt;br /&gt;了解更多—-  &lt;a href="https://code.gooengine.com/" target="_blank"&gt;labs.gooengine.com&lt;/a&gt;   &lt;br /&gt;获取源代码—  &lt;a href="https://code.gooengine.com/" target="_blank"&gt;code.gooengine.com&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://www.ambiera.com/copperlicht/" target="_blank"&gt;7. CooperLicht&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;对于创建基于浏览器的游戏，CopperLIcht是最出色的3D引擎之一，也是CopperCube 3D游戏编辑器的后端引擎。   &lt;br /&gt;CopperCube是一个支持创建3D游戏和动画所需要的所有功能的编辑器，但是，它并不开源，需要一些相关的许可费用。   &lt;br /&gt;了解更多—  &lt;a href="http://www.ambiera.com/copperlicht/download.html" target="_blank"&gt;ambiera.com/copperlicht&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://voxeljs.com/" target="_blank"&gt;8. Voxel.JS&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;Voxel.Js是开源的，基于JavaScript的一个3D游戏引擎，自从它发布以来，社区成长非常快。如果你喜欢模块化方法，Voxel是一个不错的选择。   &lt;br /&gt;Voxel-engine是创建3D游戏的核心模块，其它模块可以根据需要插入。到目前为止，已经有超过200个扩展在npm上发布。   &lt;br /&gt;了解更多—  &lt;a href="https://github.com/maxogden/voxel-engine" target="_blank"&gt;maxogden/voxel-engine&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="https://www.blend4web.com/en/" target="_blank"&gt;9. Blend4Web&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;在2014年，Blend4Web作为开源的3D框架而发布，它高度集成了Triumph的3D内容创建工具“Blender”，并且本地支持Blender的节点材料、粒子系统、bullet物理引擎和其他功能。   &lt;br /&gt;获取源代码—  &lt;a href="https://www.blend4web.com/en/downloads/" target="_blank"&gt;blend4web.com/en/downloads&lt;/a&gt;&lt;/p&gt;
 &lt;div&gt;&lt;/div&gt;
 &lt;h3&gt;  &lt;a href="http://enchantjs.com/" target="_blank"&gt;10. Enchant.js&lt;/a&gt;&lt;/h3&gt;
 &lt;p&gt;Enchant.js是一个模块化的、面向对象的JavaScript框架，可用HTML5创建简单的APP和游戏。它是基于MIT协议开源的，因此开源免费使用。3D动画和游戏开源使用额外的插件（基于WebGL）创建。   &lt;br /&gt;获取源代码–  &lt;a href="https://github.com/wise9/enchant.js" target="_blank"&gt;wise9/enchant.js&lt;/a&gt;&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;本文根据@Nicolas Bevacqua的   &lt;a href="http://noeticforce.com/best-3d-javascript-game-engines-frameworks-webgl-html5" target="_blank"&gt;《best-3d-javascript-game-engines-frameworks-webgl-html5》&lt;/a&gt;所译，整个译文带有我自己的理解与思想，如果译得不好或有不对之处还请同行朋友指点。如需转载此译文，需注明英文出处：   &lt;a href="http://noeticforce.com/best-3d-javascript-game-engines-frameworks-webgl-html5" target="_blank"&gt;http://noeticforce.com/best-3d-javascript-game-engines-frameworks-webgl-html5&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
 &lt;table border="0" cellpadding="3" cellspacing="0"&gt;
    
      &lt;tr&gt;
           &lt;td colspan="5"&gt;    &lt;strong&gt;淡忘~浅思猜你喜欢&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
    
          &lt;tr&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F1116.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="&amp;#24590;&amp;#20040;&amp;#23545;HTML 5&amp;#30340;&amp;#29305;&amp;#24615;&amp;#20570;&amp;#26816;&amp;#27979;&amp;#65311;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/7dT4Oij.jpg?i=15Yx6yXs7" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        怎么对HTML 5的特性做检测？
                    &lt;/a&gt;
                &lt;/td&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F1308.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="HTML 5&amp;#65306;&amp;#32472;&amp;#21046;&amp;#26059;&amp;#36716;&amp;#30340;&amp;#22826;&amp;#26497;&amp;#22270;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/lFJYnCwM.jpg?i=9LXHq6jw" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        HTML 5：绘制旋转的太极图
                    &lt;/a&gt;
                &lt;/td&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F1293.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="&amp;#12304;&amp;#35793;&amp;#12305;&amp;#21033;&amp;#29992;HTML 5&amp;#20013;&amp;#30340;Menu&amp;#21644;Menuitem&amp;#20803;&amp;#32032;&amp;#24555;&amp;#36895;&amp;#21019;&amp;#24314;&amp;#33756;&amp;#21333;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/5AlZA4D5.jpg?i=u78WlRr7" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        【译】利用HTML 5中的Menu和Menuitem元素快速创建菜单
                    &lt;/a&gt;
                &lt;/td&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F949.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="&amp;#21021;&amp;#35782;HTML 5&amp;#65306;&amp;#20851;&amp;#20110;&amp;#23427;&amp;#30340;&amp;#19977;&amp;#20010;&amp;#19977;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/1dhvu1uY3.jpg?i=af7W8CRC" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        初识HTML 5：关于它的三个三
                    &lt;/a&gt;
                &lt;/td&gt;
                   &lt;td valign="top" width="102"&gt;
                        &lt;a href="http://app.wumii.com/ext/redirect?url=http%3A%2F%2Fwww.ido321.com%2F1069.html&amp;from=http%3A%2F%2Fwww.ido321.com%2F1599.html" target="_blank" title="HTML 5 API&amp;#30340;&amp;#8221;&amp;#21069;&amp;#29983;&amp;#20170;&amp;#19990;&amp;#8221;"&gt;
                             &lt;img height="96px" src="http://wumii-cc.wumii.cn/site_images/ti/Zo7Qg2Fz.jpg?i=6ARMefIk" width="96px"&gt;&lt;/img&gt;     &lt;br /&gt;
                        HTML 5 API的”前生今世”
                    &lt;/a&gt;
                &lt;/td&gt;
        &lt;/tr&gt;
    
      &lt;tr&gt;
           &lt;td align="right" colspan="5"&gt;
                &lt;a href="http://www.wumii.com/widget/relatedItems" target="_blank" title="&amp;#26080;&amp;#35269;&amp;#20851;&amp;#32852;&amp;#25512;&amp;#33616;"&gt;
                无觅
            &lt;/a&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt; &lt;p&gt;转载请注明：  &lt;a href="http://www.ido321.com"&gt;淡忘~浅思&lt;/a&gt; »   &lt;a href="http://www.ido321.com/1599.html"&gt;【译文】Top 10：HTML5、JavaScript 3D游戏引擎和框架&lt;/a&gt;&lt;/p&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>HTML JavaScript HTML5 js 游戏</category>
      <guid isPermaLink="true">https://itindex.net/detail/53748-%E8%AF%91%E6%96%87-top-html5</guid>
      <pubDate>Wed, 24 Jun 2015 12:13:19 CST</pubDate>
    </item>
    <item>
      <title>一些有用的HTML5 pattern</title>
      <link>https://itindex.net/detail/53718-html5-pattern</link>
      <description>&lt;p&gt;最近在做手机页面时，遇到数字输入的键盘的问题，之前的做法只是一刀切的使用   &lt;code&gt;type=&amp;quot;tel&amp;quot;&lt;/code&gt;，不过一直觉得九宫格的电话号码键盘上的英文字母太碍事了。于是想要尝试其它的实现方案，最终的结论却令人沮丧。不过也趁机详细了解了下  &lt;code&gt;pattern&lt;/code&gt;这个属性。 &lt;/p&gt;

 &lt;h3&gt;type=&amp;quot;tel&amp;quot; 和 type=&amp;quot;number&amp;quot; 的区别&lt;/h3&gt;

 &lt;p&gt;这里还是先那么先交代一下最初遇到的问题。其实无论是  &lt;code&gt;tel&lt;/code&gt;还是  &lt;code&gt;number&lt;/code&gt;都不是完美的：&lt;/p&gt;

 &lt;h4&gt;type=&amp;quot;tel&amp;quot;&lt;/h4&gt;

 &lt;ul&gt;
  &lt;li&gt;优点是iOS和Android的键盘表现都差不多&lt;/li&gt;
  &lt;li&gt;缺点是那些字母好多余，虽然我没有强迫症但还是感觉怪怪的啊。
   &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/type_tel.jpg"&gt;&lt;/img&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;h4&gt;type=&amp;quot;number&amp;quot;&lt;/h4&gt;

 &lt;ul&gt;
  &lt;li&gt;优点是Android下实现的一个真正的数字键盘&lt;/li&gt;
  &lt;li&gt;缺点一：iOS下不是九宫格键盘，输入不方便&lt;/li&gt;
  &lt;li&gt;缺点二：旧版Android（包括微信所用的X5内核）在输入框后面会有超级   &lt;strong&gt;鸡肋的小尾巴&lt;/strong&gt;，好在Android 4.4.4以后给去掉了。&lt;/li&gt;
&lt;/ul&gt;

 &lt;p&gt;  &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/type_number.jpg"&gt;&lt;/img&gt;
  &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/numberarrow.jpg"&gt;&lt;/img&gt;
不过对于缺点二，我们可以用webkit私有的伪元素给fix掉：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;input[type=number]::-webkit-inner-spin-button,  
    input[type=number]::-webkit-outer-spin-button { 
        -webkit-appearance: none; 
        appearance: none; 
        margin: 0; 
    }
&lt;/code&gt;&lt;/pre&gt;

 &lt;h3&gt;pattern属性&lt;/h3&gt;

 &lt;p&gt;  &lt;code&gt;pattern&lt;/code&gt;用于验证表单输入的内容，通常HTML5的  &lt;code&gt;type&lt;/code&gt;属性，比如  &lt;code&gt;email&lt;/code&gt;、  &lt;code&gt;tel&lt;/code&gt;、  &lt;code&gt;number&lt;/code&gt;、  &lt;code&gt;data&lt;/code&gt;类、  &lt;code&gt;url&lt;/code&gt;等，已经自带了简单的数据格式验证功能了，加上pattern后，前端部分的验证更加简单高效了。&lt;/p&gt;

 &lt;p&gt;显而易见，  &lt;code&gt;pattern&lt;/code&gt;的属性值要用正则表达式。&lt;/p&gt;

 &lt;h3&gt;实例&lt;/h3&gt;

 &lt;h4&gt;简单的数字验证&lt;/h4&gt;

 &lt;p&gt;数字的验证有两个：  &lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;&amp;lt;input type=&amp;quot;number&amp;quot; pattern=&amp;quot;\d&amp;quot;&amp;gt;  
&amp;lt;input type=&amp;quot;number&amp;quot; pattern=&amp;quot;[0-9]*&amp;quot;&amp;gt;  
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;br /&gt;
  &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/type_number-1.jpg"&gt;&lt;/img&gt;
对表单验证来说，这两个正则的作用是一样的，表现的话差异就很大：&lt;/p&gt;

 &lt;ul&gt;
  &lt;li&gt;iOS中，   &lt;strong&gt;只有    &lt;code&gt;[0-9]\*&lt;/code&gt;才可以调起九宫格数字键盘&lt;/strong&gt;，   &lt;code&gt;\d&lt;/code&gt; 无效&lt;/li&gt;
  &lt;li&gt;Android 4.4以下(包括X5内核)，两者都调起数字键盘；&lt;/li&gt;
  &lt;li&gt;Android 4.4.4以上，只认    &lt;code&gt;type&lt;/code&gt; 属性，也就是说，如果上面的代码将    &lt;code&gt;type=&amp;quot;number&amp;quot;&lt;/code&gt; 改为    &lt;code&gt;type=&amp;quot;text&amp;quot;&lt;/code&gt; ，将调起全键盘而不会是九宫格数字键盘。&lt;/li&gt;
&lt;/ul&gt;

 &lt;h4&gt;常用的正则表达式&lt;/h4&gt;

 &lt;p&gt;  &lt;code&gt;pattern&lt;/code&gt;的用法都一样，这里不再啰嗦各种详细写法了，只是列出来一些常用的正则就好了：&lt;/p&gt;

 &lt;ul&gt;
  &lt;li&gt;信用卡     &lt;code&gt;[0-9]{13,16}&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;银联卡     &lt;code&gt;^62[0-5]\d{13,16}$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Visa:    &lt;code&gt;^4[0-9]{12}(?:[0-9]{3})?$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;万事达：   &lt;code&gt;^5[1-5][0-9]{14}$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;QQ号码：    &lt;code&gt;[1-9][0-9]{4,14}&lt;/code&gt;  &lt;/li&gt;
  &lt;li&gt;手机号码：   &lt;code&gt;^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;身份证：   &lt;code&gt;^([0-9]){7,18}(x|X)?$&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;密码：   &lt;code&gt;^[a-zA-Z]\w{5,17}$&lt;/code&gt; 字母开头，长度在6~18之间，只能包含字母、数字和下划线&lt;/li&gt;
  &lt;li&gt;强密码：   &lt;code&gt;^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$&lt;/code&gt; 包含大小写字母和数字的组合，不能使用特殊字符，长度在8-10之间&lt;/li&gt;
  &lt;li&gt;7个汉字或14个字符：   &lt;code&gt;^[\u4e00-\u9fa5]{1,7}$|^[\dA-Za-z_]{1,14}$&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

 &lt;h3&gt;浏览器支持&lt;/h3&gt;

 &lt;p&gt;很不幸，pattern的浏览器支持很惨：
  &lt;img alt="" src="http://www.qianduan.net/content/images/2015/06/patternsupport.jpg"&gt;&lt;/img&gt;
  &lt;em&gt;   &lt;a href="http://caniuse.com/#feat=input-pattern"&gt;via Can I Use&lt;/a&gt;&lt;/em&gt;   &lt;br /&gt;
但是如果只是如文章开头提到的改  &lt;strong&gt;数字键盘&lt;/strong&gt;的话，iOS和Android都是没有问题的。&lt;/p&gt; &lt;img alt="" height="1" src="http://feeds.feedburner.com/~r/qianduannet/~4/uQ9p308BqEc" width="1"&gt;&lt;/img&gt;&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>HTML5 表单 正则</category>
      <guid isPermaLink="true">https://itindex.net/detail/53718-html5-pattern</guid>
      <pubDate>Thu, 18 Jun 2015 21:42:17 CST</pubDate>
    </item>
    <item>
      <title>HTML5本地裁剪图片</title>
      <link>https://itindex.net/detail/53899-html5-%E5%9B%BE%E7%89%87</link>
      <description>&lt;h2&gt;先上效果图：&lt;/h2&gt;

 &lt;p&gt;  &lt;img alt="&amp;#26367;&amp;#20195;&amp;#25991;&amp;#23383;" src="https://wt-prj.oss.aliyuncs.com/0d06af79c49d4e08abb1ab3f7ab6e860/a08ff4d5-9228-4a31-b4d5-50b447f73b5e.gif"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;我们首先需要创建一个  &lt;code&gt;index.html&lt;/code&gt;文件，里面写上一些简单的  &lt;code&gt;html&lt;/code&gt;和  &lt;code&gt;css&lt;/code&gt;代码：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;HTML5 Crop Image&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
body{text-align:center;}
#label{border:1px solid #ccc;background-color:#fff;text-align:center;height:300px; width:300px;margin:20px auto;position:relative;}
#get_image{position:absolute;}
#edit_pic{position:absolute;display:none;background:#000;}
#cover_box{position: absolute;z-index: 9999;display:none;top:0px;left:0px;}
#show_edit{margin: 0 auto;display:inline-block;}
#show_pic{height:100px;width:100px;border:2px solid #000;overflow:hidden;margin:0 auto;display:inline-block; }
&amp;lt;/style&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;input type=&amp;quot;file&amp;quot; name=&amp;quot;file&amp;quot; id=&amp;quot;post_file&amp;quot;&amp;gt;
&amp;lt;button id=&amp;quot;save_button&amp;quot;&amp;gt;SAVE&amp;lt;/button&amp;gt;


&amp;lt;div id=&amp;quot;label&amp;quot;&amp;gt;
    &amp;lt;canvas id=&amp;quot;get_image&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;
    &amp;lt;p&amp;gt;
        &amp;lt;canvas id=&amp;quot;cover_box&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;
        &amp;lt;canvas id=&amp;quot;edit_pic&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;
    &amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;




&amp;lt;p&amp;gt;
    &amp;lt;span id=&amp;quot;show_edit&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;
    &amp;lt;span id=&amp;quot;show_pic&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/p&amp;gt;


&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;js/js.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;以上的三个  &lt;code&gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;标签都是用来处理跟图片相关的内容的，详细的处理会在后续的js代码中给出。而  &lt;code&gt;id&lt;/code&gt;为  &lt;code&gt;show_edit&lt;/code&gt; 和  &lt;code&gt;id&lt;/code&gt;为  &lt;code&gt;show_pic&lt;/code&gt;这两个是为了图片的预览和查看最后的图片生成结果。做完html和css的布局之后，我们就可以进入js代码，实现本节课的图片裁剪功能。&lt;/p&gt;

 &lt;h2&gt;实现图片裁剪的init函数：&lt;/h2&gt;

 &lt;pre&gt;  &lt;code&gt;var postFile = { 
        init: function() {
        var t = this;
        t.regional = document.getElementById(&amp;apos;label&amp;apos;);
        t.getImage = document.getElementById(&amp;apos;get_image&amp;apos;);
        t.editPic = document.getElementById(&amp;apos;edit_pic&amp;apos;);
        t.editBox = document.getElementById(&amp;apos;cover_box&amp;apos;);
        t.px = 0;    //background image x
        t.py = 0;    //background image y
        t.sx = 15;    //crop area x
        t.sy = 15;    //crop area y
        t.sHeight = 150;    //crop area height
        t.sWidth = 150    //crop area width
        document.getElementById(&amp;apos;post_file&amp;apos;).addEventListener(&amp;quot;change&amp;quot;, t.handleFiles, false);
    },

}

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;我们将所有的函数和变量都是封装在  &lt;code&gt;postFile&lt;/code&gt;这个对象里面的，上面的  &lt;code&gt;init&lt;/code&gt;方法主要是设置一些初始值&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;t.px = 0;    
t.py = 0;    
t.sx = 15;   
t.sy = 15;   
t.sHeight = 150;    
t.sWidth = 150   

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;以上的  &lt;code&gt;t.px&lt;/code&gt;   &lt;code&gt;t.py&lt;/code&gt;分别表示在实时预览区域的背景图片的坐标；  &lt;code&gt;t.sx&lt;/code&gt;，  &lt;code&gt;t.sy&lt;/code&gt;，   &lt;code&gt;t.sHeight&lt;/code&gt;，   &lt;code&gt;t.sWidth&lt;/code&gt;分别表示图片的横纵坐标和宽高。&lt;/p&gt;

 &lt;p&gt;并且我们通过  &lt;code&gt;document.getElementById&lt;/code&gt;获取了多个稍后需要操作的元素，注意到：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;document.getElementById(&amp;apos;post_file&amp;apos;).addEventListener(&amp;quot;change&amp;quot;, t.handleFiles, false);

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;我们通过监听  &lt;code&gt;id&lt;/code&gt;为  &lt;code&gt;post_file&lt;/code&gt;的  &lt;code&gt;input&lt;/code&gt;表单的  &lt;code&gt;change&lt;/code&gt;事件来处理用户上传的文件，在这我们交给了  &lt;code&gt;handleFiles&lt;/code&gt;函数来处理，所以下面我们就来实现  &lt;code&gt;handleFiles&lt;/code&gt;函数。&lt;/p&gt;

 &lt;h2&gt;实现handleFiles，获取文件，读取文件并生成url&lt;/h2&gt;

 &lt;pre&gt;  &lt;code&gt; handleFiles: function() {
        var fileList = this.files[0];
        var oFReader = new FileReader();
        oFReader.readAsDataURL(fileList);
        oFReader.onload = function (oFREvent) { 
            postFile.paintImage(oFREvent.target.result);
        };
    },

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;上面这几行代码就可以基本实现  &lt;code&gt;handleFiles&lt;/code&gt;的处理功能，我们在这里就使用了HTML5的File API，首先通过  &lt;code&gt;new FileReader()&lt;/code&gt;来实例化一个  &lt;code&gt;FileReader&lt;/code&gt;对象  &lt;code&gt;oFReader&lt;/code&gt;，再调用其  &lt;code&gt;readAsDataURL()&lt;/code&gt;方法将文件的内容读取出来并处理成base64编码的格式。&lt;/p&gt;

 &lt;p&gt;如果你对  &lt;code&gt;var fileList = this.files[0];&lt;/code&gt;有疑问，不妨在在这里打印出来看看：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;console.log(this.files);

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;你将会看到类似于这样的打印输出：&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#26367;&amp;#20195;&amp;#25991;&amp;#23383;" src="https://wt-prj.oss.aliyuncs.com/0d06af79c49d4e08abb1ab3f7ab6e860/c07413b1-bacb-408f-b4e3-b734bccedc90.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;最后，当文件读取完毕并完成加载的时候，我们通过  &lt;code&gt;postFile.paintImage(oFREvent.target.result)&lt;/code&gt;处理我们读取到的图片，说白了就是将读取到的图片数据重新绘画到浏览器上。&lt;/p&gt;

 &lt;p&gt;关于  &lt;code&gt;oFREvent&lt;/code&gt;究竟是什么东西，你可以通过  &lt;code&gt;console.log(oFREvent)&lt;/code&gt;来查看。你还可以查看这里的链接来获取更多的FileReader的知识：&lt;/p&gt;

 &lt;p&gt;  &lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader" rel="nofollow"&gt;https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader&lt;/a&gt;&lt;/p&gt;

 &lt;h2&gt;实现paintImage函数&lt;/h2&gt;

 &lt;pre&gt;  &lt;code&gt; paintImage: function(url) {
        var t = this;
        var createCanvas = t.getImage.getContext(&amp;quot;2d&amp;quot;);
        var img = new Image();
        img.src = url;
        img.onload = function(){

            if ( img.width &amp;lt; t.regional.offsetWidth &amp;amp;&amp;amp; img.height &amp;lt; t.regional.offsetHeight) {
                t.imgWidth = img.width;
                t.imgHeight = img.height;

            } else {
                var pWidth = img.width / (img.height / t.regional.offsetHeight);
                var pHeight = img.height / (img.width / t.regional.offsetWidth);
                t.imgWidth = img.width &amp;gt; img.height ? t.regional.offsetWidth : pWidth;
                t.imgHeight = img.height &amp;gt; img.width ? t.regional.offsetHeight : pHeight;
            }
            t.px = (t.regional.offsetWidth - t.imgWidth) / 2 + &amp;apos;px&amp;apos;;
            t.py = (t.regional.offsetHeight - t.imgHeight) / 2 + &amp;apos;px&amp;apos;;

            t.getImage.height = t.imgHeight;
            t.getImage.width = t.imgWidth;
            t.getImage.style.left = t.px;
            t.getImage.style.top = t.py;

            createCanvas.drawImage(img,0,0,t.imgWidth,t.imgHeight);
            t.imgUrl = t.getImage.toDataURL();
            t.cutImage(); 
            t.drag();
        };
    },


&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;以上最重要的就是根据容器的大小使用canvas绘制图片。在上一步使用File API的FileReader已经得到了需要上传图片的地址了(  &lt;code&gt;oFREvent.target.result&lt;/code&gt;这个值)，接下来需要使用canvas把这个图片绘制出来。我们首先使用到  &lt;code&gt;getImage.getContext&lt;/code&gt;来获取  &lt;code&gt;&amp;lt;canvas id=&amp;quot;get_image&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/code&gt;的2d内容，简单理解就是图像内容，然后利用  &lt;code&gt;new Image()&lt;/code&gt;来得到一个  &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;标签，设置  &lt;code&gt;src属&lt;/code&gt;性的值，如果你  &lt;code&gt;console.log(img)&lt;/code&gt;,得到的大概是这样的结果：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;&amp;lt;img src=&amp;quot;images/background.png&amp;quot; &amp;gt;

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;在  &lt;code&gt;img.onload&lt;/code&gt;函数里，我们的主要目的是为了将图片按照原大小等比例地重画出来，所以才有if条件判断，最后我们通过  &lt;code&gt;createCanvas.drawImage(img,0,0,t.imgWidth,t.imgHeight);&lt;/code&gt;这一行代码来实现真正的绘画图片，效果大概是这样的：&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#26367;&amp;#20195;&amp;#25991;&amp;#23383;" src="https://wt-prj.oss.aliyuncs.com/0d06af79c49d4e08abb1ab3f7ab6e860/7c002e9b-1a79-421e-ad23-c333f56a56bf.png"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;p&gt;这里为什么不直接插入img而用canvas重新绘制呢，这不是多此一举了吗？其实不然。如果用img直接插入页面，就无法自适应居中了，如果使用canvas绘制图片，不但能使图片自适应居中以及能等比例缩放，并且方便把图片的坐标，尺寸大小传给后来的遮罩层(  &lt;code&gt;id&lt;/code&gt;为  &lt;code&gt;label&lt;/code&gt;的div)，这样能根据图片的坐标以及图片的尺寸大小来绘制遮罩层。&lt;/p&gt;

 &lt;p&gt;如果你对drawImage()有任何疑问，点击下面的链接进行详细的了解：&lt;/p&gt;

 &lt;p&gt;  &lt;a href="https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/drawImage" rel="nofollow"&gt;https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContex...&lt;/a&gt;&lt;/p&gt;

 &lt;p&gt;到这里，前期的一小半工作其实已经完成了，我们按照上面的思路，接下来就把  &lt;code&gt;cutImage&lt;/code&gt;和  &lt;code&gt;drag&lt;/code&gt;这两个方法实现就可以了。&lt;/p&gt;

 &lt;h2&gt;实现cutImage方法&lt;/h2&gt;

 &lt;p&gt;在上一张图片中，我们其实很清楚地看到了两个明暗不一的层，这是因为我们根据背景图的坐标和尺寸来绘制遮罩层覆盖在背景上面，并且使用canvas的  &lt;code&gt;clearRect&lt;/code&gt;方法清空出一块裁剪区域，使之与不裁剪的地方做明暗对比，这样的目的一个是为了更好地看到对比，一个就是为了用户体验：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;cutImage: function() {
    var t = this;

    //绘制遮罩层：
    t.editBox.height = t.imgHeight;
    t.editBox.width = t.imgWidth;
    t.editBox.style.display = &amp;apos;block&amp;apos;;
    t.editBox.style.left = t.px;
    t.editBox.style.top = t.py;

    var cover = t.editBox.getContext(&amp;quot;2d&amp;quot;);
    cover.fillStyle = &amp;quot;rgba(0, 0, 0, 0.5)&amp;quot;;
    cover.fillRect (0,0, t.imgWidth, t.imgHeight);
    cover.clearRect(t.sx, t.sy, t.sHeight, t.sWidth);

    //预览图片

    document.getElementById(&amp;apos;show_edit&amp;apos;).style.background = &amp;apos;url(&amp;apos; + t.imgUrl + &amp;apos;)&amp;apos; + -t.sx + &amp;apos;px &amp;apos; + -t.sy + &amp;apos;px no-repeat&amp;apos;;
    document.getElementById(&amp;apos;show_edit&amp;apos;).style.height = t.sHeight + &amp;apos;px&amp;apos;;
    document.getElementById(&amp;apos;show_edit&amp;apos;).style.width = t.sWidth + &amp;apos;px&amp;apos;;
},

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;以上的  &lt;code&gt;cutImage&lt;/code&gt;方法主要是负责两个事情，一个是制造遮罩层，一个是利用css的  &lt;code&gt;background&lt;/code&gt;属性将选中的裁剪区域实时预览。&lt;/p&gt;

 &lt;p&gt;  &lt;code&gt;但是需要注意的是，这里的遮罩层仅仅是用来做显示效果，并没有做裁剪图片的工作。&lt;/code&gt;&lt;/p&gt;

 &lt;h2&gt;编写drag方法&lt;/h2&gt;

 &lt;p&gt;在很多web应用中，使用截图上传头像功能时我们希望能裁剪到满意的图片，所以裁剪框就需要不停的变动才得以裁剪出完美的图片。前几步已经把裁剪图片的基本功能做出来了，所以现在需要做的就是裁剪框跟进鼠标的移动来实时裁剪图片&lt;/p&gt;

 &lt;p&gt;先来一张预览图片：&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="&amp;#26367;&amp;#20195;&amp;#25991;&amp;#23383;" src="https://wt-prj.oss.aliyuncs.com/0d06af79c49d4e08abb1ab3f7ab6e860/5d81ad36-fea1-4c0d-bff2-e8b3d00378a4.gif"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt; drag: function() {
        var t = this;
        var draging = false;
        var startX = 0;
        var startY = 0;

        document.getElementById(&amp;apos;cover_box&amp;apos;).onmousemove = function(e) {
            var pageX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
            var pageY = e.pageY - ( t.regional.offsetTop + this.offsetTop );

            if ( pageX &amp;gt; t.sx &amp;amp;&amp;amp; pageX &amp;lt; t.sx + t.sWidth &amp;amp;&amp;amp; pageY &amp;gt; t.sy &amp;amp;&amp;amp; pageY &amp;lt; t.sy + t.sHeight ) {
                this.style.cursor = &amp;apos;move&amp;apos;;

                this.onmousedown = function(){
                    draging = true;

                    t.ex = t.sx;
                    t.ey = t.sy;

                    startX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
                    startY = e.pageY - ( t.regional.offsetTop + this.offsetTop );

                }
                window.onmouseup = function() {
                    draging = false;
                }

                if (draging) {

                    if ( t.ex + (pageX - startX) &amp;lt; 0 ) {
                        t.sx = 0;
                    } else if ( t.ex + (pageX - startX) + t.sWidth &amp;gt; t.imgWidth) {
                        t.sx = t.imgWidth - t.sWidth;
                    } else {
                        t.sx = t.ex + (pageX - startX);
                    };

                    if (t.ey + (pageY - startY) &amp;lt; 0) {
                        t.sy = 0;
                    } else if ( t.ey + (pageY - startY) + t.sHeight &amp;gt; t.imgHeight ) {
                        t.sy = t.imgHeight - t.sHeight;
                    } else {
                        t.sy = t.ey + (pageY - startY);
                    }

                    t.cutImage();
                }
            } else{
                this.style.cursor = &amp;apos;auto&amp;apos;;
            }
        };
    }


&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;这个方法里要理解一下几个主要的点：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;var pageX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
var pageY = e.pageY - ( t.regional.offsetTop + this.offsetTop );

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;我们通过上面两行代码来获取  &lt;code&gt;鼠标距离背景图片的距离&lt;/code&gt;，  &lt;code&gt;e.pageX&lt;/code&gt;代表鼠标到浏览器左边缘的距离，  &lt;code&gt;t.regional.offsetLeft + this.offsetLeft&lt;/code&gt;可以计算出图片到浏览器的左边边缘的距离。上边的距离同理可得。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt; if ( pageX &amp;gt; t.sx &amp;amp;&amp;amp; pageX &amp;lt; t.sx + t.sWidth &amp;amp;&amp;amp; pageY &amp;gt; t.sy &amp;amp;&amp;amp; pageY &amp;lt; t.sy + t.sHeight )

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;在理解了  &lt;code&gt;鼠标距离背景图片的距离&lt;/code&gt;距离之后，这个应该很容易理解：就是判断鼠标是否在图片的区域内部。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt;t.ex = t.sx; 
t.ey = t.sy;

startX = e.pageX - ( t.regional.offsetLeft + this.offsetLeft );
startY = e.pageY - ( t.regional.offsetTop + this.offsetTop );


&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;这两段代码也是要拿出来说说的，头两行是为了记录上一次截图时候的坐标（没有上一次就是初始化的时候的坐标）；后两行记录鼠标按下时候的坐标。你都可以通过  &lt;code&gt;console.log()&lt;/code&gt;来分别查看这几个值。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt;if (draging) {


    if ( t.ex + (pageX - startX) &amp;lt; 0 ) {
        t.sx = 0;
    } else if ( t.ex + (pageX - startX) + t.sWidth &amp;gt; t.imgWidth) {
        t.sx = t.imgWidth - t.sWidth;
    } else {
        t.sx = t.ex + (pageX - startX);
    };

    if (t.ey + (pageY - startY) &amp;lt; 0) {
        t.sy = 0;
    } else if ( t.ey + (pageY - startY) + t.sHeight &amp;gt; t.imgHeight ) {
        t.sy = t.imgHeight - t.sHeight;
    } else {
        t.sy = t.ey + (pageY - startY);
    }

    t.cutImage();
}


&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;上面这一行代码就是说：如果实在拖动的情况下，我们需要根据坐标的变化来实时更新  &lt;code&gt;t.sx&lt;/code&gt;和  &lt;code&gt;t.sy&lt;/code&gt;的值,并且实时调用  &lt;code&gt;cutImage&lt;/code&gt;方法实现预览。&lt;/p&gt;

 &lt;p&gt;  &lt;code&gt;移动时裁剪区域的坐标 = 上次记录的定位 + (当前鼠标的位置 - 按下鼠标的位置)&lt;/code&gt;&lt;/p&gt;

 &lt;h2&gt;最后，将裁剪的图片进行保存&lt;/h2&gt;

 &lt;p&gt;从一开始，我们就有一个save按钮在页面上，我们的目的就是在用户点击save按钮的时候，将裁剪出来的图片保存到预览右边的方框内，于是，我们在  &lt;code&gt;init&lt;/code&gt;方法里面添加下面的代码：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;   &lt;br /&gt;document.getElementById(&amp;apos;save_button&amp;apos;).onclick = function() {
    t.editPic.height = t.sHeight;
    t.editPic.width = t.sWidth;
    var ctx = t.editPic.getContext(&amp;apos;2d&amp;apos;);
    var images = new Image();
    images.src = t.imgUrl;

    images.onload = function(){
        ctx.drawImage(images,t.sx, t.sy, t.sHeight, t.sWidth, 0, 0, t.sHeight, t.sWidth); 
        document.getElementById(&amp;apos;show_pic&amp;apos;).getElementsByTagName(&amp;apos;img&amp;apos;)[0].src = t.editPic.toDataURL();
    }

}

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;跟实现  &lt;code&gt;painImage&lt;/code&gt;方法类似，首先监听save按钮的点击事件，然后我们将选中区域的图片利用  &lt;code&gt;drawImage&lt;/code&gt;方法绘制出来，最后利用  &lt;code&gt;toDataURL&lt;/code&gt;方法转换成base64编码格式并将该值赋予  &lt;code&gt;show_pic&lt;/code&gt;下  &lt;code&gt;img&lt;/code&gt;的  &lt;code&gt;src&lt;/code&gt;属性，这样就完成了图片的裁剪保存。效果如图：&lt;/p&gt;

 &lt;h2&gt;调用init方法&lt;/h2&gt;

 &lt;p&gt;最后别忘了在开始之前调用  &lt;code&gt;init&lt;/code&gt;方法，在js文件的最后一行加上：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;postFile.init();

&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;最后的代码布局应该时这样的：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;var postFile = {

    init: function() {
        //codes
        },

    handleFiles: function() {
        //codes
        },

    //...methods
}
postFile.init();
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;strong&gt;Happy Hacking&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>html5 canvas 图片处理</category>
      <guid isPermaLink="true">https://itindex.net/detail/53899-html5-%E5%9B%BE%E7%89%87</guid>
      <pubDate>Wed, 15 Jul 2015 15:55:24 CST</pubDate>
    </item>
    <item>
      <title>移动开发之总结</title>
      <link>https://itindex.net/detail/52570-%E7%A7%BB%E5%8A%A8-%E5%BC%80%E5%8F%91</link>
      <description>&lt;p&gt;1、-webkit-tap-highlight-color:rgba(255,255,255,0)可以同时屏蔽ios和android下点击元素时出现的阴影。  &lt;br /&gt;
备注：transparent的属性值在android下无效。&lt;/p&gt;

 &lt;p&gt;2、-webkit-appearance:none可以同时屏蔽输入框怪异的内阴影。&lt;/p&gt;

 &lt;p&gt;3、-webkit-transform:translate3d(0, 0, 0)在ios下可以让动画更加流畅（这个属性会调用硬件加速模式），但是在android下不可乱用，很多见所未见的bug就是因为这个。&lt;/p&gt;

 &lt;p&gt;4、@-webkit-keyframes可以预定义很多你所想到的动画，然后通过-webkit-transition来调用。&lt;/p&gt;

 &lt;p&gt;5、-webkit-background-size可以做高清图标，不过一些低版本的android只能识别background-size，所以有必要两个都要写上；用这个属性的时候推荐树勇cover这个值，可以自动去匹配宽和高。&lt;/p&gt;

 &lt;p&gt;6、text-shadow多用这个属性，可以美化文字效果。&lt;/p&gt;

 &lt;p&gt;7、border-radius、box-shadow、gradient、border-image，不解释，可以精简代码。&lt;/p&gt;

 &lt;p&gt;8、android、ios4及以下，固定宽/高块级元素的overflow:scroll/auto失效，属于浏览器的bug，可借助第三方工具实现。&lt;/p&gt;

 &lt;p&gt;9、ios5+可以通过scrollTo(0,0)来自动隐藏浏览器地址栏。&lt;/p&gt;

 &lt;p&gt;10、width可是宽度，initial-scale初始化缩放比例，maximum-scale允许用户缩放的最大比例，minimum-scale允许用户缩放的最小比例，user-scalable是否允许用户缩放。  &lt;br /&gt;
11、允许用户添加到主屏幕，并提供webapp的支持。&lt;/p&gt;

 &lt;p&gt;12、css3动画会影响你的自动聚焦，所以自动聚焦要在动画执行之前来做，或者直接舍弃。&lt;/p&gt;

 &lt;p&gt;13、使用media query适配不同屏幕。&lt;/p&gt;

 &lt;p&gt;14、如果涉及较多域外链接，DNS Prefetching可以帮你做DNS预解析。&lt;/p&gt;

 &lt;p&gt;15、如果你希望你的站点更多地在SNS上传播，那么Open Graph Protocol会比较适合你。&lt;/p&gt;

 &lt;p&gt;16、当用iScroll时候，不能使用:focus{outline:0}伪类，否则滑动会卡。&lt;/p&gt;

 &lt;p&gt;17、-webkit-user-select: none; 禁止用户进行复制.选择。&lt;/p&gt;

 &lt;p&gt;========  &lt;br /&gt;
lazyload.js 实现列表图片异步加载&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;//先载入jquery
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
//再载入lazyload
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;http://www.jo2.org/js/jquery.lazyload.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;



&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;

jQuery(document).ready(

function($){

$(&amp;quot;img&amp;quot;).lazyload({

     placeholder : &amp;quot;异步图片加载地址&amp;quot;, //加载图片前的占位图片

     effect : &amp;quot;fadeIn&amp;quot; //加载图片使用的效果(淡入)

});

});

&amp;lt;/script&amp;gt;


&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>html5 css3 jquery</category>
      <guid isPermaLink="true">https://itindex.net/detail/52570-%E7%A7%BB%E5%8A%A8-%E5%BC%80%E5%8F%91</guid>
      <pubDate>Thu, 22 Jan 2015 14:13:24 CST</pubDate>
    </item>
    <item>
      <title>Youtube网站正式全面使用HTML5&lt;video&gt;播放视频</title>
      <link>https://itindex.net/detail/52655-youtube-%E7%BD%91%E7%AB%99-html5</link>
      <description>&lt;p&gt;四年前，Youtube官方曾宣布在网站上  &lt;a href="http://apiblog.youtube.com/2010/06/flash-and-html5-tag.html"&gt;实验性的支持HTML5&amp;lt;video&amp;gt;标记&lt;/a&gt;，测试它跟使用Flash对比的效果。当时，由于诸多的限制，无法将这种技术广泛的运用到视频播放中。最重要的原因是，HTML5缺乏对Adaptive Bitrate (ABR)的支持，这种技术能让视频进行少量的缓冲就能播放。&lt;/p&gt;
 &lt;p&gt;经过最近的4年发展，浏览器的发展和各种广泛的交流促使HTML5技术和实际视频运用之间的差距越来越小。现在，在谷歌浏览器、IE11、苹果浏览器以及最新版的火狐浏览器中，使用HTML5&amp;lt;video&amp;gt;播放将成为缺省设置。&lt;/p&gt;
 &lt;p&gt;HTML5的优势并不是仅仅体现在web浏览器在，它还能运用到智能电视和其它流媒体设备中。下面是HTML5的一些关键技术指标：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;支持 ABR（Adaptive Bitrate，自适应比特率）：ABR 能够有效减少缓冲时间，能利用媒体源拓展（   &lt;a href="http://w3c.github.io/media-source/" target="_blank"&gt;MediaSourse Extensions&lt;/a&gt;）使视频 / 直播在 Chrome, IE11, Safari 8 还有 beta 版的 Firebox 等众多浏览器中流畅播放。HTML5 也能照顾到多种流媒体设备，包括目前主流的 Xbox One，Playstation 4 和 Chromecast 等。&lt;/li&gt;
  &lt;li&gt;支持VP9 codec：VP9 codec 能有效节省带宽、加载时间和文件的大小。YouTube 团队鼓励开发者使用   &lt;a href="https://developers.google.com/youtube/iframe_api_reference" target="_blank"&gt;iframe API&lt;/a&gt;代替 Flash，这样在很多不支持 Flash 的设备上也能进行视频的浏览。&lt;/li&gt;
  &lt;li&gt;加密媒体扩展 (   &lt;a href="https://w3c.github.io/encrypted-media/" target="_blank"&gt;Encrypted Media Extensions&lt;/a&gt;)：通过这个扩展和正常加密的措施的结合，YouTube 的视频能够通过简单的配置，在不同平台上对多种内容保护技术进行支撑。简化了视频传输中由于加密保护与内容高度整合带来的不便，可以减少视频播放中的卡顿。&lt;/li&gt;
  &lt;li&gt;WebRTC 和   &lt;a href="http://www.webhek.com/fullscreen"&gt;全屏幕 API 支持&lt;/a&gt;：YouTube 开发者可以通过 WebRTC 在浏览器内开发直播工具插件。有了 HTML5 的全屏 API，YouTube 在标准的 HTML UI 下，就可提供沉浸式的全屏观看体验。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;YouTube 将支持内嵌语法 &amp;lt;iframe&amp;gt;，放弃 Flash 时代惯用的 &amp;lt;object&amp;gt; 语法，全力支持 HTML5 video 标签。要内嵌影片的人，用 &amp;lt;iframe&amp;gt; API 内嵌影片，能够在所有平台顺利播放。&lt;/p&gt;
 &lt;p&gt;这种改进将不仅仅使YouTube收益，而是整个行业。其它的视频网站，比如 Netflix 和 Vimeo，甚至微软和苹果等公司，都在支持HTML5，并非常成功。基于开放的HTML5标准，像Chromebooks和Chremecast这样的新设备也成为了可能。同样，每个人都可以通过   &lt;a href="https://developers.google.com/youtube/iframe_api_reference"&gt;&amp;lt;iframe&amp;gt; API&lt;/a&gt;将YouTube视频嵌入到自己网站上。&lt;/p&gt;
 &lt;p&gt;参考英文：  &lt;a href="http://youtube-eng.blogspot.com/2015/01/youtube-now-defaults-to-html5_27.html" target="_blank"&gt;YouTube now defaults to HTML5&amp;lt;video&amp;gt;   &lt;br /&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>新闻资讯 html5 video 视频</category>
      <guid isPermaLink="true">https://itindex.net/detail/52655-youtube-%E7%BD%91%E7%AB%99-html5</guid>
      <pubDate>Fri, 30 Jan 2015 00:23:23 CST</pubDate>
    </item>
    <item>
      <title>最受欢迎的前端UI框架推荐</title>
      <link>https://itindex.net/detail/52724-%E5%89%8D%E7%AB%AF-ui-%E6%A1%86%E6%9E%B6</link>
      <description>&lt;p&gt;前端UI框架越来越受到新人追捧，下边小编为大家列出目前最受欢迎、最优秀的前端框架以供大家选择。&lt;/p&gt;
 &lt;h3&gt;Bootstrap&lt;/h3&gt;
 &lt;p&gt;目前开源社区最受欢迎的项目之一，可谓大名鼎鼎了，最新版本3.x兼容IE9+，用于开发响应式布局、移动设备优先的Web项目。&lt;/p&gt;
 &lt;p&gt;官网：  &lt;a href="http://getbootstrap.com/" target="_blank"&gt;http://getbootstrap.com/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="293" src="http://www.liyucang.cn/wp-content/uploads/2015/02/bootstrap.jpg" title="Bootstrap" width="680"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;Semantic UI&lt;/h3&gt;
 &lt;p&gt;UI框架的后起之秀，UI动画效果很棒，一个很有潜力的项目！兼容IE9+。&lt;/p&gt;
 &lt;p&gt;官网：  &lt;a href="http://semantic-ui.com/" target="_blank"&gt;http://semantic-ui.com/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="325" src="http://www.58img.com/Media/Default/framework/20140621135503.jpg" title="Semantic UI" width="975"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;Pure&lt;/h3&gt;
 &lt;p&gt;大名鼎鼎的Yahoo!支持开发的UI框架，其特点简洁小巧，对于喜欢简洁的朋友来说是一个不可多得的好项目！兼容：IE7+。&lt;/p&gt;
 &lt;p&gt;官网：  &lt;a href="http://purecss.io/" target="_blank"&gt;http://purecss.io/&lt;/a&gt;&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="289" src="http://www.58img.com/Media/Default/framework/20140621135504.jpg" title="Pure" width="802"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h3&gt;AmazeUI&lt;/h3&gt;
 &lt;p&gt;Amaze UI 是一个轻量级（所有 CSS 和 JS gzip 后 100 kB 左右）、   &lt;strong&gt;Mobile first&lt;/strong&gt; 的前端框架， 基于开源社区流行前端框架编写&lt;/p&gt;
 &lt;p&gt;官网：  &lt;a href="http://amazeui.org/"&gt;http://amazeui.org/&lt;/a&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>交互设计 CSS3 github HTML5 开源程序</category>
      <guid isPermaLink="true">https://itindex.net/detail/52724-%E5%89%8D%E7%AB%AF-ui-%E6%A1%86%E6%9E%B6</guid>
      <pubDate>Sun, 08 Feb 2015 21:31:21 CST</pubDate>
    </item>
    <item>
      <title>别不信！App三年内将被HTML5顶替彻底消失？</title>
      <link>https://itindex.net/detail/52723-%E4%B8%8D%E4%BF%A1-app-html5</link>
      <description>&lt;p&gt;2007年W3C(万维网联盟)立项HTML5，直至2014年10月底，这个长达八年的规范终于正式封稿。&lt;/p&gt;
 &lt;p&gt;过去这些年，HTML5颠覆了PC互联网的格局，优化了移动互联网的体验，接下来，HTML5将颠覆原生App世界。这听起来有点危言耸听，但若认真分析HTML5的发展史，你会发现，这个世界的发展趋势确实就是这样。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="" height="320" src="http://www.codeceo.com/wp-content/uploads/2015/02/78c0d79bdf0c76b89fb985859c2ad04f.jpg" width="585"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;h2&gt;HTML5对开发者的7大优势&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;跨平台：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;在多屏年代，开发者的痛苦指数非常高，人人都期盼HTML5能扮演救星。多套代码、不同技术工种、业务逻辑同步，这是折磨人的过程。有点类似个人电脑早期世界，那个时候的每家电脑都有自己的操作系统和编程语言，开发者疲于做不同版本，其实DOS的盛行也很大程度是因为开发者实在没精力给其他电脑写程序。跨平台技术在早期大多因为性能问题夭折，但中后期硬件能力增强后又会占据主流，因为跨平台确实是刚需。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;快速迭代：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;移动互联网是一个快鱼吃慢鱼的时代，谁对用户的需求满足的更快，谁的试错成本更低，谁就拥有巨大的优势。互联网产品大多免费、且有网络效应，后入者抢夺用户的难度非常大。使用原生开发，从招聘、开发、上线各个环节的效率都慢一倍以上，而且参与的人越多，沟通效率往往拖慢不止一倍。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;持续交付：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;很多人有这样的体会，一个原生应用上线Appstore，突然有一个大bug，只好连夜加班修复，然后静静等待2周或更长时间的Apple审核，这2个星期被用户的涂抹淹死，市场上一片差评，用户大量流失。等新应用被审核上线了，用户已经卸载了。但是，HTML5没有这些问题，你可以实时更新，有问题立即响应。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;大幅下降成本：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;创业者融资并不容易，如何花钱更高效非常重要。如果你使用原生开发的App和竞争对手使用HTML5开发的App没什么区别，但你的开发成本高出一倍，我相信没有投资人会喜欢给你投钱。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;开源生态系统发达：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;HTML5前端是开放的正反馈循环生态系统，大量的开源库可以使用，开发应用变得更轻松、更敏捷，当然这也体现在了快速迭代和成本下降上。不过更重要的是，这种开放的正反馈循环生态系统未来的生命力是比原生生态系统更强劲的。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;开放的数据交换：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;HTML是以page为单元开放代码的，它无需专门开发SDK，只要不混淆，就能与其他应用交互数据。开发者可以让手机搜索引擎很容易检索到自己的数据， 也更容易通过跨应用协作来满足最终用户需求。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;更容易推广、更容易爆发：&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;导流入口多：HTML5应用导流非常容易，超级App(如微信朋友圈)、搜索引擎、应用市场、浏览器，到处都是HTML5的流量入口。而原生App的流量入口只有应用市场。聪明的HTML5开发者当然会玩转各种流量入口从而取得更强的优势。&lt;/p&gt;
 &lt;p&gt;流量大：前段时间微信朋友圈风靡一时《神经猫》，这个游戏如果放到Appstore，绝对没有那么多流量，超级App带来的流量，远大于原生应用市场。假如微信允许游戏在桌面创建快捷方式、假如游戏后续升级解决持续娱乐问题，未来不可想象。&lt;/p&gt;
 &lt;p&gt;导流效率高：除了入口多、流量大，导流效率高也不可忽视，谁都知道：页游和端游打同样的广告，广告变用户的转化率，页游远远高于端游。&lt;/p&gt;
 &lt;h2&gt;HTML5对最终用户的3大优势&lt;/h2&gt;
 &lt;p&gt;  &lt;strong&gt;大幅降低使用门槛&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;为什么流媒体会替代下载视频成为主流?为什么页游会如此火爆?只因用户太“懒”。让用户更方便的满足需求，有时效果好于更多的满足需求。&lt;/p&gt;
 &lt;p&gt;用户眼睛看到一个兴趣点，点击后，就应该立即开始满足用户需求。比如流媒体可以立即看，页游可以立即玩。而目前的原生应用市场，用户需要这样操作：选一个应用、等待下载、确认权限、等待安装，然后点击打开。这样糟糕的体验迟早要被颠覆。&lt;/p&gt;
 &lt;p&gt;不管是App、游戏还是音视频，未来都将即点即用。谁先满足用户这个需求，谁就制胜。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;实时更新、差量更新的优秀体验&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;HTML5应用可以绕开应用市场的限制进行自主实时更新，用户可以快速享受新服务。&lt;/p&gt;
 &lt;p&gt;而且这种更新完全可以是差量更新，比如某个HTML页面或某个js文件有问题，只更新这个几k的小文件就可以了，这比原生应用的更新体验好太多。&lt;/p&gt;
 &lt;p&gt;  &lt;strong&gt;跨应用的使用体验&lt;/strong&gt;&lt;/p&gt;
 &lt;p&gt;目前手机应用切换是以桌面或任务管理器为中心的，但事实上这些中心很影响效率和体验。用户想出差三亚，先打开去哪App订票，然后切回桌面，再找到并打开天气App，搜索输入三亚，再切到桌面，找到并打开航旅纵横App，输入航班号值机，哦对了，航班号多少来着，再切到桌面，找到并打开去哪App看航班号，最后找到并打开租车App，输入租车地点，然后再切回桌面。&lt;/p&gt;
 &lt;p&gt;在原生应用体系下，用户只能这样。但在HTML5体系下，他不需要切回桌面，他可以在App间方便的直接跳来跳去，而不是使用一个一个孤岛App;他更不用重复录入数据，应用间可以方便的互相传递数据。&lt;/p&gt;
 &lt;p&gt;这种模式需要一点想象力，但未来迟早会来。&lt;/p&gt;
 &lt;p&gt;分析至此，我们可以明显的看出，不管是站在最终用户角度、还是站在开发者角度，HTML5必将取代原生应用当前的位置。并由此引发一系列颠覆。&lt;/p&gt;
 &lt;h2&gt;原生App的颠覆&lt;/h2&gt;
 &lt;p&gt;HTML5的“性工能”障碍得到解决，可以接近原生App的效果，所以它就可以替代原生App吗?很多人认为，即使HTML5会发展的比现在好，也将是与原生App各占一部分市场的格局，要求不高的长尾应用会使用HTML5，而主流应用仍是原生App的天下。&lt;/p&gt;
 &lt;p&gt;但这样的想法很危险，就像Apple成立前，HP的高层告诉沃兹：谁会在家里摆一台电脑呢?未来HTML5肯定会颠覆原生App。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>资讯 HTML5</category>
      <guid isPermaLink="true">https://itindex.net/detail/52723-%E4%B8%8D%E4%BF%A1-app-html5</guid>
      <pubDate>Sun, 08 Feb 2015 21:37:29 CST</pubDate>
    </item>
    <item>
      <title>HTML5 Web Speech API，让网站更有趣</title>
      <link>https://itindex.net/detail/52703-html5-web-speech</link>
      <description>&lt;p&gt;Web API 变得越来越丰富，其中一个值得注意的是  &lt;code&gt;Web Speech&lt;/code&gt; API。传统的网站只能“说”，这个API的出现，让网站能“倾听”用户。这个功能已经开放了一系列的用法，非常棒。&lt;/p&gt;

 &lt;p&gt;在这篇文章中，我们将看一下这项技术和建议的用法，以及如何用它来增强用户体验的一些好例子。&lt;/p&gt;

 &lt;p&gt;  &lt;img alt="clipboard.png" src="http://segmentfault.com/img/bVkOoy"&gt;&lt;/img&gt;&lt;/p&gt;

 &lt;blockquote&gt;
    &lt;p&gt;声明：本技术比较前沿，目前该规范是W3C的“非官方编辑器的征求意见稿”（截至2014年6月6日）。它的使用方法可能和本文中的代码片有所不同。查看代码规范和发布前的测试是很有必要的。&lt;/p&gt;
&lt;/blockquote&gt;

 &lt;h2&gt;语音合成 Speech Synthesis&lt;/h2&gt;

 &lt;p&gt;该API分为两部分。首先，让我们来看看语音的合成部分——说话。如果你的网站有一些文字内容——文章主体、表单、输入框、标签等——你可以运行一些有趣的功能，设备就会把文字读给用户听。&lt;/p&gt;

 &lt;p&gt;来看看做到这一点所需要的代码。首先创建  &lt;code&gt;SpeechSynthesisUtterance&lt;/code&gt;接口的新实例。然后指定要阅读的文本。再把这个实例添加到队列中，告诉浏览器什么时候说话。&lt;/p&gt;

 &lt;p&gt;下面的speak函数里完成了上面所述的功能 ，把想要朗读的内容作为参数。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;function speak(textToSpeak) {
   //创建一个 SpeechSynthesisUtterance的实例
   var newUtterance = new SpeechSynthesisUtterance();

   // 设置文本
   newUtterance.text = textToSpeak;

   // 添加到队列
   window.speechSynthesis.speak(newUtterance);
}
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;现在我们需要做的就是调用这个函数，并传入我们想要朗读的内容：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;speak(&amp;apos;Welcome to Smashing Magazine&amp;apos;);
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;code&gt;SpeechSynthesisUtterance&lt;/code&gt;还有开始、暂停、停止功能，还能设置语言、速度、声音。停止、启动或暂停都触发一个事件，开发者可以编写这个事件来完成很多有趣的事情。&lt;/p&gt;

 &lt;p&gt;目前，语音合成只有Chrome和Safari（包括桌面和移动设备版）支持。此外，通过API提供给用户的声音在很大程度上取决于操作系统。谷歌有自己的一套给Chrome的默认声音，可以在Mac OS X，Windows和Ubuntu上使用。Mac OS X的声音也可用，所以和OSX的Safari的声音一样。你可以通过开发者工具的控制台看有哪种声音可用。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;window.speechSynthesis.getVoices();
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;strong&gt;如果你使用OS X，可以用“Zarvox”声音&lt;/strong&gt;&lt;/p&gt;

 &lt;h2&gt;语音识别 Speech Recognition&lt;/h2&gt;

 &lt;p&gt;Web Speech API另一部分是语音识别，它能够识别用过从麦克风或网站应用获取的语音。&lt;/p&gt;

 &lt;p&gt;让我们通过一些代码运行。这一次，我们将创建  &lt;code&gt;SpeechRecognition&lt;/code&gt;的新实例。因为这部分只得到了Chrome的支持，所以要添加WebKit的前缀。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;var newRecognition = webkitSpeechRecognition();
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;  &lt;code&gt;peechRecognition&lt;/code&gt;有相当多的属性。比如状态是可连续的，浏览器在没有接收到声音的一段时间后默认把状态设为  &lt;code&gt;false&lt;/code&gt;，如果你想继续听，可以设为  &lt;code&gt;true&lt;/code&gt;。&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;newRecognition.continuous = true;
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;开启和停止语音识别，使用  &lt;code&gt;start()&lt;/code&gt; 、   &lt;code&gt;stop()&lt;/code&gt;：&lt;/p&gt;

 &lt;pre&gt;  &lt;code&gt;// 开始
newRecognition.start();

// 停止
newRecognition.stop();
&lt;/code&gt;&lt;/pre&gt;

 &lt;p&gt;还可以绑定很多事件，例如：  &lt;code&gt;soundstart&lt;/code&gt;、  &lt;code&gt;speechstart&lt;/code&gt;、  &lt;code&gt;result&lt;/code&gt; 、   &lt;code&gt;error&lt;/code&gt;。  &lt;a href="http://codepen.io/Rumyra/pen/bCphe" rel="nofollow"&gt;看看这个demo&lt;/a&gt;。&lt;/p&gt;

 &lt;h2&gt;使用场景举例&lt;/h2&gt;

 &lt;h3&gt;听写&lt;/h3&gt;

 &lt;p&gt;目前，Speech API最常见的用法是听写和读取。也就是用户通过麦克风说话，设备把语音翻译成文字（看看  &lt;a href="https://www.google.com/intl/en/chrome/demos/speech.html" rel="nofollow"&gt;Chrome开发团队做的demo&lt;/a&gt;），或者设备读取文字转化成语音。&lt;/p&gt;

 &lt;p&gt;设备能说话这是非常有用的功能。设想一下，当你早上起床的时候，镜子告诉你今天的天气，这多么神奇。&lt;/p&gt;

 &lt;p&gt;很多汽车都有语音系统，在你开车的时候给你导航。设想一下，当你在开车的时候，浏览器把你想要的内容读给你听，多么方便。&lt;/p&gt;

 &lt;h3&gt;声音控制&lt;/h3&gt;

 &lt;p&gt;听写可以很容易地变成语音控制。正如上面的例子，我们可以通过语音导航。如果把这个功能加入到网络电视的浏览器中，将会有更多有意思的实现。&lt;/p&gt;

 &lt;p&gt;我的同事做了个网球应用，在他打球的时候，它的应用会把他的分数读出来。&lt;/p&gt;

 &lt;h3&gt;翻译&lt;/h3&gt;

 &lt;p&gt;未来翻译会变得很不一样。一个人说了一段话，设备就翻译成对方的语言并读出。&lt;/p&gt;

 &lt;h2&gt;限制&lt;/h2&gt;

 &lt;p&gt;离线是需要注意的问题。目前API的实现是浏览器把数据发送到远端服务器，再把处理好的数据返回。没有网络就无法实现功能。&lt;/p&gt;

 &lt;hr&gt;&lt;/hr&gt;
 &lt;p&gt;英文原文：   &lt;a href="http://www.smashingmagazine.com/2014/12/05/enhancing-ux-with-the-web-speech-api/" rel="nofollow"&gt;Enhancing User Experience With The Web Speech API&lt;/a&gt;  &lt;br /&gt;
由SegmentFault整理翻译&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>html5</category>
      <guid isPermaLink="true">https://itindex.net/detail/52703-html5-web-speech</guid>
      <pubDate>Thu, 05 Feb 2015 15:39:02 CST</pubDate>
    </item>
    <item>
      <title>HTML5的页面资源预加载技术(Link prefetch)加速页面加载</title>
      <link>https://itindex.net/detail/49441-html5-%E9%A1%B5%E9%9D%A2-%E8%B5%84%E6%BA%90</link>
      <description>&lt;p&gt;不管是浏览器的开发者还是普通web应用的开发者，他们都在做一个共同的努力：让Web浏览有更快的速度感觉。有很多已知的技术都可以让你的网站速度变得更快：使用CSS sprites，使用图片优化工具，使用.htaccess设置页面头信息和缓存时间，JavaScript压缩，使用CDN等。我曾经介绍过本站上使用的一些速度优化技术。而在  &lt;a href="http://www.html5tricks.com/" target="_blank" title="HTML5"&gt;HTML5&lt;/a&gt;里，出现了一个新的用来优化网站速度的新功能：页面资源预加载/预读取(Link prefetch)。&lt;/p&gt;
 &lt;p&gt;页面资源预加载/预读取(Link prefetch)是什么？来自  &lt;a href="https://developer.mozilla.org/en/link_prefetching_faq" rel="nofollow"&gt;MDN&lt;/a&gt;的解释:&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;页面资源预加载(Link prefetch)是浏览器提供的一个技巧，目的是让浏览器在空闲时间下载或预读取一些文档资源，用户在将来将会访问这些资源。一个Web页面可以对浏览器设置一系列的预加载指示，当浏览器加载完当前页面后，它会在后台静悄悄的加载指定的文档，并把它们存储在缓存里。当用户访问到这些预加载的文档后，浏览器能快速的从缓存里提取给用户。&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;简单说来就是：让浏览器预先加载用户访问当前页后极有可能访问的其他资源(页面，图片，视频等)。而且方法超级的简单！&lt;/p&gt;
 &lt;h2&gt;HTML5页面资源预加载(Link prefetch)写法&lt;/h2&gt;
 &lt;pre&gt;&amp;lt;!-- 预加载整个页面 --&amp;gt;
&amp;lt;link rel=&amp;quot;prefetch&amp;quot; href=&amp;quot;http://www.webhek.com/misc/3d-album/&amp;quot; /&amp;gt;

&amp;lt;!-- 预加载一个图片 --&amp;gt;
&amp;lt;link rel=&amp;quot;prefetch&amp;quot; href=&amp;quot; http://www.webhek.com/wordpress/
wp-content/uploads/2014/04/b-334x193.jpg &amp;quot; /&amp;gt;&lt;/pre&gt;
 &lt;p&gt;HTML5页面资源预加载/预读取(Link prefetch)功能是通过  &lt;code&gt;Link&lt;/code&gt;标记实现的，将  &lt;code&gt;rel属性&lt;/code&gt;指定为“prefetch”，在  &lt;code&gt;href属性&lt;/code&gt;里指定要加载资源的地址。火狐浏览器里还提供了一种额外的属性支持：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;link rel=&amp;quot;prefetch alternate stylesheet&amp;quot; 
title=&amp;quot;Designed for Mozilla&amp;quot; href=&amp;quot;mozspecific.css&amp;quot; /&amp;gt;
&amp;lt;link rel=&amp;quot;next&amp;quot; href=&amp;quot;2.html&amp;quot; /&amp;gt;&lt;/pre&gt;
 &lt;p&gt;HTTPS协议资源下也可以使用prefetch。&lt;/p&gt;
 &lt;h2&gt;什么情况下应该预加载页面资源&lt;/h2&gt;
 &lt;p&gt;在你的页面里加载什么样的资源，什么时候加载，这完全取决于你。下面是一些建议：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;当页面有幻灯片类似的服务时，预加载/预读取接下来的1-3页和之前的1-3页。&lt;/li&gt;
  &lt;li&gt;预加载那些整个网站通用的图片。&lt;/li&gt;
  &lt;li&gt;预加载网站上搜索结果的下一页。&lt;/li&gt;
&lt;/ul&gt;
 &lt;h2&gt;禁止页面资源预加载(Link prefetch)&lt;/h2&gt;
 &lt;p&gt;火狐浏览器里有一个选项可以禁止任何的页面资源预加载(Link prefetch)功能，你可以这样设置：&lt;/p&gt;
 &lt;pre&gt;user_pref(&amp;quot;network.prefetch-next&amp;quot;, false);&lt;/pre&gt;
 &lt;h2&gt;页面资源预加载(Link prefetch)注意事项&lt;/h2&gt;
 &lt;p&gt;下面是一些关于页面资源预加载(Link prefetch)的注意事项：&lt;/p&gt;
 &lt;ul&gt;
  &lt;li&gt;预加载(Link prefetch)不能跨域工作，包括跨域拉取cookies。&lt;/li&gt;
  &lt;li&gt;预加载(Link prefetch)会污染你的网站访问量统计，因为有些预加载到浏览器的页面用户可能并未真正访问。&lt;/li&gt;
  &lt;li&gt;火狐浏览器从2003年开始就已经提供了对这项预加载(Link prefetch)技术的支持。&lt;/li&gt;
&lt;/ul&gt;
 &lt;p&gt;利用浏览器空闲时间加载一些额外的资源文件，看起来是既刺激又危险，你想试试这些技术吗？&lt;/p&gt;
 &lt;p&gt;原文来自：  &lt;a href="http://www.webhek.com/link-prefetch/" target="_blank"&gt;webhek&lt;/a&gt;&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>HTML5教程 Link prefetch 预加载</category>
      <guid isPermaLink="true">https://itindex.net/detail/49441-html5-%E9%A1%B5%E9%9D%A2-%E8%B5%84%E6%BA%90</guid>
      <pubDate>Sun, 04 May 2014 09:25:58 CST</pubDate>
    </item>
    <item>
      <title>使用HTML5技术控制电脑或手机上的摄像头</title>
      <link>https://itindex.net/detail/49404-html5-%E6%8A%80%E6%9C%AF-%E6%8E%A7%E5%88%B6</link>
      <description>&lt;p&gt;移动设备和桌面电脑上的客户端API起初并不是同步的。最初总是移动设备上先拥有某些功能和相应的API，但慢慢的，这些API会出现在桌面电脑上。其中一个应用接口技术就是  &lt;code&gt;getUserMedia&lt;/code&gt; API，它能让应用开发者访问用户的摄像头或内置相机。下面就让我展示一下如何通过浏览器来访问你的摄像头，并提取截屏图形。&lt;/p&gt;
 &lt;div&gt;  &lt;a href="http://www.webhek.com/demo/browser-camera/" target="_blank"&gt;观看演示&lt;/a&gt;&lt;/div&gt;
 &lt;h2&gt;HTML代码&lt;/h2&gt;
 &lt;p&gt;下面的代码里我写了一部分注释，请阅读：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;!--
	理想情况下我们应该先判断你的设备上是否
	有摄像头或相机，但简单起见，我们在这里直接
	写出了HTML标记，而不是用JavaScript先判断
	然后动态生成这些标记
--&amp;gt;
&amp;lt;video id=&amp;quot;video&amp;quot; width=&amp;quot;640&amp;quot; height=&amp;quot;480&amp;quot; autoplay&amp;gt;&amp;lt;/video&amp;gt;
&amp;lt;button id=&amp;quot;snap&amp;quot;&amp;gt;Snap Photo&amp;lt;/button&amp;gt;
&amp;lt;canvas id=&amp;quot;canvas&amp;quot; width=&amp;quot;640&amp;quot; height=&amp;quot;480&amp;quot;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/pre&gt;
 &lt;p&gt;在写出上面这些标记前应该判断用户的客户端是否有摄像头支持，但这里为了不那么麻烦，这里直接写出了这些HTML标记，需要注意的是我们这里使用的长宽是640×480。&lt;/p&gt;
 &lt;h2&gt;JavaScript代码&lt;/h2&gt;
 &lt;p&gt;因为我们是手工写出的HTML，所以下面的js代码会比你想象的要简单了很多。&lt;/p&gt;
 &lt;pre&gt;// Put event listeners into place
window.addEventListener(&amp;quot;DOMContentLoaded&amp;quot;, function() {
	// Grab elements, create settings, etc.
	var canvas = document.getElementById(&amp;quot;canvas&amp;quot;),
		context = canvas.getContext(&amp;quot;2d&amp;quot;),
		video = document.getElementById(&amp;quot;video&amp;quot;),
		videoObj = { &amp;quot;video&amp;quot;: true },
		errBack = function(error) {
			console.log(&amp;quot;Video capture error: &amp;quot;, error.code); 
		};

	// Put video listeners into place
	if(navigator.getUserMedia) { // Standard
		navigator.getUserMedia(videoObj, function(stream) {
			video.src = stream;
			video.play();
		}, errBack);
	} else if(navigator.webkitGetUserMedia) { // WebKit-prefixed
		navigator.webkitGetUserMedia(videoObj, function(stream){
			video.src = window.webkitURL.createObjectURL(stream);
			video.play();
		}, errBack);
	}
	else if(navigator.mozGetUserMedia) { // Firefox-prefixed
		navigator.mozGetUserMedia(videoObj, function(stream){
			video.src = window.URL.createObjectURL(stream);
			video.play();
		}, errBack);
	}
}, false);&lt;/pre&gt;
 &lt;p&gt;一旦判断出用户浏览器支持  &lt;code&gt;getUserMedia&lt;/code&gt; ，下面就非常简单了，只需要将那个  &lt;code&gt;video&lt;/code&gt;元素的  &lt;code&gt;src&lt;/code&gt;设置为用户的摄像头视频直播连接。这就是用浏览器访问摄像头需要做的所有的事情！&lt;/p&gt;
 &lt;p&gt;拍照的功能只能说是稍微复杂一点点。我们在按钮上加入一个监听器，将视频画面画到画布上。&lt;/p&gt;
 &lt;pre&gt;// 触发拍照动作
document.getElementById(&amp;quot;snap&amp;quot;)
       .addEventListener(&amp;quot;click&amp;quot;, function() {
	context.drawImage(video, 0, 0, 640, 480);
});&lt;/pre&gt;
 &lt;p&gt;当然，你还可以在图片上加一些滤镜效果….我还是把这些技术放到以后的文章里再说吧。但至少你可以将这个  &lt;a href="http://www.webhek.com/convert-canvas-image/"&gt;画布图像转换成一张图片&lt;/a&gt;。&lt;/p&gt;
 &lt;div&gt;  &lt;a href="http://www.webhek.com/demo/browser-camera/" target="_blank"&gt;观看演示&lt;/a&gt;&lt;/div&gt;
 &lt;p&gt;以前我们需要使用第三方的插件才能从浏览器里访问用户的摄像头，这不免有些复杂。现在只需要HTML5的画布技术和javaScript，我们就能简单快速的操作用户的摄像头。不仅仅还是访问摄像头，而且是因为HTML5的画布技术及其强大，我们可以给图片上加入各种迷人的滤镜效果。现在，在浏览器里用自己的摄像头给自己拍张照片吧！&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>技术技巧 html5 摄像头</category>
      <guid isPermaLink="true">https://itindex.net/detail/49404-html5-%E6%8A%80%E6%9C%AF-%E6%8E%A7%E5%88%B6</guid>
      <pubDate>Fri, 02 May 2014 00:37:39 CST</pubDate>
    </item>
    <item>
      <title>Javascript网页截屏的方法</title>
      <link>https://itindex.net/detail/50195-javascript-%E7%BD%91%E9%A1%B5-%E6%96%B9%E6%B3%95</link>
      <description>&lt;p&gt;最近我在研究开发一个火狐插件，具体的功能是将网页内容截屏并分享到微博上。目前基本功能已经实现，大家可以在   &lt;a href="http://weibo.com/computerworld" rel="nofollow" target="_blank"&gt;@程序师视野&lt;/a&gt; 里看到用这个截图插件分享的微博的效果。&lt;/p&gt;
 &lt;p&gt;之前我曾写过  &lt;a href="http://www.webhek.com/convert-canvas-image/"&gt;如何将canvas图形转换成图片&lt;/a&gt;和  &lt;a href="http://www.webhek.com/save-canvas-to-image/"&gt;下载canvas图像&lt;/a&gt;的方法，这些都是在为这个插件做技术准备。&lt;/p&gt;
 &lt;p&gt;技术路线很清晰，将网页的某个区域的内容生成图像，保持到canvas里，然后将canvas内容转换成图片，保存到本地，最后上传到微博。&lt;/p&gt;
 &lt;p&gt;我在网上搜寻到  &lt;a href="https://github.com/niklasvh/html2canvas" rel="nofollow" target="_blank"&gt;html2canvas&lt;/a&gt;这个能将指定网页元素内容生成canvas图像的javascript工具。这个js工具的用法很简单，你只需要将它的js文件引入到页面里，然后调用  &lt;code&gt;html2canvas()&lt;/code&gt;函数：&lt;/p&gt;
 &lt;pre&gt;html2canvas(document.body, {
    onrendered: function(canvas) {
        /* canvas is the actual canvas element,
           to append it to the page call for example
           document.body.appendChild( canvas );
        */
    }
});&lt;/pre&gt;
 &lt;p&gt;这个  &lt;code&gt;html2canvas()&lt;/code&gt;函数有个参数，上面的例子里传入的参数是  &lt;code&gt;document.body&lt;/code&gt;，这会截取整个页面的图像。如果你想只截取一个区域，比如对某个  &lt;code&gt;div&lt;/code&gt;或某个  &lt;code&gt;   &lt;a href="http://www.webhek.com/table-bad/"&gt;table&lt;/a&gt;&lt;/code&gt;截图，你就将这个  &lt;code&gt;div&lt;/code&gt;或某个  &lt;code&gt;   &lt;a href="http://www.webhek.com/table-bad/"&gt;table&lt;/a&gt;&lt;/code&gt;当做参数传进去。&lt;/p&gt;
 &lt;p&gt;我最终并没有选用html2canvas这个js工具，因为在我的实验过程中发现它有几个问题。&lt;/p&gt;
 &lt;p&gt;首先，跨域问题。我举个例子说明这个问题，比如我的网页网址是http://www.webhek.com/about/，而我在这个页面上有个张图片，这个图片并不是来自www.webhek.com域，而是来自CDN图片服务器www.webhek-cdn.com/images/about.jpg，那么，这张图片就和这个网页不是同域，那么html2canvas就无法对这种图片进行截图，如果你的网站的所有图片都放在单独的图片服务器上，那么用html2canvas对整个网页进行截图是就会发现所有图片的地方都是空白。&lt;/p&gt;
 &lt;p&gt;这个问题也有补救的方法，就是用代理：&lt;/p&gt;
 &lt;pre&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;
        &amp;lt;title&amp;gt;html2canvas php proxy&amp;lt;/title&amp;gt;
        &amp;lt;script src=&amp;quot;html2canvas.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
        &amp;lt;script&amp;gt;
        //&amp;lt;![CDATA[
        (function() {
            window.onload = function(){
                html2canvas(document.body, {
                    &amp;quot;logging&amp;quot;: true, //Enable log (use Web Console for get Errors and Warnings)
                    &amp;quot;proxy&amp;quot;:&amp;quot;html2canvasproxy.php&amp;quot;,
                    &amp;quot;onrendered&amp;quot;: function(canvas) {
                        var img = new Image();
                        img.onload = function() {
                            img.onload = null;
                            document.body.appendChild(img);
                        };
                        img.onerror = function() {
                            img.onerror = null;
                            if(window.console.log) {
                                window.console.log(&amp;quot;Not loaded image from canvas.toDataURL&amp;quot;);
                            } else {
                                alert(&amp;quot;Not loaded image from canvas.toDataURL&amp;quot;);
                            }
                        };
                        img.src = canvas.toDataURL(&amp;quot;image/png&amp;quot;);
                    }
                });
            };
        })();
        //]]&amp;gt;
        &amp;lt;/script&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;p&amp;gt;
            &amp;lt;img alt=&amp;quot;google maps static&amp;quot; src=&amp;quot;http://maps.googleapis.com/maps/api/staticmap?center=40.714728,-73.998672&amp;amp;zoom=12&amp;amp;size=800x600&amp;amp;maptype=roadmap&amp;amp;sensor=false&amp;quot;&amp;gt;
        &amp;lt;/p&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;
 &lt;p&gt;这个方法只能用在你自己的服务器里，如果是对别人的网页截图，还是不行。&lt;/p&gt;
 &lt;p&gt;试验的过程中还发现用html2canvas截屏出来的图像有时会出现文字重叠的现象。我估计是因为html2canvas在解析页面内容、处理css时不是很完美的原因。&lt;/p&gt;
 &lt;p&gt;最后，我在火狐浏览器的官方网站上找到了  &lt;code&gt;   &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D#drawWindow%28%29" rel="nofollow" target="_blank"&gt;drawWindow()&lt;/a&gt;&lt;/code&gt;这个方法，这个方法和上面提到html2canvas不同之处在于，它不分析页面元素，它只针对区域，也就是说，它接受的参数是四个数字标志的区域，不论这个区域中什么地方，有没有页面内容。&lt;/p&gt;
 &lt;pre&gt;void drawWindow(
  in nsIDOMWindow window,
  in float x, 
  in float y,
  in float w,
  in float h,
  in DOMString bgColor,
  in unsigned long flags [optional]
);&lt;/pre&gt;
 &lt;p&gt;这个原生的JavaScript方法看起来非常的完美，正是我需要的，但这个方法不能使用在普通网页中，因为火狐官方发现这个方法会引起有  &lt;a href="http://mxr.mozilla.org/mozilla/source/content/canvas/src/nsCanvasRenderingContext2D.cpp#2352" rel="nofollow" target="_blank"&gt;安全漏洞&lt;/a&gt;，在这个bug修复之前，只有具有“Chrome privileges”的代码才能使用这个  &lt;code&gt;drawWindow()&lt;/code&gt;函数。&lt;/p&gt;
 &lt;p&gt;虽然有很大的限制，但周折一下还是可以用的，在我开发的火狐addon插件中，main.js就是具有“Chrome privileges”的代码。我在网上发现了一段火狐插件SDK里自带  &lt;a href="http://stackoverflow.com/questions/17913911/how-do-i-use-the-canvas-drawwindow-function-in-an-addon-created-using-the-addon?answertab=votes#tab-top" rel="nofollow" target="_blank"&gt;代码样例&lt;/a&gt;：&lt;/p&gt;
 &lt;pre&gt;var window = require(&amp;apos;window/utils&amp;apos;).getMostRecentBrowserWindow();
var tab = require(&amp;apos;tabs/utils&amp;apos;).getActiveTab(window);
var thumbnail = window.document.createElementNS(&amp;quot;http://www.w3.org/1999/xhtml&amp;quot;, &amp;quot;canvas&amp;quot;);
thumbnail.mozOpaque = true;
window = tab.linkedBrowser.contentWindow;
thumbnail.width = Math.ceil(window.screen.availWidth / 5.75);
var aspectRatio = 0.5625; // 16:9
thumbnail.height = Math.round(thumbnail.width * aspectRatio);
var ctx = thumbnail.getContext(&amp;quot;2d&amp;quot;);
var snippetWidth = window.innerWidth * .6;
var scale = thumbnail.width / snippetWidth;
ctx.scale(scale, scale);
ctx.drawWindow(window, window.scrollX, window.scrollY, snippetWidth, snippetWidth * aspectRatio, &amp;quot;rgb(255,255,255)&amp;quot;);
// thumbnail now represents a thumbnail of the tab&lt;/pre&gt;
 &lt;p&gt;这段代码写的非常清楚，只需要依据它做稍微的修改就能适应自己的需求。&lt;/p&gt;
 &lt;p&gt;我是第一次接触火狐插件开发，是边学习，边研究，边开发。所以开发速度很慢，这个小小的插件用了整整一周才基本上达到能用的程度。你可以在   &lt;a href="http://weibo.com/computerworld" rel="nofollow" target="_blank"&gt;@程序师视野&lt;/a&gt; 微博里看到用它上传的图片效果还是不错的。&lt;/p&gt;
 &lt;p&gt;先能用，然后使用的过程中慢慢做改进，这是我的软件开发理念。&lt;/p&gt;
 &lt;p&gt;希望和对火狐插件有兴趣的朋友一起探讨、一起学习。&lt;/p&gt;
 &lt;p&gt; &lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>技术技巧 addon canvas html5 javascript</category>
      <guid isPermaLink="true">https://itindex.net/detail/50195-javascript-%E7%BD%91%E9%A1%B5-%E6%96%B9%E6%B3%95</guid>
      <pubDate>Fri, 27 Jun 2014 10:42:01 CST</pubDate>
    </item>
    <item>
      <title>将画布(canvas)图像保存成本地图片的方法</title>
      <link>https://itindex.net/detail/50144-canvas-%E5%9B%BE%E5%83%8F-%E6%88%90%E6%9C%AC</link>
      <description>&lt;p&gt;之前我曾介绍过如何将HTML5  &lt;a href="http://www.webhek.com/convert-canvas-image/"&gt;画布(canvas)内容转变成图片&lt;/a&gt;形式，方法十分简单。但后来我发现只将canvas内容转变成图片输出还不够，如何能将转变后的图片保存到本地呢？&lt;/p&gt;
 &lt;p&gt;其实，这个方法也是非常简单的，几乎不用额外的编程知识。但我们可以更完美些，下面我将使用  &lt;a href="http://www.webhek.com/canvas2image.js"&gt;canvas2image.js&lt;/a&gt;,   &lt;a href="http://www.webhek.com/base64.js"&gt;base64.js&lt;/a&gt;这两个脚本实现更强大的canvas-&amp;gt;图片-&amp;gt;本地的过程。&lt;/p&gt;
 &lt;p&gt;在下面的方框内你可以用鼠标绘制任意的图案，试一下吧，然后点击“保存…”按钮，浏览器将会提示你保存下载图片。或者点击”转换成…”，然后右键点击画布，可以看到浏览器右键菜单里有“保存图片..”一项。&lt;/p&gt;
 &lt;p&gt;你的浏览器不支持画布技术，请使用谷歌浏览器/火狐浏览器或最新的IE9/10/11。&lt;/p&gt;
 &lt;div&gt;
  &lt;p&gt;现在你可以右键点击画布，下载这张图片了。&lt;/p&gt;
  &lt;p&gt;   &lt;input type="button" value="&amp;#37325;&amp;#32622;"&gt;&lt;/input&gt;&lt;/p&gt;
&lt;/div&gt;
 &lt;p&gt;  &lt;input type="button" value="&amp;#20445;&amp;#23384;PNG&amp;#22270;&amp;#29255;"&gt;&lt;/input&gt;   &lt;input type="button" value="&amp;#36716;&amp;#25442;&amp;#25104;PNG&amp;#22270;&amp;#29255;"&gt;&lt;/input&gt;   &lt;input type="button" value="&amp;#20445;&amp;#23384;BMP&amp;#22270;&amp;#29255;"&gt;&lt;/input&gt;   &lt;input type="button" value="&amp;#36716;&amp;#25442;&amp;#25104;BMP&amp;#22270;&amp;#29255;"&gt;&lt;/input&gt;   &lt;input type="button" value="&amp;#20445;&amp;#23384;JPEG&amp;#22270;&amp;#29255;"&gt;&lt;/input&gt;   &lt;input type="button" value="&amp;#36716;&amp;#25442;&amp;#25104;JPEG&amp;#22270;&amp;#29255;"&gt;&lt;/input&gt;  &lt;br /&gt;
 &lt;/p&gt;
 &lt;p&gt;使用HTML5画布技术，你可以在浏览器客户端用JavaScript绘制出各种美丽酷炫的图案，这些图案是不能直接保存的，本身也不是图片形式。  &lt;br /&gt;
幸运的是，画布(canvas)对象有一个非常有用的方法:  &lt;code&gt;toDataURL()&lt;/code&gt;。这个方法能把画布里的图案转变成base64编码格式的png，然后返回  &lt;a href="http://www.webhek.com/data-url/"&gt; Data URL&lt;/a&gt;数据。&lt;/p&gt;
 &lt;pre&gt;var strDataURI = oCanvas.toDataURL();
// returns &amp;quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACt...&amp;quot;
&lt;/pre&gt;
 &lt;p&gt;而且，如果你给  &lt;code&gt;toDataURL()&lt;/code&gt;传入mine类型的参数，你还可以将画布转变成其它格式的图片。&lt;/p&gt;
 &lt;pre&gt;var strDataURI = oCanvas.toDataURL(&amp;quot;image/jpeg&amp;quot;);
// returns &amp;quot;data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAA...&amp;quot;
&lt;/pre&gt;
 &lt;p&gt;现在，有了  &lt;a href="http://www.webhek.com/data-url/"&gt; Data URL&lt;/a&gt;数据后，我们可将这些数据直接填充到  &lt;code&gt;&amp;lt;img&amp;gt; &lt;/code&gt;元素里，或者我们可以直接从浏览器里下载它们。&lt;/p&gt;
 &lt;p&gt;上面我提到的两个js包也就是封装了一些方便的方法：&lt;/p&gt;
 &lt;pre&gt;/*
 * Canvas2Image.saveAsXXXX = function(oCanvasElement, bReturnImgElement, iWidth, iHeight) { ... }
 */

var oCanvas = document.getElementById(&amp;quot;thecanvas&amp;quot;);

Canvas2Image.saveAsPNG(oCanvas);  // 这将会提示用户保存PNG图片

Canvas2Image.saveAsJPEG(oCanvas); // 这将会提示用户保存JPG图片

Canvas2Image.saveAsBMP(oCanvas);  // 这将会提示用户保存BMP图片


// 返回一个包含PNG图片的&amp;lt;img&amp;gt;元素
var oImgPNG = Canvas2Image.saveAsPNG(oCanvas, true);   

// 返回一个包含JPG图片的&amp;lt;img&amp;gt;元素
var oImgJPEG = Canvas2Image.saveAsJPEG(oCanvas, true); 
                                                       
// 返回一个包含BMP图片的&amp;lt;img&amp;gt;元素
var oImgBMP = Canvas2Image.saveAsBMP(oCanvas, true); 


// 这些函数都可以接受高度和宽度的参数
// 可以用来调整图片大小

// 把画布保存成100x100的png格式
Canvas2Image.saveAsPNG(oCanvas, false, 100, 100);

&lt;/pre&gt;
 &lt;p&gt;你也许注意到了saveAsBMP这个函数，实际上没有浏览器直接支持转化成BMP格式，但我们可以借用getImageData()方法实现对它的支持，这个方法提供给我们从画布里直接读取原始像素的功能。&lt;/p&gt;
 &lt;p&gt;有了这些数据，我们可以构造出BMP格式图片(这种格式非常的简单)。&lt;/p&gt;
 &lt;p&gt;对于大个的图片，转化成BMP格式会需要几秒钟的时间，但小图片就非常的快了，不会有延迟的感觉。&lt;/p&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>技术技巧 canvas html5 画布 画布图片转化</category>
      <guid isPermaLink="true">https://itindex.net/detail/50144-canvas-%E5%9B%BE%E5%83%8F-%E6%88%90%E6%9C%AC</guid>
      <pubDate>Tue, 24 Jun 2014 11:30:11 CST</pubDate>
    </item>
    <item>
      <title>HTML5中新型input类型</title>
      <link>https://itindex.net/detail/50014-html5-%E4%B8%AD%E6%96%B0-input</link>
      <description>&lt;p&gt;你可能已经听说过，HTML5里引入了几种新的input类型。在HTML5之前，大家熟知的input类型包括：text(输入框)，hidden(隐藏域)，submit(提交按钮)等。而HTML5到来之后，新增的input类型包括：number(数字)，date(日期)，color(颜色)，range(范围)等等。网上之所以还没有大量的出现对这些新型的input类型的使用，是因为还有很多人在使用古老的IE6/IE8，只有当使用这些古老浏览器的人所占的比例可以忽略不计时，那就是HTML5主导天下之日，那天也是我们Web开发人员的新纪元的开始。&lt;/p&gt;
 &lt;p&gt;下面是这几种新型input类型的实例演示，可能在不同的浏览器上它们的样式会稍微有些变化，但基本的功能都是一样的。&lt;/p&gt;
 &lt;h2&gt;html5中的新型input类型&lt;/h2&gt;
 &lt;h3&gt;数字型 type=”number”&lt;/h3&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;number&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;效果：  &lt;input type="number"&gt;&lt;/input&gt;&lt;/p&gt;
 &lt;h3&gt;日期型 type=”date”&lt;/h3&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;date&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;效果：  &lt;input type="date"&gt;&lt;/input&gt;&lt;/p&gt;
 &lt;h3&gt;颜色选择器 type=”color”&lt;/h3&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;color&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;效果：  &lt;input type="color"&gt;&lt;/input&gt;&lt;/p&gt;
 &lt;h3&gt;范围 type=”range”&lt;/h3&gt;
 &lt;pre&gt;&amp;lt;input type=&amp;quot;range&amp;quot;&amp;gt;&lt;/pre&gt;
 &lt;p&gt;效果：  &lt;input type="range"&gt;&lt;/input&gt;&lt;/p&gt;
 &lt;p&gt;需要注意的是，如果你使用的是谷歌浏览器或Opera浏览器，当你点击日期类型的输入框时，会弹出日历，让你选择日期，但如果你使用的是火狐浏览器，很遗憾，火狐浏览器还没有实现弹出日历的功能，因为HTML5规范里没有规定实现日历的方法，所以各浏览器自己决定如何实现，相信不久之后火狐浏览器/IE浏览器也会有自己的弹出式日历框。&lt;/p&gt;
 &lt;p&gt;谷歌浏览器中date类型效果图：&lt;/p&gt;
 &lt;div&gt;  &lt;img alt="&amp;#35895;&amp;#27468;&amp;#27983;&amp;#35272;&amp;#22120;&amp;#20013;date&amp;#31867;&amp;#22411;&amp;#25928;&amp;#26524;&amp;#22270;" height="351" src="http://www.webhek.com/wordpress/wp-content/uploads/2014/06/date-type.jpg?17c416" width="399"&gt;&lt;/img&gt;  &lt;p&gt;谷歌浏览器中date类型效果图&lt;/p&gt;&lt;/div&gt;
&lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>技术技巧 html5 input type input类型</category>
      <guid isPermaLink="true">https://itindex.net/detail/50014-html5-%E4%B8%AD%E6%96%B0-input</guid>
      <pubDate>Fri, 13 Jun 2014 10:36:13 CST</pubDate>
    </item>
    <item>
      <title>100个惊人的CSS、JS代码技术</title>
      <link>https://itindex.net/detail/47699-css-js-%E4%BB%A3%E7%A0%81</link>
      <description>&lt;p&gt;  &lt;img alt="css top-2013" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090348o8m.png" width="500"&gt;&lt;/img&gt;&lt;/p&gt;
 &lt;p&gt;最近在Codepen看到Top Pens of 2013这个专题，专题内容为2013年上最优秀的前100个CSS、HTML5和Javascript Pens，在惊叹技术人员的创造力同时我们还能学习这些技术，对交互设计师而言还能获取灵感哦！&lt;/p&gt;
 &lt;blockquote&gt;  &lt;p&gt;Top Pens of 2013专题地址：   &lt;a href="http://codepen.io/2013/popular" rel="nofollow" target="_blank"&gt;http://codepen.io/2013/popular&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;
 &lt;p&gt;这里我们选出排名前10名的Pens，无论是前端人员还是设计师，我觉得还是值得一看的。PS:在浏览这些技术记得使用兼容CSS3/  &lt;a href="http://www.shejidaren.com/tag/html5"&gt;HTML5&lt;/a&gt;的浏览器哦，否则有些效果你看不出来。&lt;/p&gt;
 &lt;h3&gt;TOP 10: CSS 绝对居中（水平垂直居中）&lt;/h3&gt;
 &lt;p&gt;一个CSS居中的新写法，这个我觉得比较实用，因为兼容IE8呢，IE6就不说了，一边去吧。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-10" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090349yAo.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/shshaw/pen/gEiDt" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;TOP 9: 跟随移动鼠标HOVER特效&lt;/h3&gt;
 &lt;p&gt;这个中文有点难解释，大家自己看案例才知道是什么效果…挺新鲜的效果。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-09" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090349jxi.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/noeldelgado/pen/pGwFx" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;TOP 8: 拟实化倒计时实例&lt;/h3&gt;
 &lt;p&gt;这个倒计时设计图出来的时候，第一眼就很喜欢了，现在代码版了，些DEMO由CSS+JS写的。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-08" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090349bHj.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/ademilter/pen/czIGo" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;TOP 7: CSS 3D效果&lt;/h3&gt;
 &lt;p&gt;这个在实际项目中没什么有，但可以用来学习研究，看看能否在其它项目上使用。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-07" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090349n0M.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/peterwestendorp/pen/JEomi" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;TOP 6: CSS+jQuery实现WIN8风格的效果切换&lt;/h3&gt;
 &lt;p&gt;效果确实真的不错，动画也流畅，如果用在个人博客还是挺个性化的。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-06" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090349PdD.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/SaraSoueidan/pen/sBELl" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;TOP 5: 创意CSS菜单&lt;/h3&gt;
 &lt;p&gt;这个CSS写的菜单真的很有创新，点击后会以动画形式改变成形状的图标，NICE!&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-05" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090349g9U.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/bennettfeely/pen/twbyA" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;TOP 4: 拟实化CSS按钮&lt;/h3&gt;
 &lt;p&gt;使用  &lt;a href="http://www.shejidaren.com/tag/css3"&gt;CSS3&lt;/a&gt;编写，效果不错。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-04" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090349PLx.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/soulwire/pen/bKens" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;TOP 3: 创新CSS按钮&lt;/h3&gt;
 &lt;p&gt;鼠标移到按钮上的打开面板效果很不错，带3D感，还有阴影啊，做得真细节。&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-03" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090349rNI.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/bennettfeely/pen/ErFGv" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;TOP 2: 触摸设备菜单概念设计&lt;/h3&gt;
 &lt;p&gt;设计可爱，动画效果也很棒，赞！&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-02" src="http://images.shejidaren.com/wp-content/uploads/2014/01/0903491y4.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/sol0mka/pen/Jsyxq" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;h3&gt;TOP 1: Tearable Cloth&lt;/h3&gt;
 &lt;p&gt;十分强大的js技术特效，PS: 用右键可以把网切开哦！&lt;/p&gt;
 &lt;p&gt;  &lt;img alt="css top-01" src="http://images.shejidaren.com/wp-content/uploads/2014/01/090349Frc.png" width="500"&gt;&lt;/img&gt;  &lt;br /&gt;
  &lt;a href="http://codepen.io/suffick/pen/KrAwx" rel="nofollow" target="_blank"&gt;在看演示&lt;/a&gt;&lt;/p&gt;
 &lt;hr&gt;&lt;/hr&gt;Copyright ©2010-2013 ¦  &lt;a href="http://feed.feedsky.com/sjdr" target="_blank" title="RSS&amp;#35746;&amp;#38405;"&gt;RSS订阅&lt;/a&gt; ¦  &lt;a href="http://weibo.com/shejidaren888" target="_blank" title="&amp;#26032;&amp;#28010;&amp;#24494;&amp;#21338;"&gt;新浪微博&lt;/a&gt; ¦ &lt;a href="http://www.shejidaren.com/100-powerful-css-and-js-demo.html" target="_blank" title="100&amp;#20010;&amp;#24778;&amp;#20154;&amp;#30340;CSS&amp;#12289;JS&amp;#20195;&amp;#30721;&amp;#25216;&amp;#26415;"&gt;本文链接&lt;/a&gt; ¦  &lt;a href="http://www.shejidaren.com/100-powerful-css-and-js-demo.html#respond" target="_blank" title="100&amp;#20010;&amp;#24778;&amp;#20154;&amp;#30340;CSS&amp;#12289;JS&amp;#20195;&amp;#30721;&amp;#25216;&amp;#26415;&amp;#30340;&amp;#35780;&amp;#35770;"&gt;添加评论&lt;/a&gt; &lt;div&gt; &lt;a href="https://itindex.net/"  title="IT 资讯"&gt;&lt;img src="https://itindex.net/images/iconWarning.gif" title="IT 资讯" border="0"/&gt; &lt;/a&gt;</description>
      <category>HTML &amp; CSS CSS3 HTML5</category>
      <guid isPermaLink="true">https://itindex.net/detail/47699-css-js-%E4%BB%A3%E7%A0%81</guid>
      <pubDate>Mon, 20 Jan 2014 17:09:45 CST</pubDate>
    </item>
  </channel>
</rss>

