mozilla

Revision 54546 of Writing forward-compatible websites

  • Revision slug: Web_development/Writing_forward-compatible_websites
  • Revision title: Writing forward-compatible websites
  • Revision id: 54546
  • Created:
  • Creator: Bzbarsky
  • Is current revision? No
  • Comment 446 words added

Revision Content

This is a list of best practices for creating websites that do not break when browsers are updated.  It's not always possible to follow all of these, but following as many of them as possible as

Prefix all global variable access in event handler content attributes with window.

When an event handler content attribute (onclick, onmouseover, and so forth) is used on HTML element, all name lookup in the attribute first happens on the element itself, then on the element's form if the element is a form control, then on the document, and then on the window. For example, if you have this markup:

<div onclick="alert(ownerDocument)">Click me</div>

then clicking on the text will alert the ownerDocument of the div. This will happen even if there is a var ownerDocument declared in global scope.

What this means is that any time you access a global variable in an event handler content attribute, including calling any function declared globally, you can end up with a name collision if a specification adds a new DOM property to elements or documents. If that happens, then suddenly your function will stop being called. This has happened multiple times to various sites already during the evolution of HTML5.

To avoid this, fully qualify global variable access, like so:

<script>
  function localName() {
    alert('Function localName has been called');
  }
</script>
<div onclick="window.localName()">Clicking me should show an alert<div>

Note that removing "window." in the example above completely changes the behavior in this case.

Don't assume that sniffing a particular object or capability implies anything about the presence or absence of other objects, capabilities, or bugs

If you plan to use some feature, use object-detection to sniff for that exact feature, if possible.  As a simple example, don't assume that any browser in which "filter" in body.style tests true must be Microsoft Internet Explorer and have a window.event available in event handlers. Don't assume that browsers with support for a given DOM feature must also have some other, especially nonstandard, DOM feature. Or that they don't have support for some other feature (e.g. don't assume that a browser that supports onload on script elements will never support onreadystatechange on them). As browsers converge behavior, they will both add features and remove them. They will also fix bugs.  All three of these have happened in the past and will happen again.

Don't UA-sniff

This is really a particularly common instance of assuming that one feature (the presence of a particular substring in the UA string) implies something about the presence or absence of other features.

Avoid depending on cutting-edge nonstandard features

Even if the feature is prefixed, using it could be dangerous: as the specification evolves the browser's prefixed implementation can likewise change to track the specification. And once the feature is standardized, the prefixed version will likely be removed.

Avoid missing >

Passing a validator is one way to ensure this, but even if your website doesn't validate entirely you should make sure all your > characters are present. Missing those can lead to unexpected situations due to a following tag name being treated as an attribute on a previous tag. This can work for a bit, then break if a specification attaches a meaning to that attribute. Here's an example that works in browsers without HTML5 support but breaks in a browser supporting HTML5:

<form action="http://www.example.com">
  <input type="submit" value="Submit the form"
</form>

due to the missing > on the input tag.

Revision Source

<p>This is a list of best practices for creating websites that do not break when browsers are updated.  It's not always possible to follow all of these, but following as many of them as possible as</p>
<h2>Prefix all global variable access in event handler content attributes with <code>window.</code></h2>
<p>When an event handler content attribute (<code>onclick</code>, <code>onmouseover</code>, and so forth) is used on HTML element, all name lookup in the attribute first happens on the element itself, then on the element's form if the element is a form control, then on the document, and then on the window. For example, if you have this markup:</p>
<pre>&lt;div onclick="alert(ownerDocument)"&gt;Click me&lt;/div&gt;</pre>
<p>then clicking on the text will alert the <code>ownerDocument</code> of the <code>div</code>. This will happen even if there is a <code>var ownerDocument</code> declared in global scope.</p>
<p>What this means is that any time you access a global variable in an event handler content attribute, including calling any function declared globally, you can end up with a name collision if a specification adds a new DOM property to elements or documents. If that happens, then suddenly your function will stop being called. This has happened multiple times to various sites already during the evolution of HTML5.</p>
<p>To avoid this, fully qualify global variable access, like so:</p>
<pre>&lt;script&gt;
  function localName() {
    alert('Function localName has been called');
  }
&lt;/script&gt;
&lt;div onclick="window.localName()"&gt;Clicking me should show an alert&lt;div&gt;</pre>
<p>Note that removing "<code>window.</code>" in the example above completely changes the behavior in this case.</p>
<h2>Don't assume that sniffing a particular object or capability implies anything about the presence or absence of other objects, capabilities, or bugs</h2>
<p>If you plan to use some feature, use object-detection to sniff for that exact feature, if possible.  As a simple example, don't assume that any browser in which <code>"filter" in body.style</code> tests true must be Microsoft Internet Explorer and have a <code>window.event</code> available in event handlers. Don't assume that browsers with support for a given DOM feature must also have some other, especially nonstandard, DOM feature. Or that they don't have support for some other feature (e.g. don't assume that a browser that supports <code>onload</code> on script elements will never support <code>onreadystatechange</code> on them). As browsers converge behavior, they will both add features and remove them. They will also fix bugs.  All three of these have happened in the past and will happen again.</p>
<h2>Don't UA-sniff</h2>
<p>This is really a particularly common instance of assuming that one feature (the presence of a particular substring in the UA string) implies something about the presence or absence of other features.</p>
<h2>Avoid depending on cutting-edge nonstandard features</h2>
<p>Even if the feature is prefixed, using it could be dangerous: as the specification evolves the browser's prefixed implementation can likewise change to track the specification. And once the feature is standardized, the prefixed version will likely be removed.</p>
<h2>Avoid missing <code>&gt;</code></h2>
<p>Passing a validator is one way to ensure this, but even if your website doesn't validate entirely you should make sure all your <code>&gt;</code> characters are present. Missing those can lead to unexpected situations due to a following tag name being treated as an attribute on a previous tag. This can work for a bit, then break if a specification attaches a meaning to that attribute. Here's an example that works in browsers without HTML5 support but breaks in a browser supporting HTML5:</p>
<pre>&lt;form action="http://www.example.com"&gt;
  &lt;input type="submit" value="Submit the form"
&lt;/form&gt;
</pre>
<p>due to the missing <code>&gt;</code> on the <code>input</code> tag.</p>
Revert to this revision