AutoHead – my first Browserscope user test
In the comments from my last blog post (appendChild vs insertBefore) someone asked which browsers do and don’t automatically create a HEAD element. This is important when you’re deciding how to dynamically add scripts to your web page. I used this question as the motivation for creating my first Browserscope user test. Here’s the story behind this new feature in Browserscope and the answer to the automatically create HEAD question. (You can run the AutoHead test to skip ahead and see the results.)
Level, Meta-level, Meta-meta-level
Level1: When Chrome was launched in 2008 I started a project called UA Profiler to analyze the performance characteristics of browsers. The key concept was to crowdsource gathering the data – publish the test framework and encourage the web community to run the tests on their browser of choice. There are numerous benefits to this approach:
- a wider variety of browsers are tested (more than I could possibly install in a test lab)
- results for new browsers happen immediately (often before the browser is officially released)
- tests are performed under real world conditions
Level 2: I teamed up with Lindsey Simon to take UA Profiler to the next level. The result was the launch of Browserscope. In addition to making this a functioning open source project, the framework was opened up to include multiple test categories. In addition to performance (renamed “Network“), other test categories were added: Security, Acid3, Selectors API, and Rich Text.
Level 3: A few weeks ago Lindsey took Browserscope to the next level with the addition of the User Tests feature. Now, anyone can add a test to Browserscope. In this early alpha version of the feature, users create one or more test pages on their own server, register the test with Browserscope, and embed a JavaScript snippet at the end of their test to send the results back to Browserscope for storing. The benefit for the test creator is that Browserscope stores all the data, parses the User-Agent strings for proper categorization, and provides a widget for viewing the results.
Even though Lindsey is careful to call this an alpha, it went very smoothly for me. Once I had my test page, it took less than 15 minutes to integrate with Browserscope and start gathering results. So let’s take a look at my test…
the test – AutoHead
In my appendChild vs insertBefore blog post I talk about why this code generates bugs:
document.getElementsByTagName('head')[0].appendChild(...)
The context was using this pattern in 3rd party code snippets – where you don’t have any control of the main page. It turns out that some web pages out in the wild wild web don’t use the HEAD tag. Luckily, most browsers automatically create a HEAD element if one isn’t specified in the page. Unfortunately, not all browsers do this.
In the comments on that blog post Andy asked, “What browsers are we talking about here?”
How can I possibly attempt to answer that question? It would require running a test on many different versions of many different browsers, including mobile devices. I’m not equipped with a setup to do that.
Then the light bulb lit up. I can do this with a Browserscope User Test!
Creating the test was easy. My HTML page doesn’t have a HEAD tag. I put a script at the bottom that checks if the page contains a head element:
bHead = document.getElementsByTagName('head').length;
I have to store the result in a specific variable that Browserscope looks for:
var _bTestResults = { 'autohead': bHead };
This data structure is slurped up by Browserscope via this snippet (as shown on the User Tests Howto page):
(function() { var _bTestKey = '<YOUR-TEST-ID-GOES-HERE>'; var _bScript = document.createElement('script'); _bScript.src = 'http://www.browserscope.org/user/beacon/' + _bTestKey; _bScript.setAttribute('async', 'true'); var scripts = document.getElementsByTagName('script'); var lastScript = scripts[scripts.length - 1]; lastScript.parentNode.insertBefore(_bScript, lastScript); })();
Voila! You’re done. Well, almost done. You still have to promote your test.
Promoting your test
With this small amount of work I’m now ready to ask the web community to help me gather results. For me personally, I accomplish this by writing this blog post asking for help:
Help me out by running the AutoHead test. Thanks!
You can view the Browserscope results here, so you can see results as they come in. So far iPhone and Safari 3.2 are the only browsers that don’t automatically create the HEAD element.
If you want to avoid bugs when dynamically adding scripts, you might want to use one of the more solid patterns mentioned in my appendChild vs insertBefore blog post. If you want to gather data on some browser test that interests you, read the Browserscope User Test Howto and go for it. If you have problems, contact the Browserscope mailing list. If you have success, contact me and I’ll tweet your test to drive more traffic to it. This is still in alpha, but I’m very excited about the possibilities. I can’t wait to see the kinds of tests you come up with.
Update: After just one day, thanks to all of you who ran the test, I’ve collected 400 measurements on 20 different browsers and 60 unique versions. The results show that the following browsers do NOT automatically create a HEAD element: Android 1.6, Chrome 5.0.307 (strange), iPhone 3.1.3, Nokia 90, Opera 8.50, Opera 9.27, and Safari 3.2.1. This adds up to over 1% of your users, so it’s important to keep this in mind when adding scripts dynamically.
I also had some comments I wanted to pass on about my Browserscope user test. In hindsight, I wish I had chosen a better “test_key” name for the _bTestResults object. I didn’t realize this would appear as the column header in my results table. Rather than “autohead” I would have done “Automatically Creates HEAD”. Also, rather than return 0 or 1, I wish I had returned “no” and “yes”. Finally, I wish there was a way to embed the results table widget besides using an iframe. I’ll file bugs requesting better documentation for these items.
Jean-Paul Horn | 12-May-10 at 4:20 pm | Permalink |
Did some tests and iPad seems to be recognized as Safari 4.0 (and passed the HEAD test)
Martijn | 13-May-10 at 4:53 am | Permalink |
European Nintendo DS Browser is seen as Opera 8.50 and doesn’t pass the test.
To make sure I wasn’t screwing up the statistics I ran the test in the Windows XP version of Opera 8.50 as well, didn’t pass so the test is still accurate.
Puts the total of browser having problems with this to 6.
Pedro Simonetti | 13-May-10 at 6:22 am | Permalink |
Hi Steve,
Thanks for yet another interesting and insightful post!
I had a problem with this “missing head” issue a while ago when working on the Firebug Lite compatibility with XML+XSL documents.
When using a XML+XSL document, Firefox 3.6 and Chrome 4 won’t create the missing head tag (if the generated html does not contain a doctype). Take a look at this test case:
http://fbug.googlecode.com/svn/lite/branches/firebug1.3/test/head/xsl/xml-xsl.xml
If you include a doctype, Chrome will properly create a head tag, but not Firefox. IE7 will create the missing tag in both cases.
So, it seems that this problem depends not only on the browser, but also on the type of document being used.
Tino Zijdel | 13-May-10 at 4:11 pm | Permalink |
Did you consider that maybe other factors may be in play, such as the difference between quirksmode (no or incomplete doctype) and standards compliant mode? And maybe ommitting the html and/or the body-tags may also be a factor, and let’s not forget IE’s base-issues.
Although your test does point to some browsers that don’t follow the HTML/DOM specifications correctly in your test (I’m mentioning HTML here since even though the testpage has an XHTML doctype it is still served as text/html) it doesn’t mean that it covers all possible scenarios where browsers may go wrong. See for some other interesting examples where browsers get things wrong this post from Ian Hixie: http://ln.hixie.ch/?start=1137740632&count=1
Steve Clay | 13-May-10 at 4:34 pm | Permalink |
@Tino: Yep. I can see quirks/doctypes and application/xhtml+xml having a big effect. And valid pages can lack BODY and HTML elements, too :).
Steve Souders | 13-May-10 at 4:37 pm | Permalink |
@Tino: You should create a Browserscope User Test that explores these issues! I’ll tweet it when you’re done.
Tino Zijdel | 14-May-10 at 4:02 pm | Permalink |
@Steve: I think I would have to use iframes in such test in order to be able to load different documents and gather results; I’m not sure if that would possibly expel some (mobile) browsers…
Steve Souders | 14-May-10 at 5:17 pm | Permalink |
@Tino: The Browserscope Network tests use an iframe and run on mobile. The code is all available to copy, but it’s not that hard to write from scratch, too.
Tino Zijdel | 14-May-10 at 5:47 pm | Permalink |
@Steve: ok, when iframes aren’t a restriction I’ll be able to cook up some additional tests :)
Lars Gunther | 15-May-10 at 2:22 am | Permalink |
Fennec 1.1 nightly, MicroB and Opera Mobile 10.50, all three running on my Nokia N900 (Maemo), pass the test. They might turn up unexpected UA-strings, so I thought that I’d mention it in this comment as well.
Andrew | 15-May-10 at 6:01 am | Permalink |
BrowserScope shows that I’m running Opera 10 but I’m using 10.53. It passes the test too.
Sergey Chernyshev | 16-May-10 at 2:38 pm | Permalink |
Great approach to tests. I wish more things were done in similar distributed way.
BTW, I get a JS debug popup in IE7 when going to the test page:
https://stevesouders.com/tests/autohead.html
It looks like it’s from Browserscope’s embed.
Tino Zijdel | 16-May-10 at 3:20 pm | Permalink |
Delivering on my promise, here’s a more extensive test: http://achelois.tweakers.net/~crisp/autohead/index.html
I made a total of 5 tests, by label these consist of:
Base: A quirksmode document starting with a BASE-element
Explicit: A standards-compliant document that does have an explicit HEAD-element (so in all browsers this should give a positive result)
Quirksmode: A quirksmode document that doesn’t have HTML, HEAD or BODY
Valid: A standards-compliant document but with HTML, HEAD and BODY omitted
XHTML: A standards-compliant document with an XHTML doctype and served as application/xhtml+xml that doesn’t have a HEAD-element
In IE-based browsers I do skip that last test because IE doesn’t have true XHTML support. It should be noted that I do expect most browsers to not implicitly create a HEAD-element in the DOM for this test because it is an XML-application and not SGML-based (or HTML5).
Also it seems impossible to report the results as anything other than numeric values; I tried ‘yes’, ‘no’ and ‘skipped’ but those would just not show up…
Jean-Paul Horn | 16-May-10 at 4:36 pm | Permalink |
@Tino/Crisp: Provided iPhone 3.1, Chrome 5/OS X and Safari 4/OS X. Only iPhone 3.1 doesn’t seem to support quirksmode.
Tino Zijdel | 16-May-10 at 4:59 pm | Permalink |
Here’s a link to the blogpost I wrote on this particular test: http://crisp.tweakblogs.net/blog/4198/heads-or-tails.html
Dan Beam | 23-May-11 at 10:04 am | Permalink |
Hi Steve,
I think you have a typo in your code. I think:
document.getElementsByTagName[‘head’][0].appendChild(…)
should be
document.getElementsByTagName(‘head’)[0].appendChild(…)
Steve Souders | 23-May-11 at 10:19 am | Permalink |
@Dan: Fixed – thanks!
Nicholas Shanks | 02-Sep-12 at 2:55 am | Permalink |
@Tino: As the goal of XHTML is to allow XML processors (that know nothing about HTML) to generate the same node tree as a web browser would, and that no tags are optional in XHTML, I think it is correct that a web browser does not generate DOM elements for tags that are not present, as doing so would break XPath compatability.