[译]用非响应式设计构建跨端Web App

写在前面的话:对于移动Web App来说,响应式设计相当的有价值,现在大家也正在逐渐的了解它。但是我认为它也有自己适用的范围,需要根据具体的场景来选择使用。正好最近业界对此也有一些声音和反思传递,例如我之前的一篇博文《用HTML5实现iPad应用无限平滑滚动》里就有提及。现在我翻译一篇相关文章,大家可以对此有更多的了解和判断。-- 宇捷

媒介查询很伟大,但是...

        对于Web开发人员来说,如果要通过对样式表进行微调来为不同尺寸设备的用户提供更好的体验,媒介查询(Media Queries)非常棒。 媒介查询实质上可以根据屏幕的尺寸来自定义网站的CSS。在你深入这篇文章之前,可以更多的了解响应式网页设计(还记得《用3个步骤实现响应式网页设计》这篇文章吗?) ,并且看看使用媒介查询的一些好例子: mediaqueri.es 。

        像布拉德·弗罗斯特在以前文章中指出的一样,调整界面只是构建移动Web App时需要考虑的众多事情之一。 如果你在构建移动Web App时只通过媒介查询自定义了布局,那么我们会有以下的问题:

  • 所有的设备都采用同样的JavaScript、CSS以及内容(图片、视频等),导致产生比预期更长的加载时间。
  • 所有的设备都有相同的初始DOM结构,可能迫使开发人员编写过于复杂的CSS样式。
  • 对于为每个设备指定自定义的交互来说缺乏弹性。

除媒介查询外,Web APP还需要更多

        不要误会我的意思。我并不是讨厌通过媒介查询进行响应式设计,并绝对认为它占有一席之地。此外,上述的一些问题可以通过例如响应图像 ,动态脚本加载等来解决。但是就某一点而言,你也许会发现自己做了太多的增量调整,而可能提供不同的版本效果会更佳。

        当构建的界面在复杂性方面有所增加,同时被单页的Web App所吸引,你会想要为每个设备类型自定义用户界面做更多事情。本文将教你如何用最少的努力实现这样的自定义。通用的方法包括将访问的设备划分到正确的分类,并且为该设备提供合适的版本,同时最大限度地提高代码在版本之间的重用。

针对哪些设备类型?

        现在有成千上万的互联网设备,几乎每一个都有浏览器。复杂之处在于它们的差异性:苹果笔记本,Windows工作站,有触摸输入、滚轮、键盘和语音输入的iPhone手机,iPad和Android手机,带压力传感器的设备,智能手表,烤面包机以及冰箱等等。它们无处不在,而且有些非常罕见。


各种各样的设备(来源

        为了创造良好的用户体验,你需要知道谁是你的用户以及他们使用的是什么设备。如果你为桌面用户创建了一个使用鼠标和键盘的界面,并将它展示给智能手机用户,这将是一个极大的失败,因为它设计在另一个屏幕大小和输入方式之上。

        这里有两种极端的方法:

1.   创建一个为所有设备工作的版本。用户体验将因此受到影响,因为不同的设备有不同的设计考虑。

2.   为每一个要支持的设备各自创建一个版本。这个工作将永远进行下去,因为你将为你的应用构建太多版本。此外,当新的智能手机诞生(大约每周都有)时,你将被​​迫再次创建一个版本。

        这里有一个基本的权衡:有更多的设备类别时,你可以提供更好的用户体验,但是需要做更多设计,实现和维护的工作。

        为每种设备创建单独的版本对于性能原因来说也许是一个好办法,或者你想为不同的设备创建的版本差异甚巨。否则, 响应式网页设计会是完全合理的做法。

一个潜在的方案

这里有一个妥协方案:将设备分类,并为每个种类提供最佳体验。选择什么类别取决于你的产品和目标用户。下面是一个示例,能够很好的跨越现今流行的网络设备。

1.    小屏幕+触摸(主要是手机)

2.    大屏幕+触摸(主要是平板)

3.    大屏幕+键盘/鼠标(主要是台式机/笔记本电脑)

        这只是许多可能的分类方式之一,但在写作时有很大的意义。上面的列表中缺少的是没有触摸屏的移动设备(例如功能手机,一些专用的电子书阅读器)。然而,这些设备大部分都有键盘或者屏幕阅读软件,如果你的站点精心设计,可以在上面工作良好。

特定外形的WEB App例子

        有许多针对不同因素提供不同Web服务版本的例子。谷歌搜索是这样,Facebook也是。这主要是考虑了到性能(获取资源,渲染页面)和更通用的用户体验。

        在Native App的世界里,许多开发者选择为不同种类的设备设计产品。 例如,Flipboard iPad版本的UI与iPhone版本差异很大。平板版本为双手使用和水平旋转进行了优化,而手机版本关注单手交互和垂直翻转的体验。许多其他的iOS应用在手机和平板上也有明显的不同,例如Things(Todo list)和如下所示的 Showyou (社会化视频):


针对手机和平板定制的UI

方法#1:服务器端检测

        在服务器端,我们要了解正在处理的设备有更多的限制。每次请求发送的User-Agent头所提供的user agent(用户代理)字符串可能是最有用的线索。正因为如此,相同UA的嗅探方法会产生作用。事实上,DeviceAtlas和WURFL项目已经开始这样做了(并提供了一大堆设备有关的其他信息)。

        不幸的是目前这些项目都存在挑战。WURFL非常庞大,包含20MB的XML,可能为每个请求导致明显的服务器开销。有项目因为性能方面的原因分割了这些XML。DeviceAtlas并不开源,需要付费使用。

        这里有更简单,而且免费的替代品,例如检测移动浏览器项目。当然,缺点是设备检测难免会不够全面。 此外,它只区分移动和非移动设备,以及通过ad-hoc软件提供有限的平板支持。

方法2:客户端检测

        使用特性检测,我们可以了解更多用户浏览器和设备的信息。我们需要确定的要点是,该设备是否具有触摸功能,以及它的屏幕是大是小。

        我们需要画一条线来区分屏幕大和小的触摸设备。例如像5寸Galaxy Note的边缘情况。下图显示了许多流行的Andr​​oid和iOS设备轮廓(附上相应的屏幕分辨率)。星号表示该设备可以支持双倍密度。虽然像素密度可能会增加一倍,CSS仍然会报告相同的大小。

        对CSS里像素点的快速介绍:手机Web页面上的CSS像素和PC上并不一样。iOS视网膜设备引入了双倍像素密度(例如iPhone 3GS对iPhone 4,iPad 2对iPad 3)。视网膜设备上Safari浏览器的用户代理仍然报告相同的设备宽度,以免破坏网页。当其它设备(例如Android)采用了更高分辨率的显示屏时,它们也采用了相当的解决方案。


设备的分辨率

        这种方式会更复杂,但是这对考虑同时兼容纵向和横向模式非常重要。我们不希望每次屏幕旋转时都重新加载页面或者加载额外的脚本,虽然我们可能要呈现不同的页面。

下图中,正方形代表每个设备的最大尺寸,是叠加了纵向和横向轮廓的结果:


横向+纵向分辨率

        通过将阈值设置为650px ,我们将iPhone,Galaxy Nexus分类为小触摸屏设备,而将iPad,Galaxy Tab分类为“平板”。跨界的Galaxy Note在这种情况下被归类为“手机”,将采用手机布局。

        所以,一个合理的策略可能看起来像下面这样:

if (hasTouch) {
  if (isSmall) {
    device = PHONE;
  } else {
    device = TABLET;
  }
} else {
  device = DESKTOP;
}

        赶快看看一个小的示例特性检测方法吧。

        另一种方法是使用用户代理嗅探来检测设备类型,基本上就是创建一套试探方法来匹配用户的navigator.userAgent。伪代码看起来像这样:

var ua = navigator.userAgent;
for (var re in RULES) {
  if (ua.match(re)) {
    device = RULES[re];
    return;
  }
}

        马上来看看一个示例-UA检测方法

在客户端加载的说明

        如果你正在服务器上检测用户代理,你可以在收到新请求时决定提供哪种CSS,JavaScript和DOM节点。然而,如果你正在采用客户端检测,情况则更为复杂。你有如下几种选择:

1.    重定向到特定设备类型的URL,其​​中包含该设备类型的版本。

2.    动态加载设备特定类型的内容。

        第一种方法很简单,需要采用window.location.href = '/tablet'这种重定向的方式。然而,URL地址会附加设备类型的信息,所以你可能想使用HTML5的历史API来清理网址。不幸的是,这种方法涉及一个重定向,所以可能会很慢,尤其是在移动设备上。

        第二种方法实现更加复杂。你需要一种机制来动态加载CSS和JS,还有(根据浏览器而定)你可能无法实现例如自定义<meta viewport> 这样的事。此外因为没有重定向,你需要在一张页面上来响应请求。当然,你可以用JavaScript来实现,但是这可能导致性能缓慢和/或糟糕的代码,这一切都取决于你的应用程序。

选择客户端或服务器方案

        下面是在这些方法之间的权衡:

选择客户端 :

  • 基于屏幕尺寸或可扩展性的方案和用户代理比起来更为长远。
  • 无需不断更新用户代理名单。

选择服务器 :

  • 能完全控制什么设备上加载什么版本。
  • 更好的性能:无需客户端重定向或动态加载。

        我个人的偏好是,最开始使用device.js和客户端检测。 随着应用的发展,如果发现客户端重定向有明显的性能问题,你可以很容易地删除device.js脚本,并在服务器上执行用户代理检测。

DEVICE.JS介绍

        device.js是一个起点,这样做基于语义,依靠媒介查询进行设备检测,从而无需特殊的服务器端配置,节省了需要实现用户代理字符串解析的时间和精力。

        这个方法是在<head>标签的顶部用搜索引擎友好的标记(linkrel=alternate)声明你要提供的网站版本。

<link rel="alternate" href="http://foo.com" id="desktop"
    media="only screen and (touch-enabled: 0)">

        接下来,你可以采用服务器端UA检测和版本重定向,或者使用device.js脚本来执行基于功能的客户端重定向。

        更多详细信息,请参阅device.js项目页面 ,同时还有一个使用了device.js进行客户端重定向的测试应用

建议:MVC的具体视图

        现在你可能会想,我告诉你的是建立三个完全独立的应用程序,每个用于一种设备类型。不! 代码共享是关键。

        希望你已经使用了一个类MVC的框架,例如Backbone,Ember等等。如果你已经熟悉重点分解的原则,尤其是你的用户界面(视图层)应该与逻辑(模型层)分离。如果你对此还比较陌生,可以开始了解MVC的一些资源JavaScript中的MVC 模式。

        跨设备非常适合现有的MVC框架。你可以轻松地移动视图到独立的文件,为每个设备类型创建一个自定义视图。然后你就可以为所有设备使用除了视图层之外同样的代码。


跨设备的MVC模式

        你的项目可能有以下的结构(当然,你可以自由选择对你应用最有意义的结构):

models/ (shared models)
  item.js
  item-collection.js

controllers/ (shared controllers)
  item-controller.js

versions/ (device-specific stuff)
  tablet/
  desktop/
  phone/ (phone-specific code)
    style.css
    index.html
    views/
      item.js
      item-list.js

        这种结构使你能够完全控制每个版本加载哪些内容,因为你必须为每个设备采用自定义的HTML,CSS和JavaScript。这非常强大,是开发跨端Web App最精简和最有效的方式,不会依赖于一些小的技巧,例如自适应图像。

        一旦你运行喜欢的构建工具,会把所有的Javascript和CSS合并和压缩到一个独立的文件里,以实现更快的加载速度,而输出的HTML页面看起来类似以下的形式(在手机上,使用device.js):

<!doctype html>
<head>
  <title>Mobile Web Rocks! (Phone Edition)</title>

  <!-- Every version of your webapp should include a list of all
       versions. -->
  <link rel="alternate" href="http://foo.com" id="desktop"
      media="only screen and (touch-enabled: 0)">
  <link rel="alternate" href="http://m.foo.com" id="phone"
      media="only screen and (max-device-width: 650px)">
  <link rel="alternate" href="http://tablet.foo.com" id="tablet"
      media="only screen and (min-device-width: 650px)">

  <!-- Viewport is very important, since it affects results of media
       query matching. -->
  <meta name="viewport" content="width=device-width">

  <!-- Include device.js in each version for redirection. -->
  <script src=”device.js”></script>

  <link rel=”style” href=”phone.min.css”>
</head>
<body>
  <script src=”phone.min.js”></script>
</body>

        需要注意的是(touch-enabled: 0)媒介查询并不标准(只有Firefox通过moz前缀实现了),但是能够被device.js正确运行(感谢Modernizr.touch)。

版本覆盖

        设备检测有时候有误,在某些情况下,用户可能更喜欢在手机上采用平板布局(也许他们正在使用Galaxy Note),所以一定要向用户提供版本的选择。

        通常的做法是提供一个从桌面到移动版本的链接。这很容易实现,device.js通过device的GET参数来支持此功能。

结论

        综上,当需要建立跨设备单页的用户界面时,并不适合响应式设计,我们可以这样做:

1.    挑选一系列设备分类进行支持,并为设备分类设定标准。

2.    建立你的MVC应用,把界面从代码库分离出来。

3.    使用device.js进行客户端设备分类检测。

4.    当你准备好了时,为每个设备分类打包你的脚本和样式表。

5.    如果客户端重定向有性能问题,放弃device.js,并换到服务器端做UA检测。

译自:http://www.html5rocks.com/en/mobile/cross-device/

转载请注明:来自蒋宇捷的博客

作者:hfahe 发表于2012-5-18 23:01:52  原文链接
阅读:153 评论:0  查看评论
共享 保持为未读状态

[译]用HTML5实现iPad应用无限平滑滚动

前言:

        LinkedIn 52日发布了新的iPad版本,它基于HTML5制作,在体验和界面上非常出色,在使用中可以发现它和原生应用基本没有任何差别


        关于这个版本,有两篇文章非常有价值,深入的介绍了Mobile Web App和HTML5移动开发的原理和方法。

        第一篇《你绝对想不到的LinkedIn如何构建iPad新应用》主要包括三个方面的内容:

  • LinkedIn and themobile web

        LinkedIn开始越来越多的采用HTML5来开发移动Web应用。

  • Now, with more Node.js

        大量使用了node.js

  • “Responsive design” just doesn’t work

        他们认为响应式网页设计对简单的、一次性的网站很有用,但是对应用或者社交网络来说,它没有那么好。

        -------- -------- -------- -------- 华丽的分隔线

        而下面一篇文章讲述了LinkedIn是如何使用HTML5iOS中实现平滑无限滚动以及内存和性能优化的。

LinkedIn iPad版:用HTML55项技术实现无限平滑滚动

        作者:TrunalBhanse

        译者:蒋宇捷

        这是在一系列博客文章中的第二篇,我们将聊聊LinkedIniPad应用。在第一篇文章中,我们谈到了如何使用HTML5本地存储建立敏捷的移动体验,而这篇文章我要讲讲当实现一个无限翻页的列表时所面临的挑战。

什么是

        iPad项目开始时,我们考虑过如何才能为用户创造一个引人入胜的内容消费体验。我们决定以的方式来展示文章、网络更新,以及其他类似的内容:一个可以无限翻页的界面。这里是页面流的第一页:


移动设备上无限列表的挑战

        和台式机相比,移动设备具有更少的内存和更低的CPU主频。如果在HTML页面中渲染很长的列表,你会面临运行设备崩溃的危险。这使得在移动设备上构建大型的HTML5互动应用成为一个挑战。Native技术提供了UITableViewController来建立长的,无限滚动的列表。UITableView包含可复用的UITableViewCells来优化内存,性能以及响应。而针对HTML5我们没有任何现成解决方案。因此,我们将自己实现一个!

技巧1:移除图像

        UIWebView或者移动Safari浏览器对图像有严格限制。我们的页面流里铺满了大尺寸图像,所以很快就会达到上限。一种选择是使用HTML5Canvas绘制图像,不会带来内存问题。然而我们发现在画布上绘制非常大的图像相当缓慢,所以我们不得不采取另一种方法:当一副图像完全“流”出屏幕时,用另一副非常小的图像替换img标签的“SRC”属性。这能确保渲染大型图像所使用的内存被定期释放。此外,我们保证并没有引入图像src属性的错误

技巧2:隐藏页面

        释放图像并没有回收足够的内存来防止崩溃。因此,我们开始通过将CSS visibility属性设置为hidden 隐藏流的独立页面(图2表示隐藏的页面)。经过这种调整,我们不仅看到了更多的内存被回收(这样应用程序就不会崩溃),而且渲染速度也更快,因为浏览器不会为界面上隐藏的页面进行绘制。

技巧3:删除页面

        采用隐藏的页面可以覆盖80%的情况。但是余下的20%仍然会导致应用程序崩溃!我们更进一步,开始删除不需要的页面。作为副作用,如果我们删除当前页面左侧的页面,页面流会左移,而用户将失去所在位置。为了保持滚动位置,我们不得不在移除页面时(即DOM节点)用同样高度和宽度的空白页面来取代(图2中示意的占位符)。例如,如果用户正在浏览第5页,我们删除第0页,并用占位符取而代之。

        采用了上述的3种技术,我们的流开始类似于下面图里的样子。 正如你可以在图1中看到的一样,如果用户正在查看第3页,前一页和后一页将完全加载。而当用户决定向前或者向后翻页时,他可以看到完全呈现的页面。当用户试图滚动时,我们开始加载图像并渲染页面。它可以在iPad模拟器上完美运行,但在实际设备上,你可以看到滚动性能的下降。

图1


图2

        正如图2所示,当用户翻动到第5页,第0和第1页将会被删除,第2页将会隐藏,而第3页移除了所有图像。此时,用户可以继续向前翻页,其它页面将根据它们和可见页面之间的距离来决定是移除图像、隐藏还是删除自身。

        我们不得不为不同版本的iPad使用一个可变大小的窗口。例如,iPad1内存最少,所以我们不得不给它一个非常小的窗口:

 getConfig : function() {

    //默认设置
    var config = {
      size : 3,
      maxVisibleOnOneSide : 1,
    };

    //根据设备更新设置
    if($isDesktop || $native.isNative() && $os.ipad) {
      //检测是ipad1还是ipad2
      if($isDesktop || $native.getDeviceVersion() > 1) {
        config.size = 7;
        config.maxVisibleOnOneSide = 2;
      }
    }
    return config;

  }

技巧4:避免缩放和盒阴影

        按照之前的经验,我们使用两个HTML / CSS的优化技巧来改善性能:

  • 通过HTML IMG标签中指定宽度高度属性来避免客户端缩放图像
  • 避免CSS盒阴影:它在WebKit下很

技术5:减少DOM节点

        经过上述优化,你是否预期应用再也不会崩溃?错了!在测试过程中,上述技巧让应用程序运行的时间更长,但一段时间后它仍然会崩溃。

        根据之前iPhone应用的经验,我们知道保持DOM节点最少是平滑滚动和保证足够内存的关键点。 记住这一点后,我们将所有占位所用的节点合并为一个虚拟的,相同大小的节点。结果是:不管我们滑动到多少页,页面流不会在任何设备上崩溃!最终机制如图3所示:


图3

技术实现的视频

        这里有一个当用户滑动翻页时,DOM所表现出来行为的视频。左边我们在Chrome窗口中加载页面流。而在右边,我们通过Chrome的开发者工具来展示如何添加或删除节点和通过虚拟页面的宽度来填补被删除的网页。 注意DOM节点是如何保持在一个恒定的数量的,以及UL 的第一个li节点虚拟节点)大小是如何增长的(你可能需要全屏播放视频来看)。

失败的尝试

        我们并没有在第一时间得到正确的结果,所以必须要列出我们一些曾经失败的尝试。我们最开始使用多个UIWebViews来各自渲染一个页面并用UISwipeGestureRecognizer来翻页 然而我们很快就意识到,在本地应用程序使用多个Web视图在内存和性能方面是一种糟糕的方式。

        随后我们尝试了和3-DIV类似的方法。它可以工作,但是我们对滑动翻页的性能并不满意。 有时如果用户在翻页,我们同时在渲染一个页面,单线程的UIWebView 无法添加到页面流里面。

致谢

        感谢Akhilesh GuptaAarthiJayaramAshitGandhiKiranPrasadGanesh Srinivasan

        此外,特别感谢 Ryan帮我为这篇文章录制视频。

        原文链接:《LinkedIn for iPad: 5 techniques for smooth infinite scrolling in HTML5

        转载请注明:来自蒋宇捷的博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值