`
hax
  • 浏览: 961284 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

坑爹的viewport

    博客分类:
  • UX
阅读更多


最近我做了一点儿针对手机的Web开发和相关研究。按说,Web自设计之初,就已经考虑了设备无关性。然而,现实总是不尽如人意

我们知道大多数网页都是针对桌面显示器开发和测试的,但是手机屏幕通常要比桌面显示器小很多,比如iPhone也就是320px。那么那些网页在手机上如何浏览呢?

一种是把网页缩放到很小,你可以看到整个网页但是看不清字了;或者只看网页的一个局部,然后上下左右移动来看其他部分。现在的手机浏览器把两种模式结合使用。
(或许还有第三种——分析网页,将其中内容抽取出来,重组,然后呈现,不过这里不讨论这种方式。)

如果仅仅是出现横向滚动条,那问题倒不是很大。对于那些采用固定布局的“像素级精确设计”确实就是如此。但是使用自适应布局的网页就有问题了。比如一个三栏布局,其中一个边栏可能只有20%宽度,320px的屏幕上只有60多像素,只能放5个汉字,排版不美观不要说,如果里面有一些图片,很可能图片的宽度都超过60像素,造成overflow,从而破坏了布局。另一种常见布局方式是采用固定大小的边栏,例如240px宽,而主体部分则自适应宽度。然而对于320px的屏幕来说,本来是次要的边栏占据了3/4空间,主要部分却只有1/4空间,另外也极有可能因为内容包含图片等造成overflow。

说到这里,那些喜欢固定布局的人(比如那些热衷于960px grid排版的同志们——哦,最近淘宝升级成1000并放弃了栅格!不过那仍然是固定布局)可能要乐了,你们倡导了半天流式布局,结果在mobile设备上表现反而很糟糕,真是费力不讨好。

真正掌握CSS的同志(是的,珍稀动物!)肯定会反驳。上面这些问题其实都很容易解决。比如设定min-width。还有,适应不同屏幕大小的“正确”的方案,应该用media query。

问题是,大多数网页没有这么做!或者说不是按照“正确”的方式写的!未必是网页作者不懂CSS,而只是他们压根没费心考虑过手机大小的屏幕(毫不惭愧的说,本人也是其中一份子)。你可以试着把桌面浏览器收缩成320px宽(或者可以试着zoom in到300%),可以看到不少网页会发生严重的布局错乱,至少也是浏览体验上的大幅下降。为了迎合这些网页,手机浏览器厂商发明了两个viewport

简单来说,就是手机浏览器把自己冒充为拥有一个更宽的屏幕,这样页面的布局就能跟桌面浏览器一样了。不同浏览器冒充的数值不一样:iPhone是神奇的980——960它表弟;Android是保守的800——冒充一个800*600的显示器;而Windows Phone 7则是1024——冒充一个1024*768的显示器(充分体现微软的庸俗特质)。

原本布局就是按照viewport(桌面上的浏览器窗口)大小来进行的,现在决定布局的viewport和窗口分裂了,产生了两个viewport。

两个viewport其实并不新鲜。就像前面说的,所有做固定布局的同学其实都在不自觉使用两个viewport——固定布局,其实相当于人为设定了布局viewport。

使用独立的布局viewport还有一个好处,那就是缩放变得很简单,不用引起relayout。

在浏览器的历史上,主要有两种不同的缩放方式,一种是以IE6为代表的缩放(文字大小),实质是改变root元素的字体大小。另一种是像素缩放,实质是改变CSS pixel的大小(即1个css像素不再对应1个物理像素),或者说改变了浏览器的内部DPI。(Firefox还支持真正的字体缩放,与改变root元素的字体大小不同,它会缩放所有元素的font-size最终使用的值(used value),因此不仅对于以em设定的字体大小有效,对于以px和pt等所有单位设定的字体大小都有效。)

在桌面浏览器上,因为缩放时viewport的物理大小是固定的,如果进行像素缩放,实际就意味着viewport以CSS pixel计算的宽度和高度会随之改变,比如若放大到200%,CSS宽高就会缩小到原来的50%。而这必然引起relayout。

相反,在mobile浏览器上,像素缩放时,布局viewport的物理大小可随之缩放,因此其CSS宽高值是不变的,就不必引起relayout。这不仅避免了relayout的大量计算,也更符合移动设备上的用户体验(考虑一下你如何缩放地图就明白了)。

虽然两个viewport能比较好的解决在手机上浏览过往网页的问题,然而,这毕竟是一个向后看的方案,体验毕竟是受限的。想象在320宽的窗口里看960固定布局的网页,不可避免的要时常缩放和使用横向滚动条。在触摸屏上我们可以用手势来控制,会方便一点,但是仍然很麻烦。所以绝大多数移动Web开发者最终还是选择针对小屏幕(重新)进行设计。

不过一个显然的问题是,如果我的网页已经考虑了小屏幕,甚至就是专门为手机设计的,那么我其实不需要两个viewport(也不需要缩放),这时候怎么办?更一般的问题是,如果我设计的网页不是针对960或者800或者1024的呢(至少你选了960,就排除了800和1024;你选了800,就排除了960和1024;你选了1024,就排除了800和960……)?

于是Apple发明了viewport的meta标签,例如:
<meta name="viewport" content="width=320, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">

其中width表示网页的布局layout宽度。initial-scale表示初始时的缩放比例,minimum-scale和maximum-scale分别表示最小和最大缩放比例。这样,上面这个meta就表示布局宽度320像素,初始缩放为1倍(即不缩放),且禁止用户缩放(因为最大最小缩放都为1倍)——一个专为iPhone优化的网页通常就会用这样的设置。

如果你是针对960设计的,那么可以用这样一个meta:
<meta name="viewport" content="width=960, initial-scale=0.33">
这表示布局宽度为960像素,初始缩放为0.33,也就是,会缩小到大约1/3,这样正好可以在320像素的宽度里看到整个网页。你也可以不设initial-scale,因为手机浏览器大多默认会初始缩放到可容纳整个网页宽度。

嗯,看上去不错吧。

可是,说到底,手机浏览器的这种设计,实际上揭示了一个难堪的真相——你们这些网页仔,其实从来没真正做好过屏幕适应。因为一个能自动完美适应不同屏幕大小的“正确”方案,width的取值就不应该是一个固定数字。幸好,safari的工程师在发明viewport时还是给我们留了点面子,width的取值除了像320或960这样的数字,也可以是关键字device-width(其实我认为更合适的词是auto),表示采用设备宽度。

然而,历史总是杯具的重复自己。微软就又(嗯,我为什么要说“又”呢?)贡献了这样一个例子:Window Phone 7的设备宽度通常至少是480,那么按理说,如果viewport中设置了width=device-width,layout宽度应该是480像素,可是IE mobile会将viewport设为320!这是神马原因呢?

原来据说微软收集的数据表明,有大量站点使用了device-width,但是其实只为320像素宽(也就是iPhone的宽度)优化——比如直接用一个固定宽度320px的<div>将内容wrap起来!我勒个去,诸位移动Web开发者,你们有木有这么干?有木有!

那后面的故事就不用说了。微软当然是做出了一个“正确”的选择。

另外需要注意的是,width只是设置layout宽度,还要乘上缩放比例,才能得到最终的显示宽度。那么对于480像素的屏幕来说,若device-width“被320”,那initial-scale应该是1.5才能占满整个屏幕宽度。可是如前所述,针对性优化的网页会把initial-scale设成1.0!

对此微软是如何处理的呢?文档语焉不详,而其模拟器要在Windows 7上才能运行,所以我也暂时没有进行实测,不过据我推测,其initial-scale应该仍旧会保持1.0,也就是这1.5会变成额外的缩放因子。实际上其他移动浏览器已经这样做了,比如Fennec(Firefox的移动版)就是如此。Android和iPhone 4也都有类似的设计,为什么会这样?这样会不会产生新问题?留待下一篇博客再讨论。







6
0
分享到:
评论
7 楼 limuchen12 2013-02-28  
limuchen12 写道
cn126 写道
<meta name="viewport" content="width=960, initial-scale=0.33">
其中的width不是layout的宽度,而是viewport的宽度。搞清楚了width的含义,楼主的一切疑问都仍忍而解,所以viewport没坑爹。


width=960 :
960是layout的宽度;
width是viewport的宽度;
这里是将viewport的宽度设置为正好显示layout;
浏览器在解析viewport时,将viewport转换为屏幕宽度;
layout正好显示layout。


layout正好显示layout。

手机屏幕正好显示layout。
6 楼 limuchen12 2013-02-28  
cn126 写道
<meta name="viewport" content="width=960, initial-scale=0.33">
其中的width不是layout的宽度,而是viewport的宽度。搞清楚了width的含义,楼主的一切疑问都仍忍而解,所以viewport没坑爹。


width=960 :
960是layout的宽度;
width是viewport的宽度;
这里是将viewport的宽度设置为正好显示layout;
浏览器在解析viewport时,将viewport转换为屏幕宽度;
layout正好显示layout。
5 楼 accphc 2013-02-22  
文笔很犀利,就是没说解决方案啊。
4 楼 yangbeibei28 2013-01-04  
我觉得楼主说的很有道理,我最近也遇到了这样的问题,最后是怎么解决的呢?
3 楼 hax 2012-08-12  
@cn126 我的疑问是为什么总有人不懂装懂。
2 楼 cn126 2012-07-25  
<meta name="viewport" content="width=960, initial-scale=0.33">
其中的width不是layout的宽度,而是viewport的宽度。搞清楚了width的含义,楼主的一切疑问都仍忍而解,所以viewport没坑爹。
1 楼 dulao5 2011-03-29  
每次看HAX的文章都惊为天人, 请教一下HAX是如何做这些深入研究的? 有学习路线没?

相关推荐

    html meta viewport属性说明

    什么是Viewport 手机浏览器是把页面放在一个虚拟的“窗口”(viewport)中,通常这个虚拟的“窗口”(viewport)比屏幕宽,这样就不用把每个网页挤 到很小的窗口中(这样会破坏没有针对手机浏览器优化的网页的布局)...

    Viewport Auto-Snap

    "Viewport Auto-Snap" 是一个专门针对3D视图操作的工具或脚本,它旨在提升3D建模和设计过程中的工作效率。在3D建模软件中,视口是用户观察、操作3D模型的主要界面,而"Auto-Snap"功能则是指自动对齐或捕捉,通常用于...

    WPF的3D显示 ViewPort3D绘图入门参考资料

    `ViewPort3D` 是WPF中的关键组件,用于在2D屏幕上显示3D场景。在这个主题中,我们将深入探讨如何使用`ViewPort3D`以及相关的`Helix Toolkit`库来实现3D模型的缩放、旋转和平移。 首先,`ViewPort3D`是WPF 3D框架中...

    viewport响应式模板

    viewport响应式模板

    WPF ViewPort3D 展示且平移操作

    在Windows Presentation Foundation (WPF) 中,ViewPort3D 是一个强大的组件,它允许开发者创建丰富的3D图形用户界面。这个组件是WPF 3D功能的核心,它为3D对象提供了一个显示区域,并提供了对3D场景进行交互的能力...

    前端开源库-postcss-px-to-viewport

    其中,`postcss-px-to-viewport` 是一个非常实用的前端开源工具,它允许我们将传统的像素单位(px)自动转换为基于视口的单位(vw、vh、vmin、vmax),以适应各种屏幕尺寸,从而实现更加灵活的布局。 首先,我们...

    viewport与android的webview

    在移动Web开发中,`viewport` 和 `Android Webview` 是两个至关重要的概念。`viewport` 是一个虚拟的浏览区域,决定了网页在不同设备上的显示方式,尤其是对于智能手机和平板电脑这样的小屏幕设备。而`Android ...

    前端开源库-viewport-list

    【前端开源库-viewport-list】是一个专为前端开发者设计的工具库,它的主要功能是提供一个设备视区的列表,帮助开发者更好地理解和处理不同设备在渲染网页时的可见区域,即视口。在Web开发中,视口是浏览器用于显示...

    Ext Designer入门3-Viewport和Border布局

    本节介绍 Ext的Border布局以及如何创建一个Viewport。 1、Viewport介绍: Viewport 是一类特殊的容器。它创建后会自动填充到整个页面区域,并能自动适应页面缩放。一般作为用用程序全局容器使用。 2、Border布局...

    图文并茂让你必须弄懂viewport配套示例代码.rar

    【标题】"图文并茂让你必须弄懂viewport配套示例代码.rar"的资源是一份针对网页开发中的关键概念——“视口”(viewport)的详细教程。这份压缩包包含了一个HTML示例页面(视口--viewport.html)、一个链接到相关...

    WPF三维立体动画(一个WPF项目,利用viewport3D呈现)

    `Viewport3D` 包含两个主要组成部分:`Viewport3DVisual` 和 `Model3DGroup`。`Viewport3DVisual` 是显示3D内容的容器,而 `Model3DGroup` 则用于组织3D模型和效果。 要构建3D模型,我们通常会用到以下几种3D元素:...

    前端项目-viewport-units-buggyfill.zip

    【前端项目-viewport-units-buggyfill.zip】是一个专门针对前端开发的项目,其核心目的是确保在旧版的WebKit(如Safari、Chrome的老版本)和Trident(IE浏览器)中,视区单位(viewport units)如 vh (viewport ...

    ember-in-viewport, 在 viewport @ 60FPS,检测Ember视图或者组件是否为.zip

    ember-in-viewport, 在 viewport @ 60FPS,检测Ember视图或者组件是否为 ember-in-viewport检测Ember视图或者组件是否位于 viewport @ 60 FPS 。美国船厂建立和维护收费 ,请与我们联系,咨询专家 Ember.js 。读取 ...

    前端开源库-postcss-px-to-viewport.zip

    标题"前端开源库-postcss-px-to-viewport.zip"指出这是一个关于前端开发的开源库,具体是PostCSS插件——Postcss-px-to-viewport。PostCSS是一个工具,允许开发者通过编写JavaScript插件来转换CSS代码,以实现各种...

    fabricjs-viewport, 在fabricjs中,允许缩放和viewport操作.zip

    fabricjs-viewport, 在fabricjs中,允许缩放和viewport操作 fabricjs-viewport fabricjs中viewport和缩放的简单实现。不更改数据模型,因此缩放/抓取后画布上的所有对象都不会更改支持触摸屏设备支持自由绘制模式第...

    WPF_Viewport3D-master_wpfviewPort3D_

    **WPF Viewport3D详解** 在Windows Presentation Foundation (WPF)中,ViewPort3D是用于构建3D图形和场景的主要控件。这个项目,"WPF_Viewport3D-master",旨在提供一个简单的实例,帮助开发者了解如何在WPF环境中...

    一个功能强大的viewport程序实例

    一个功能强大的viewport程序实例,可以满足你多种需要调节。

    viewport 视口与窗口 逻辑坐标 设备坐标

    viewport 视口 窗口 GDI 坐标 映射方式定义了Windows如何将GDI函数中指定的逻辑坐标映射为设备坐标。 Windows有关映射模式的一些术语:逻辑坐标所在的坐标系称为"窗口",将设备坐标所在的坐标系称为"视口"。

    ExtJs_Viewport_Example

    "ExtJS_Viewport_Example"是关于如何在ExtJS应用中使用Viewport的概念和实践示例。 Viewport 是ExtJS中的一个重要概念,它是一个特殊的容器,全屏占据浏览器窗口的可见部分,用来展示应用的主要内容。当你想要确保...

Global site tag (gtag.js) - Google Analytics