0
팔로우
1 팔로워

A tale of two viewports — part two

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 and -Height contain the layout viewport’s dimensions.

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

Measuring the visual viewport

As to the visual viewport, it is measured by window.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 guess window.innerWidth/Height is a standard, albeit a badly supported one.

The screen

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

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

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

Media queries

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 the device-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 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

Finally, let’s discuss the <meta name="viewport" content="widdth=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.

편집 게시물 신고 종료 삭제

질문 2013-08-27 22:47:04 +0900

director의 그라바타 이미지

수정 2013-08-28 00:17:53 +0900

0

A tale of two viewports — part two

이 미니 튜토리얼에서, viewport 와 <html> 그리고 window 와 screen 의 넓이에 대해서 논할 것이다.

이번 문서에서는, 모바일 브라우저에 대해서 얘기할 것이다. 모바일 환경이 처음이라면, desktop 브라우저에 관해 다룬 part one 을 먼저 보기 바란다.

The problem of mobile browsers

모바일 브라우저를 데스크탑 브라우저와 비교하면, 가장 확연히 차이나는 것은 둘의 사이즈다. 모바일 브라우저는 데스크탑을 고려하고 만든 웹사이트를, 데스크탑 브라우저 보다 훨씬 조금 보여준다: zoom out 해서 텍스트가 읽어볼 수 없을 정도로 작게 보이게 하던가, 전체 페이지의 특정 영역만을 보여준다.

모바일 화면은 데스크탑 화면보다 훨씬 작다; 최대 400px 을 생각하면된다. 그리고 어쩔땐 이보다 많이 작을 때도 있다. (어떤 전화기는 더 넓은 화면을 갖고 있다고 _주장하기도_ 하지만, 거짓말이다 - 또는 쓸데 없는 정보이다.)

iPad 나 HP webOS 기반의 tablet 기기들이 데스크탑과 모바일 사이의 사이즈를 가질 전망이다.(역주: 꽤나 오래전에 쓰여진 글인듯) 하지만, 그들이 근원적인 문제를 해결하는 것은 아니다. 웹 사이트는 모바일 (전화기) 기기에서 동작해야 한다, 우리는 웹사이트들이 작은 화면에서 잘 보여지도록 만들어야 한다.

가장 중요한 문제는 CSS, 특히 viewport 의 크기에 관한 것이다. 데스크탑 모델을 그대로 카피하여 사용하면, CSS 즉 페이지의 스타일은 엉망이 될 것이다.

width: 10% 의 sidebar 예제를 다시 사용해보자. 모바일 브라우저가 데스크탑 브라우저와 동일하게 동작한다면, 이 sidebar 의 넓이는 최대 40px 이 될 것이다. 이것은 너무 작다. 반응형 layout 이 엄청나게 축소되어 보일 것이다.

이 문제를 해결하는 한 방법은 모바일 브라우저를 위해 따로 웹사이트를 만드는 것이다. "정말 이렇게 해야하나" 근원적인 물음을 떠나서, 현실적으로, 모바일 기기만을 위해 따로 사이트를 만들 정도로 해박한 웹사이트 주인은 많이 없다.

모바일 브라우저 개발사는 고객들에게 최고의 환경을 제공하고 싶어한다. 현재 그것은 "데스크탑과 최대한 비슷하게" 라는 뜻이다. 그래서 몇가지 트릭들이 적용되었다.

The two viewports

모바일에서 viewport 는 CSS layout 을 보여주기에 너무 작다. 따라서 가장 먼저 떠올릴 수 있는 해결책은 viewport 를 넓게 만드는 것이다. 그래서 visual viewport 와 layout viewport 두가지가 공존하게 된다.

George Cummins 가 StackOverflow 글 에 기본 개념을 잘 설명해 놓았다.

layout viewport 는 사이즈나 모양이 변경되지 않는 큰 이미지라고 생각하면 쉽다. 그리고 조그만 창을 통해 이 큰 이미지를 본다고 생각해 보라. 이 창 주위는 가려져 있고, 당신이 볼 수 있는 것은 창에 보이는 큰 이미지의 일부분 뿐이다. 당신이 창을 통해 보는 영역이 visual viewport 이다. 창을들고 뒤로 물러서서 (zoom out) 큰 이미지를 한눈에 볼 수도 있고, 창을 들고 앞으로 전진해서 (zoom in) 작은 부분만을 볼 수도 있다. 창의 방향을 바꿀 수도 있지만, 큰 이미지 (layout viewport) 의 크기나 모양은 절대 변하지 않는다.

Chris 의 설명 도 참조하라.

visual viewport 는 전체 페이지에서 현재 화면에 보이는 영역이다. 사용자는 스크롤해서 페이지의 어떤 영역을 볼지 변경할 수 있고, zoom 해서 visual viewport 의 사이즈를 변경할 수도 있다.

하지만, CSS layout, 특히 % 넓이들은 layout viewport 를 기준으로 계산된다. 그리고 이 layout viewport 는 visual viewport 보다 훨씬 크다.

처음에 <html> 은 layout viewport 의 넓이를 갖는다. 그리고 전화기의 화면보다 훨씬 화면이 큰 것처럼 CSS 가 인식하게 된다. 이렇게 하면 모바일의 레이아웃이 데스크탑의 레이아웃과 동일하게 보이게 된다.

layout viewport 가 얼마나 넓은가? 브라우저마다 다르다. Safari iPhone 은 980px, Opera 는 850px, Android WebKit 은 800px, IE 는 974px 을 사용한다.

몇몇 브라우저들은 특이 사항들이 있다:

  • Symbian WebKit 은 layout viewport 와 visual viewport 와 동일하게 만드려고 한다. % 넓이를 가진 요소들이 이상하게 동작할 수 있다. 페이지의 크기가 커서 visual viewport 안에 들어갈 수 없으면 브라우저는 layout viewport 를 850px 까지 늘린다.
  • Samsung WebKit (on bada) 는 layout viewport 를 가장 큰 요소의 넓이만큼 넓게 만든다.
  • BlackBerry 은 layout viewport 와 visual viewport 가 100% zoom 상태에서 동일하다. 그리고 이것은 변하지 않는다. (역주: 잘 모르겠음)

Zooming

두가지의 viewport 는 CSS pixel 로 길이가 측정된다. 하지만 visual viewport 의 크기가 zoom 에 따라 변하는 반면 (zoom in 하면, 적은 수의 CSS pixel 이 스크린에 보여진다), layout viewport 의 크기는 변하지 않는다. (만약 크기가 변한다면, % 로 된 넓이들도 계속 사이즈가 변하는 것을 볼것이다.)

Understanding the layout viewport

layout viewport 의 크기를 이해하려면, 페이지가 완전히 zoom out 되었을 때 어떤일이 일어나는지 살펴보아야 한다. 많은 모바일 브라우저들은 페이지들을 완전히 zoom out 된 상태로 보여준다.

요점은: 브라우저들은 layout viewport 의 사이즈를, 완전히 zoom-out 한 상태에서 layout viewport 가 화면을 가득 채우도록 설정하였다. (즉 zoom out 상태에서 layout viewport 와 visual viewport 가 동일하게)

따라서 layout viewport 의 넓이와 높이는, 완전히 zoom out 상태에서 화면에 나타낼 수 있는 크기이다. 사용자가 zoom in 하더라도 이 크기는 변경되지 않는다.

layout viewport 의 넓이는 항상 동일하다. 폰을 회전하면, visual viewport 는 변한다. 하지만 브라우저는 적당히 zoom in 하여, layout viewport 의 넓이가 visual viewport 의 넓이와 동일하도록 설정한다.

따라서 폰을 회전하면, layout viewport 의 높이는 변하게 되고, portrait mode 에서 보다 높이가 작아지게 된다. 하지만 웹 개발자들은 height 에 대해서는 별로 신경쓸일이 없다. width 만 알면 된다.

Measuring the layout viewport

우리는 두개의 viewport 를 가지고 있고, 이 두개의 크기를 알고 싶다. Browser 전쟁으로 인해 두개의 속성이 있다는 것은 정말 다행이다.

document.documentElement.clientWidth 은 layout viewport 의 크기를 알려준다.

폰의 방향 (가로/세로) 에 따라 높이가 변하지만, 넓이는 변하지 않는다.

Measuring the visual viewport

window.innerWidth/Height 는 visual viewport 의 크기를 알려준다. 당연히, 이 크기는 zoom 상태에 따라 변하게 된다. screen 에 보여지는 CSS pixel 의 갯수가 달라지기 때문이다.

불행히도, 이 부분에 대해서 모든 브라우저가 동일하게 동작하지는 않는다: 많은 브라우저들이 visual viewport 의 크기를 얻어올 수 있는 방법들을 지원하지 않고 있다. 하지만 이 크기를 다른 속성에 저장하는 경우를 본적은 없다. 따라서 window.innerWidth/Height 이 표준이기는 한데, 아직 잘 지원되지 않는 표준이라 할 수 있겠다.

The screen

데스크탑에서와 마찬가지로 screen.width/heigh 는 화면의 크기를 device pixel 단위로 알려준다. 데스크탑 환경에서와 마찬가지로, 웹 개발자로서 이 정보를 사용할 일은 별로 없다. 궁금한 것은 화면의 물리적 크기가 아니라, CSS pixel 이 현재 몇개나 화면에 보여질 수 있느냐 이다.

The zoom level

zoom level 을 알려주는 변수는 없다. 하지만 screen.widthwindow.innerWidth 로 나누어서 알 수 있다. 물론 이 두 값을 브라우저에서 정확히 계산한다는 가정하에 말이다.

다행이도, zoom level 은 중요하지 않다. 알아야 할 것은 "얼마나 많은 CSS pixel 이 화면에 보여지느냐" 이다. 그리고 이 정보를 window.innerWidth 를 이용하여 얻을 수 있다. - 브라우저에서 제대로 계산한다면 말이다.

Scrolling offset

layout viewport 기준으로 현재의 visual viewport 가 어디에 위치해 있는지 알아야 할 때가 있다. 이 값은 scrolling offset 이라고 부르고, 데스크탑에서와 마찬가지로 window.page.X/YOffset 으로 얻어올 수 있다.

<html> element

데스크탑에서와 마찬가지로 document.documentElement.offsetWidth/Height<html> 의 CSS pixel 크기를 얻어올 수 있다.

Media queries

Media query 는 데스크탑과 동일하게 동작한다. width/height 은 layout viewport 를 사용하고 CSS pixel 단위이다. device-width/height 는 device screen 을 이용하고, device pixel 단위이다.

즉, width/heightdocument. documentElement. clientWidth/Height 값을 이용하고, device-width/heightscreen.width/height 값을 이용한다. (모든 브라우저에서 이렇게 동작한다. 값들이 틀릴때가 있지만 말이다.)

자 그럼, 웹 개발자에게 중요한 크기는 둘중에 어떤 것인가? 나도 잘 모르겠다.

처음에는 device-width 가 가장 중요하다고 생각했다. 왜냐하면 이 정보를 다음처럼 사용할 수 있기 때문이다. 즉, 기기의 크기에 따라 layout 의 크기를 변경하는 방법을 쓸 수 있다. 하지만 <meta viewport> 를 이용해도 같은 효과를 얻을 수 있다. 반드시 device-width media query 를 이용해야 하는 것은 아니다.

그렇다면 width 가 더 중요한 media query 인가? 이 값은 브라우저 개발사가 보가에, 특정 웹사이트가 이 기기에서 어느정도 넓이를 갖는게 좋다고 생각하는지, 유추해볼 수 있는 근거는 된다. 하지만 그것은 애매모호한 개념이다. width media query 는 그 이상의 정보를 제공하지는 않는다.

그래서 나는 아직 잘 모르겠다. 현재 내 생각은, media query 는 사용자가 desktop 을 사용중인지 tablet 을 사용중인지 또는 mobile 기기를 사용중인지 알아내는데 중요한 역할을 한다고 생각한다. 하지만 많은 tablet 과 mobile 기기들을 구분하는데는 별 쓸모가 없다고 생각한다.

글쎄다.

Event coordinates

Event 좌표는 데스크탑과 거의 비슷하다. 불행히도, 테스트한 12 개의 브라우저 중에, Symbian Webkit 과 Iris 만이 세개의 값들을 정확히 얻어왔다. 다른 브라우저들은 크고 작은 문제들이 있었다.

pageX/Y 는 페이지 기준으로, CSS pixel 단위의 위치다. 데스크탑에서와 마찬가지로, 세가지 정보중에 이 값이 제일중요하다.

clientX/Y 는 visual viewport 기준의 좌표값이고 CSS pixel 단위이다. 무슨 뜻인지 이해는 되지만, 어디에 사용할 수 있는지는 모르겠다.

screenX/Y 는 스크린 기준의 좌표값이고 device pixel 단위이다. clientX/Y 와 비슷하지만 device pixel 은 무용지물이다. 데스크탑에서와 마찬가지로 screenX/Y 에 대해서는 신경쓸 필요가 없다.

Meta viewport

마지막으로 <meta name="viewport" content="widdth=320"> 에 대해서 얘기해 보자. Apple 이 처음에 도입했고 다른 많은 브라우저에서 차용했다. layout viewport 의 크기를 변경하기 위해 도입되었다. 왜 이 기능이 필요한지, 한발 물러서 보자.

간단한 페이지를 만들었는데, 요소들에 width 값을 주지 않았다고 해보자. 이들은 layout viewport 의 100% 넓이를 사용하도록 늘어날 것이다. 대부분의 브라우저들은 layout viewport 전체를 화면에 보여주기 위해 zoom out 하여 다음 처럼 보여진다:

사용자는 즉시 zoom in 기능을 사용할 것이다. 그런데 브라우저는 요소들의 넓이를 변경하지 않아, 텍스트를 읽기가 힘들어진다.

(Android WebKit 은 예외이다. Android WebKit 은 text 를 포함하는 요소의 사이즈를 줄여서 화면 크기에 맞게 변경한다. 이 기능은 아주 좋다고 생각한다, 다른 브라우저들도 따라했으면 좋겠다. 다음에 더 자세히 설명하겠다.)

html {width: 320px} 라고 설정할 수 있다. <html> 이 작아지고, 그 안의 다른 모든 요소들도 같이 작아진다. html 의 넓이가 320px 이면, zoom in 상태에서는 잘 보일 것이다. 하지만 처음에는 (역주: 처음에는 브라우저는 최대한 zoom out 해서 페이지를 보여준다), 페이지가 zoom out 되어 있어서, 화면에 별로 내용이 없어 보일 것이다.

Apple 이 이 문제를 해결하기 위해서 meta viewport 를 만들었다. <meta name="viewport" content="width=320"> 을 설정하면, layout viewport 의 넓이를 320px 로 변경한다. 이렇게 하면 page 를 처음 열었을 때도, 이상하지 않게 보인다.

layout viewport 의 넓이를 원하는 값으로 정할 수 있다. device-width 로 할 수도 있다. 이렇게 하면 screen.width (device pixel 단위로) 를 기준으로 layout viewport 의 크기를 변경한다.

주의할 것이 있다. screen.width 는 말이 안될 때가 있다. 예를 들면, Nexus One 은 width 가 480px 이다. 하지만 Google 엔지니어들은 device-width 를 사용할 때 480px layout viewport 를 주는 것이 너무 많다고 생각했다. 2/3 로 줄여서 device-width 는 320px 넓이를 준다. iPhone 과 동일한 값이다.

새 iPhone (역주: iPhone 4 를 말하는듯) 더 많은 pixel 을 사용할 것이라고 한다. (더 화면이 크다는 뜻은 아니다!) Apple 이 안드로이드를 따라해도 놀라지 않을 것이다. 아마도 device-width 는 그냥 320px 을 의미하게 될지도 모른다.

편집 게시물 신고 삭제 publish 링크

게시 2013-08-28 00:17:17 +0900

director의 그라바타 이미지

통계

질문: 2013-08-27 22:47:04 +0900

읽음: 827 시간

마지막 업데이트: Aug 27 '13