Web developers are quite annoyed that
position: fixed doesn’t work on mobile browsers, but mobile browser vendors cannot afford to support it. This dilemma is unsolvable by the means we presently have at our disposal.
To offer a way out, I’m proposing to create a new
position: device-fixed declaration better suited to the mobile scenario with its tiny screen and its zoom. The zoom aspect, in particular, is completely ignored by the spec, and so far mobile browsers haven’t found a good solution, either.
With a new value, fixed positioning could be split into a desktop and a mobile variant, and browsers could decide which one to support. That would allow web developers to devise separate solutions for desktop and mobile.
The fundamental problem is that the mobile and desktop use cases of the fixed element are radically different.
On the one hand, the fixed element’s content must be terse and to-the-point on the tiny mobile screen, while it can be much more sprawling on a desktop screen.
On the other hand, the fixed element’s content is likely to be more important on mobile than on desktop. If you occupy a sizable chunk of a small screen, you’d better occupy it with something important. Conversely, because there’s so much space available, desktop fixed elements are usually filled with lots of little extras (that, quite frankly, are rarely interesting).
Until now web developers have opted for the desktop approach. But fixed elements designed for the desktop are far too large for the tiny mobile screen, and some information will bleed out of the element. Thus the user will not be able to see, much less read, the information. Scrolling doesn’t help: the element is fixed, and will stubbornly stay in its position.
If mobile browsers were to implement
position: fixed exactly as the desktop browsers do, many sites with fixed elements would become unusable on mobile. Therefore most mobile browser vendors have ignored a large part of the spec. From a practical perspective they’re right, even though
position: fixed as specified could work on mobile.
The CSS 2.1 spec defines
position: fixed as follows:
Fixed positioning is a subcategory of absolute positioning. The only difference is that for a fixed positioned box, the containing block is established by the viewport. For continuous media, fixed boxes do not move when the document is scrolled. In this respect, they are similar to fixed background images.
Spec and mobile reality are diverging at a brisk pace. The “fixed boxes do not move” requirement has been ignored by most mobile browsers. On the other hand, the specification ignores zooming.
And what is the viewport? On desktop browsers it’s the browser window, and as a result fixed positioned elements are placed relative to the window, and don’t move when the document is scrolled. We all know that, and we want it on mobile.
Mobile browsers, however, have two viewports: the visual one and the layout one. Relative to which viewport do browsers position the fixed element?
Nobody will be particularly surprised to hear that this depends on the browser. The vast majority has opted for the layout viewport, with only Nokia WebKit dissenting. You can test your browser at this test page. See also the inevitable compatibility table.
The difference between the two positioning schemes can be visualised best if we give the fixed element a
bottom: 0. Thus it is aligned at the bottom of whatever box it is positioned relative to.
This is an element fixed relative to the visual viewport:
The fixed element is positione at the bottom of the page and stays there when the user scrolls, just as on the desktop.
Although it’s clear that this is the most accurate porting of the desktop effect to mobile, of all the myriad mobile browsers only Nokia WebKit implements it — and then not even in all circumstances. As we already discussed, fixing elements designed for the desktop relative to the tiny visual viewport is just not very useful on mobile.
What happens when the user zooms? The Nokia N8 removes the fixed element entirely; and we can all agree that’s not the best possible behaviour. But what should happen? I have no clue. Browsers can’t handle the situation, and the spec is silent.
Other browsers, notably Safari on iOS, decided to position the fixed element relative to the layout viewport, and scroll them with the document. Thus they ignore an important part of the specification.
(Essentially this makes
position: fixed equal to
position: absolute: absolute elements are positioned relative to the layout viewport if they don’t have an ancestor with
position: relative. Open the test page in a desktop browser to see what I mean.)
The fixed element with
bottom: 0 is placed at the bottom of the layout viewport, and scrolls with the page. Thus its fixed nature is lost, but it remains fully readable because it scrolls and zooms with the rest of the page.
This solution is not perfect, either. The fixed element may cover crucial page content. Designers make sure that absolute elements don’t cover anything, but they will likely forget to do the same for fixed elements because they assume the user can always scroll a bit. If a fixed element scrolls with the page, though, the information underneath it will never be uncovered.
Still other browsers, notably Opera Mobile and BlackBerry WebKit, try to combine the two approaches. They initially position the fixed element relative to the layout viewport, but when the user scrolls the element “hops” to a new position at the bottom of the current visual viewport. It remains at this new position until the user scrolls again, after which they “hop” again.
The problem is that the “hop” only takes place about half a second after the user has stopped scrolling. This makes the effect a bit weird: stuff appears to change without any user command. (The command was of course the scrolling, but that’s not at all apparent to the average user) Still, this avoids any problems due to the fixed element covering vital information.
And what about zoom? Opera Mobile takes the most sensible position: while the user is zoomed in the position of the fixed element does not change at all. This allows the user to inspect it. It only starts “hopping” again when the user has zoomed out.
In contrast, BlackBerry WebKit tries something complicated to keep the element in view, but the effect is buggy. Sometimes the element just disappears, and at other times the positioning is off by a few pixels. And of course the content of the fixed layer grows so large that it bleeds out of the element and becomes unreadable.
Android is fragmented. My Nexus One with 2.2 uses the plain layout viewport solution, but my HTC Legend with 2.1 uses the hopping variation (buggily). I’m not sure if this is a 2.2 vs. 2.1 or a Google vs. HTC difference.
Samsung Dolfin, Android WebKit, Nokia WebKit, and possibly other browsers, change the handling of
position: fixed when a
<meta viewport> is added to the page. To preserve my sanity I did not research this aspect in depth, but it should be noted that my Nexus One implements true fixed positioning if you set
<meta name="viewport" content="width=device-width, user-scalable=no" />; in other words, if you take away a goodly part of the user interaction.
Which of these solutions is the best? Having tested them extensively during several periods of research and in several test pages, I tend to think that none of them are particularly good.
Instead, I believe it’s time for
position: device-fixed. It would be the fifth value for the
position declaration, and the fact that it is a new value would solve the biggest problem at one stroke.
If mobile browsers would support
device-fixed and desktop browsers would not, web developers could afford to create fixed solutions specifically for the one or the other.
position: device-fixed works like true fixed positioning in that the element is fixed relative to the visual viewport, and stays there no matter how the user scrolls or zooms.
In addition, CSS units used for the device-fixed element and its descendants are relative not to the CSS pixels of the layout viewport, but to the physical device pixels (or, if the device implements them, logical pixels). See this blog post for the three kinds of pixels.
Essentially this makes device-fixed elements unzoomable. That’s actually desirable. Zooming is pointless in this context because the content will bleed out of the device-fixed element and become unreadable. So why not suppress it altogether?
This no-zooming requirement is crucial. Without it,
device-fixed elements are no different from
fixed elements, and implementing the new value would be pointless.
This demo works only in Safari and BlackBerry WebKit, because only those browsers expose the dimensions of both the visual and the layout viewport, allowing me to calculate the zoom factor.
The idea is that desktop browsers do not support
device-fixed, while mobile browsers stop supporting
fixed. Thus web developers can create two effects, the
fixed and the
device-fixed, and be reasonably certain that the one works only on desktop, the other only on mobile.
What would happen with
device-fixed elements on the desktop, or with
fixed elements on mobile? They won’t be fixed, obviously, but will they be hidden entirely (
display: none), or will they remain visible as any block-level element at their natural position on the page?
The old BlackBerry browser (4.6) already does something like that: it completely hides
What about tablets? Will they support
device-fixed, or both? Right now I don’t know. Once both values are operational the tablets’ browser engineers will take an informed decision. The fact that there are two values ensures maximum flexibility.
The fact that
device-fixed addresses a use case that could be handled by the current specification of
fixed speaks against it, although the spec doesn’t address zooming at all and thus remains incomplete.
Still, web developers need true mobile fixed positioning — in fact, there’s considerable outcry over this very subject. At the same time, mobile browser vendors cannot afford to implement true
device-fixed offers a way out of this dilemma. It’s a practical solution first and foremost; I appreciate that from a theoretical point of view it’s less defensible.
So I’d like to ask the CSS wizards from W3C and the web development community, as well as the mobile browser vendors, to consider
Not that it will be easy to implement. I already mentioned a few details that will have to be worked out, and no doubt more will be found. I also wonder if making CSS units relative to something other than CSS pixels is simple.
One thing is certain, though: without
position: device-fixed or a similar solution there will be no true fixed positioning on mobile.
Upcoming speaking gigs:
Comments are closed.