Viewport experiments

Experiments:

A pure CSS experiment to determine default behaviour.

The same, but in quirks mode.

The same, but I added the :root selector.

Click on elements. What is the target?

Append an element.

Remove an element.

Try interesting properties and see what they mean (or don't mean).

No background for the html element.

Set the heights of some crucial elements.

overflow.

On this page I discuss some experiments to determine the relation between the viewport and the document inside it, both from a CSS and from a JavaScript point of view.

These experiments are hardly complete, and I'm not entirely sure yet how the results should be interpreted. In deference to Explorer 6 all experiments but one are in Strict Mode.

The pure example

We take the following simple HTML:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
<html>
<head>
<title>The pure effect</title>
</head>

<body>
The BODY
<div id="testdiv">
	The DIV
</div>
</body>
</html>

and the following CSS:

html,body,div {
	position: relative;
	margin: 20px;
	padding: 0;
	font: 13px verdana,helvetica,arial,sans-serif;
	border: 1px solid #000000;
}

html {
	background-color: #732264;  
}

body {
	background-color: #B0BDEC;  
}

div {
	background-color: #DEE7F7;  
}

See the pure example in Strict mode and the Quirks mode example. Only Explorer 6 Windows makes any difference between Quirks and Strict mode.

The browsers render it as follows. Opera, Explorer Mac and Safari agree with each other.

Others Mozilla IE Win Strict IE Win Quirks

:root

The next test adds the :root selector to the style sheet.

Note that I defined the :root styles before the normal ones:

<style>
<!--
:root {
	border: 1px solid #000000;
	background-color: #cccccc;
}
-->
</style>
<link rel="stylesheet" href="doctests.css">

Mozilla, Explorer Mac and Safari support :root: in these browsers :root seems to denote the same element as html. Not unexpected, and certainly understandable.

The :root style (gray background) overrules the html style (purple background) because :root is a pseudo-class, which, like a real class, overrules a mere tag name.

:root = html

I'm curious what Opera will do with this pseudo-class. As we'll see later on, it probably inserts another block between html and the viewport. Will this anonymous block become the :root?

Click on it

The next experiment confirms this theory. I added an onclick event handler to the document. Clicking anywhere in the page reveals (should reveal) the target of the click.

Personally I feel that a really consistent implementation would give the document as the target of a click outside the visual border of the html. All browsers disagree with me, though.

Click on Explorer 6 Windows Explorer 5.2 Mac Mozilla 1.6 Safari 1.2 Opera 7.50
div
div div div div div
body
body body body body body
html
html No reaction html body html
Outside html
Not possible No reaction html body html

The html element's visual border does not denote its true border. The area outside it is also part of this element. Therefore, despite appearances, the html element is not a normal element like any other.
Presentation and behaviour match perfectly only in Explorer Windows.

DOM tree

Let's continue with JavaScript. Is the html element a normal DOM object, to which you can append children? The next experiment takes a closer look.

I try to append a span to the div, the body, the html element and the document. You should see a black 50x50 block in the upper left corner of the element. Then I alert the nodeName of the last child of this element. If my append action succeeds it should be SPAN.

Note: Explorer Mac and Opera may have redrawing problems. Hide the window and take it forward again to see changes in the layout, if any.

Append to Explorer 6 Windows Explorer 5.2 Mac Mozilla 1.6 Safari 1.2 Opera 7.50
div
Yes Yes Yes Doesn't show Yes
body
Yes Yes Yes Doesn't show Yes
documentElement
Doesn't show Yes Yes Error Yes
document
Doesn't show Action failed Error Error Error

On the whole I side with Mozilla and Opera here. Although custom dictates that an html element should only contain a head and a body element, the DOM shouldn't be limited by HTML custom, since it is meant for working with any XML document. Appending children to the documentElement should work.

Appending children to the document element is not allowed, though.

Browsers see the document.documentElement as a normal element node to which you can append children. The document can have only one child, though: document.documentElement.

Removing elements

Let's take it one step further and try to remove document.body and even document.documentElement from the DOM tree.

Warning: May crash Explorer 5.2 Mac and Safari 1.2. See below.

Remove Explorer 6 Windows Explorer 5.2 Mac Mozilla 1.6 Safari 1.2 Opera 7.50
div
Yes Unstable Yes Crash Yes
body
Yes Unstable Yes Crash Buggy
documentElement
Yes Nothing happens Keyboard control lost Yes Error

Only Explorer Windows does as it's told without raising a fuss.

Removing document.body and document.documentElement shows fascinating browser behaviour that is impossible to correlate with other findings.

Properties

In the next experiment you can select a property of an element. The script shows a bar that is as wide or as high as the tested property dictates, and sets it in the upper left corner of the element. So you can check whether the value of document.body.offsetHeight matches the height of the body.

These experiments are the only ones to have a practical value, because we need this information for cross browser scripts to read out the window height, the document height and the scrolling offset.

See the browser compatibility page for the results.

Safari note: it is the only browser to give the document dimensions. All other browsers return undefined.

No background

In the next experiment I declared

html {background: transparent;}

In all browsers the html element reverse-inherits the background colour of the body element. Not surprising, but the test had to be performed.

overflow

As we all know all browsers generate a scrollbar when the HTML page is longer (or wider) than the viewport. In CSS scrollbars are ruled by the overflow declaration. The next experiment tries to find out whether the normal page scrollbar is also set by an overflow declaration, and, if so, on which element it is applied. It also tests basic support for overflow on the body and html elements.

You can set the overflow of html and body to default, visible, hidden or auto. default means: no overflow value given.

Safari turns out not to support overflow on these elements at all.

Explorer Mac has a bug: when you set overflow: hidden on the body this style remains in place after a reload. You can overrule it by resetting overflow: auto.

For the moment I describe five tests:

  1. Set body and html to overflow: auto.
  2. Set body and html to overflow: hidden.
  3. The last test tries to restore the default scrollbars without using the "No value" option. This should show which overflow values the browser uses as default (if any).

All "Desired result" screenshots are from Opera, which is by far the most consistent browser in this series of tests.

Test Explorer 6 Windows Explorer 5.2 Mac Mozilla 1.6 Safari 1.2 Opera 7.50
body {overflow: auto}
Generate a scrollbar for the body element only

Desired result
Almost No Yes Untestable Yes
Explorer Windows suddenly gives the div with position: relative a position: fixed.
Explorer Mac doesn't react at all: it shows the scrollbar for the entire page.
html {overflow: auto}
Generate a scrollbar for the html element only

Desired result
Almost Hides body Buggy Untestable Yes
Explorer Windows gives the html element a slightly greater width than before, probably because the space for the scrollbar is removed. This leads to a horizontal scrollbar.

Mozilla and Opera both move the scrollbar to just inside the border of the html element. However, Mozilla never restores the scrollbar to its original position.

Mozilla removes the background colour of the body.
body {overflow: hidden}
Hide content at body border.

Desired result
Yes Not quite Yes Untestable Yes
Explorer Mac removes the scrollbar of the entire page.
html {overflow: hidden}
Hide content at html border.

Desired result
Yes Hides body Buggy Untestable Yes
Explorer sees the entire viewport as the html element, so although it doesn't cut off the content at the bottom border of the html (which isn't visible in any case), it performs this test correctly according to its own definitions.

Mozilla removes the background colour of the body.
Restore default
option "[no value]" not allowed!

Desired result
html:auto
body:visible
html:visible
body:auto
Untestable Untestable html:visible
body:visible
Setting both elements to overflow: visible seems to be the cross-browser way,

The test only works in Mozilla 1.6 if you haven't made any changes yet. However, this kind of defeats the purpose of the test.

Explorer Windows never quite restores the defaults.

Based on these tests, browsers define their initial containing block as follows:

Opera is the most consistent browser in this series of tests.

Set height

The last experiment allows you to set the heights of the documentElement, the body and the div to auto, 300px, 50% and 100%. I need expert help from a CSS guru to interpret the results, so I don't draw any conclusions yet. Try it for yourself and see what you think.

If you want to seriously delve into this subject, please write a page about the results of the experiment in several browsers and tell me when it's online. I'll link to you.

Conclusions

I cannot yet draw real conclusions; my experiments have hardly started yet. Nonetheless there seem to be some general rules:

  1. Despite appearances, all browsers treat html as a special element, not as just any block level element. It always spans the entire viewport, even though it may not seem to. Opera and Safari treat it as any block level element when it comes to CSS, but not in JavaScript.
  2. When Microsoft added Strict Mode to Explorer Windows, it apparently inserted a block level element between the body and the rest of the page. This new block level element became the body, and its parent (the old body) became the html element. It retained most of its properties and behaviour, though.
  3. Safari and Opera occasionally find it difficult to distinguish between body and html.