关于移动设备视口

A tale of two viewports — part two

show page contents

In this mini-series I will explain how viewports and the widths of various important elements work, such as the <html>element, as well as the window and the screen.

On this page we’re going to talk about the mobile browsers. If you’re totally new to mobile I advise you to read part one about the desktop browsers first, in order to set the stage in a familiar environment.

The problem of mobile browsers

When we compare the mobile browsers to the desktop ones, the most obvious difference is screen size. Mobile browsers display significantly less of a desktop-optimised website than desktop browsers; either by zooming out until the text is unreadably small, or by showing only the small part of the site that fits in the screen.

A mobile screen is far smaller than a desktop screen; think about 400px wide at maximum, and sometimes a lot less. (Some phones report larger widths, but they’re lying — or at the very least giving us useless information.)

An intermediate layer of tablet devices such as the iPad or the rumoured HP webOS-based one will bridge the gap between desktop and mobile, but that doesn’t change the fundamental problem. Sites must work on mobile devices, too, so we have to get them to display well on a small screen.

The most important problems center on CSS, especially the dimensions of the viewport. If we’d copy the desktop model one-to-one, our CSS would start to misfire horrendously.

Let’s go back to our sidebar with width: 10%. If mobile browsers would do exactly the same as desktop browsers, they’d make the element about 40px wide at most, and that’s far too narrow. Your liquid layout would look horribly squashed.

One way of solving the problem is building a special website for mobile browsers. Even apart from the fundamental question of whether you should do that at all, the practical problem is that only very few site owners are sufficiently clued-in to cater specifically to mobile devices.

Mobile browser vendors want to offer their clients the best possible experience, which right now means “as much like desktop as possible.” Hence some sleight of hand was necessary.

The two viewports

So the viewport is too narrow to serve as a basis for your CSS layout. The obvious solution is to make the viewport wider. That, however, requires it to be split into two: the visual viewport and the layout viewport.

George Cummins explains the basic concept best here at Stack Overflow:

Imagine the layout viewport as being a large image which does not change size or shape. Now image you have a smaller frame through which you look at the large image. The small frame is surrounded by opaque material which obscures your view of all but a portion of the large image. The portion of the large image that you can see through the frame is the visual viewport. You can back away from the large image while holding your frame (zoom out) to see the entire image at once, or you can move closer (zoom in) to see only a portion. You can also change the orientation of the frame, but the size and shape of the large image (layout viewport) never changes.

See also this explanation by Chris.

The visual viewport is the part of the page that’s currently shown on-screen. The user may scroll to change the part of the page he sees, or zoom to change the size of the visual viewport.

However, the CSS layout, especially percentual widths, are calculated relative to the layout viewport, which is considerably wider than the visual viewport.

Thus the <html> element takes the width of the layout viewport initially, and your CSS is interpreted as if the screen were significantly wider than the phone screen. This makes sure that your site’s layout behaves as it does on a desktop browser.

How wide is the layout viewport? That differs per browser. Safari iPhone uses 980px, Opera 850px, Android WebKit 800px, and IE 974px.

Some browsers have special behaviour:

  • Symbian WebKit tries to keep the layout viewport equal to the visual viewport, and yes, that means that elements with a percentual width may behave oddly. However, if the page doesn’t fit into the visual viewport due to absolute widths the browser stretches up the layout viewport to a maximum of 850px.
  • Samsung WebKit (on bada) makes the layout viewport as wide as the widest element.
  • On BlackBerry the layout viewport equals the visual viewport at 100% zoom. This does not change.

Zooming

Both viewports are measured in CSS pixels, obviously. But while the visual viewport dimensions change with zooming (if you zoom in, less CSS pixels fit on the screen), the layout viewport dimensions remain the same. (If they didn’t your page would constantly reflow as percentual widths are recalculated.)

Understanding the layout viewport

In order to understand the size of the layout viewport we have to take a look at what happens when the page is fully zoomed out. Many mobile browsers initially show any page in fully zoomed-out mode.

The point is: browsers have chosen their dimensions of the layout viewport such that it completely covers the screen in fully zoomed-out mode (and is thus equal to the visual viewport).

Thus the width and the height of the layout viewport are equal to whatever can be shown on the screen in the maximally zoomed-out mode. When the user zooms in these dimensions stay the same.

The layout viewport width is always the same. If you rotate your phone, the visual viewport changes, but the browser adapts to this new orientation by zooming in slightly so that the layout viewport is again as wide as the visual viewport.

This has consequences for the layout viewport’s height, which is now substantially less than in portrait mode. But web developers don’t care about the height, only about the width.

Measuring the layout viewport

We now have two viewports that we want to measure. Therefore it’s very lucky that the Browser Wars gave us two property pairs.

document. documentElement. clientWidth/Height
Meaning
Layout viewport dimensions
Measured in
CSS pixels
Full support
Opera, iPhone, Android, Symbian, Bolt, MicroB, Skyfire, Obigo
Problems
Visual viewport dimensions in Iris
Samsung WebKit reports the correct values when a <meta viewport> tag is applied to the page; the dimensions of the <html> element otherwise.
Screen dimensions in device pixels in Firefox
IE returns 1024x768. However, it stores the information indocument.body.clientWidth/Height. This is consistent with IE6 desktop.
NetFront’s values are only correct at 100% zoom.
Symbian WebKit 1 (older S60v3 devices) does not support these properties.
Not supported
BlackBerry

document.documentElement.clientWidth and -Height contain the layout viewport’s dimensions.

The orientation matters for the height, but not for the width.

Measuring the visual viewport

window.innerWidth/Height
Meaning
Visual viewport dimensions
Measured in
CSS pixels
Full support
iPhone, Symbian, BlackBerry
Problems
Opera and Firefox return the screen width in device pixels.
Android, Bolt, MicroB, and NetFront return the layout viewport dimensions in CSS pixels.
Not supported
IE, but it gives the visual viewport dimension indocument. documentElement. offsetWidth/Height.
Samsung WebKit reports either the dimensions of the layout viewport or of the <html>, depending on whether a <meta viewport> tag has been applied to the page or not.
Gibberish
Iris, Skyfire, Obigo

As to the visual viewport, it is measured bywindow.innerWidth/Height. Obviously the measurements change when the user zooms out or in, since more or fewer CSS pixels fit into the screen.

Unfortunately this is an area of incompatibilities; many browsers still have to add support for the measurement of the visual viewport. Still, no browser stores this measurment in any other property pair, so I guesswindow.innerWidth/Height is a standard, albeit a badly supported one.

The screen

screen.width and screen.height
Meaning
Screen size
Measured in
Device pixels
Full support
Opera Mini, Android, Symbian, Iris, Firefox, MicroB, IE, BlackBerry
Problems
Opera Mobile on Windows Mobile only gives the landscape size. Opera Mobile on S60 gets it right.
Samsung WebKit reports either the dimensions of the layout viewport or of the <html>, depending on whether a <meta viewport> tag has been applied to the page or not.
iPhone and Obigo only give portrait sizes.
NetFront only gives landscape sizes.
Gibberish
Bolt, Skyfire

As on desktop, screen.width/height give the screen size, in device pixels. As on the desktop, you never need this information as a web developer. You’re not interested in the physical size of the screen, but in how many CSS pixels currently fit on it.

The zoom level

Reading out the zoom level directly is not possible, but you can get it by dividing screen.width by window.innerWidth. Of course that only works if both properties are perfectly supported.

Fortunately the zoom level is not important. What you need to know is how many CSS pixels currently fit on the screen. And you can get that information from window.innerWidth — if it’s supported correctly.

Scrolling offset

window.pageX/YOffset
Meaning
Scrolling offset; which is the same as the visual viewport’s offset relative to the layout viewport.
Measured in
CSS pixels
Full support
iPhone, Android, Symbian, Iris, MicroB, Skyfire, Obigo.
Problems
Opera, Bolt, Firefox, and NetFront always return 0.
Samsung WebKit reports correct values only if a <meta viewport> is applied to the page.
Not supported
IE, BlackBerry. IE stores the values in document. documentElement. scrollLeft / Top

What you also need to know is the current position of the visual viewport relative to the layout viewport. This is the scrolling offset, and, just as on desktop, it’s stored in window.pageX/YOffset.

<html> element

document. documentElement. offsetWidth / Height
Meaning
Total size of the <html>element.
Measured in
CSS pixels
Full support
Opera, iPhone, Android, Symbian, Samsung, Iris, Bolt, Firefox, MicroB, Skyfire, BlackBerry, Obigo.
Problems
NetFront’s values are only correct at 100% zoom.
IE uses this propery pair to store the dimensions of the visual viewport. In IE, see document. body. clientWidth/Height for the correct values.

Just as on desktop,document.documentElement.offsetWidth/Height gives the total size of the <html> element in CSS pixels.

Media queries

Media queries
Meaning
Measure <html> element width (CSS pixels) or device width (device pixels).
Full support
Opera, iPhone, Android, Symbian, Samsung, Iris, Bolt, Firefox, MicroB.
Not supported
Skyfire, IE, BlackBerry, NetFront, Obigo.
Note
What I test here is whether the browsers take their data from the correct property pairs. Whether these property pairs give correct information is not part of this particular test.

Media queries work the same as on desktop. width/height uses the layout viewport as its reference and is measured in CSS pixels, device-width/height uses the device screen and is measured in device pixels.

In other words, width/height mirrors the values of document. documentElement. clientWidth/Height, while device-width/height mirrors the values of screen.width/height. (They actually do so in all browsers, even if the mirrored values are incorrect.)

Now which measurement is more useful to us web developers? Point is, I don’t know.

I started out thinking that the device-width was the most important one, since it gives us some information about the device that we might be able to use. For instance, you could vary the width of your layout to accomodate the width of the device. However, you could also do that by using a <meta viewport>; it’s not absolutely necessary to use thedevice-width media query.

So is width the more important media query after all? Maybe; it gives some clue as to what the browser vendor thinks is a good width for a website on this device. But that’s rather vague, and the width media query doesn’t really give any other information.

So I’m undecided. For the moment I think that media queries are important to figure out whether you’re on a desktop, a tablet, or a mobile device, but not so very useful for distinguishing between the various tablet or mobile devices.

Or something.

Event coordinates

Event coordinates
Meaning
See main text.
Measured in
See main text.
Full support
Symbian, Iris
Problems
Opera Mobile gives pageX/Y in all three property pairs, but something goes wrong when you scroll a lot.
On iPhone, Firefox, and BlackBerry clientX/Y is equal to pageX/Y
On Android and MicroB screenX/Y is equal to clientX/Y (in CSS pixels, in other words)
On Firefox screenX/Y is wrong.
IE, BlackBerry, and Obigo don’t support pageX/Y.
In NetFront all three are screenX/Y.
In Obigo clientX/Y is screenX/Y.
Samsung WebKit always reports pageX/Y.
Not tested in
Opera Mini, Bolt, Skyfire

Event coordinates work more or less as on desktop. Unfortunately, of the twelve tested browsers only two, Symbian WebKit and Iris, get all three exactly right. All other browsers have more or less serious problems.

pageX/Y is still relative to the page in CSS pixels, and this is by far the most useful of the three property pairs, just as it is on desktop.

clientX/Y is relative to the visual viewport in CSS pixels. This makes sense, although I’m not entirely certain what it’s good for.

screenX/Y is relative to the screen in device pixels. Of course, this is the same reference that clientX/Y uses, and device pixels are useless. So we do not need to worry about screenX/Y; it’s every bit as useless as on desktop.

Meta viewport

Meta viewport
Meaning
Set the layout viewport’s width.
Measured in
CSS pixels
Full support
Opera Mobile, iPhone, Android, Iris, IE, BlackBerry, Obigo
Not supported
Opera Mini, Symbian, Bolt, Firefox, MicroB, NetFront
Problems
Skyfire can’t handle my test page.
If the <meta viewport> is applied to the page in Samsung WebKit, several other properties change meaning.
Opera Mobile, iPhone, Samsung, and BlackBerry do not allow the user to zoom out.

Finally, let’s discuss the <meta name="viewport" content="width=320">; originally an Apple extension but meanwhile copied by many more browsers. It is meant to resize the layout viewport. In order to understand why that’s necessary, let’s take one step back.

Suppose you build a simple page and give your elements no width. Now they stretch up to take 100% of the width of the layout viewport. Most browsers zoom out to show the entire layout viewport on the screen, giving an effect like this:

All users will immediately zoom in, which works, but most browsers keep the width of the elements intact, which makes the text hard to read.

(The significant exception here is Android WebKit, which actually reduces the size of text-containing elements so that they fit on the screen. This is absolutely brilliant, and I feel all other browsers should copy this behaviour. I will document it fully later.)

Now what you could try is setting html {width: 320px}. Now the<html> element shrinks, and with it all other elements, which now take 100% of 320px. This works when the user zooms in, but not initially, when the user is confronted with a zoomed-out page that mostly contains nothing.

It is in order to get around this problem that Apple invented the meta viewport tag. When you set <meta name="viewport" content="width=320"> you set the width of the layout viewport to 320px. Now the initial state of the page is also correct.

You can set the layout viewport’s width to any dimension you want, including device-width. That last one takes screen.width (in device pixels) as its reference and resizes the layout viewport accordingly.

There’s a catch here, though. Sometimes the formal screen.width does not make much sense because the pixel count is just too high. For instance, the Nexus One has a formal width of 480px, but Google engineers have decided that giving the layout viewport a width of 480px when using device-width is just too much. They shrank it to 2/3rds, so that device-width gives you a width of 320px, just as on the iPhone.

If, as is rumoured, the new iPhone will sport a larger pixel count (which does not necessarily equal a larger screen!), I wouldn’t be surprised if Apple copies this behaviour. Maybe in the end device-width will just mean 320px.

Related research

Several related topics have to be researched further:

      • position: fixed. A fixed element, as we know, is positioned relative to the viewport. But relative to which viewport?
        I’ve done this research meanwhile.
      • Other media queries: dpi, orientation, aspect-ratio. dpi, especially, is a disaster area, not only because all browsers report 96dpi, which is usually false, but also because I’m not yet totally sure which value is most interesting for web developers.
      • What happens when an element is wider than the layout viewport/HTML element? Say I insert an element with width: 1500px into one of my test pages? The element will stick out of the HTML element (overflow: visible), but that means that the actual viewport can become wider than the layout viewport. Besides, an old Android (Nexus One) enlarged the HTML element when this happens. Is that a good idea?
时间: 2024-08-09 09:22:12

关于移动设备视口的相关文章

vh——实现根据视口的高度,自适应某一部分的高度

vh是CSS3中的相对长度单位,表示相对视口高度(Viewport Height),视口被均分为100单位的vh,即1vh = 1% * 视口高度. 可以用来解决主体内容不足以撑起视口的剩余高度时,页面底部留白太多的尴尬问题. demo: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport

《响应式Web设计实践》学习笔记

原书: 响应式Web设计实践 第2章 流动布局 1. 布局选项 传统的固定布局中存在很多问题, 随着屏幕大小的越来越多元化, 固定布局已经不能适用了. 在流动布局中, 度量的单位不再是像素, 而是变成了百分比. 弹性布局与流动布局类似, 但是通常情况下, 弹性布局中会以em来作为单位. 带来一个好处是随着用户增大或减小字体, 适用弹性布局的元素的宽度也会等比例地变化. 但是其也可能出现水平滚动条 混合布局 媒体查询: 媒体查询允许根据设备的信息----诸如屏幕宽度, 方向或者分辨率等属性来使用不

响应式设计:媒体查询

媒体查询可以让我们根据设备显示的特性为其设定CSS样式.可以在不改变页面内容的情况下,为特定的一些输出设变指定显示效果. 一.媒体查询语法 1.<link>标签:通过link标签的media属性为样式表指定设备类型,例如: 以下代码表示媒体类型是显示屏,媒体特性为显示屏纵向放置,此时才引入cssy样式 <link rel="stylesheet" type="text/css" media="screen and (orientation

响应式实现初探

前段时间,因为项目需要,略微接触了一下响应式设计.在此记录一些经验之谈. 我所理解的响应式设计,  是网站能响应当前屏幕的宽度,呈现相应合适的样式和内容.比如在手机端,手机端屏幕较小,而且用户可能在3g网络下访问.网站在手机端下显示的时候,呈现的内容较之桌面要少一些,所消耗的流量也要少些.通过css的媒体查询,可以控制在各分辨率内容的显示.要减少流量消耗,一些专业的网站都是为手机端另外做一个页面. 响应式的设计,可以从分辨率由大到小,也可以从分辨率由小到大开始设计.我们目前尝试的是先完成桌面端,

关于移动端适配的问题

1.使用rem 2.meta内容如下: <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=no"> <!-- 禁止ios设备将数字作为拨号连接,邮箱自动发送,点击地图跳转 --> <met

MFC中的GDI绘图&lt;转&gt;

一.关于GDI的基本概念 什么是GDI? Windows绘图的实质就是利用Windows提供的图形设备接口GDI(Graphics Device Interface)将图形绘制在显示器上. 在Windows操作系统中,动态链接库C:\WINDOWS\system32\gdi32.dll(GDI Client DLL)中定义了GDI函数,实现与设备无关的包括屏幕上输出像素.在打印机上输出硬拷贝以及绘制Windows用户界面功能.在Visual C++6.0中的头文件C:\Program Files

MFC中的GDI绘图(5)

坐标映射实例 (1)建立单文档MFC项目Draw:New->Projects->MFC AppWizard(EXE)->Single Document. (2)找到CMainFrame::PreCreateWindow函数,在其中设置默认窗口大小为400 pixel*300 pixel. BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return

响应式布局详细介绍

一.响应式布局 定宽布局的局限:屏幕越来越宽,而定宽的宽度是固定的,看定宽的网页不美观 屏幕也在一直往小变,定宽也不合适,看不到完整的网页内容 在这种情况之下,就出现了一种自适应布局,分别是早起的流动式布局(根据浮动,基本淘汰)和百分比宽度布局(还有一些应用). 百分比布局的局限:不够完美,没法得到一个很好的显示效果. 屏幕太大,撑满整个屏幕,不好,屏幕太小,画面太过拘谨也不好. 屏幕尺寸过于碎片化,我们到底要设计什么样的网页才能满足所有人呢?  可以采取一个网站有多个尺寸的适配,两套设计方案,

关于移动端适配

通常移动端的布局方式 1.rem布局,通过动态设置根目录下的font-size达到元素大小"自适应",通常和百分比布局一起使用 2.固定像素设固定视口宽度. 3.最费事的media query,根据设备视口宽度不同设置不同的样式,换句话说一个页面有多套样式.可以说是正宗的响应式布局. 常规的做法带来的苦恼 常规的这些做法总有一些缺陷是令人遗憾的: 1.rem和百分比布局,这种布局rem终归也是有极限的,当屏幕比较大时,页面元素就开始变得有那么一些不协调了. 2.设置固定的视口使用固定像