It's getting busy on the JavaScript front. For a good overview of what's happening right now you should read the three articles I mention below. They discuss different aspects of the change JavaScript is going through at the moment. As an extra I've thrown in a little trick I've been using quite a lot lately.
First of all Brendan Eich, inventor of JavaScript, speaks up. In his JavaScript 1, 2, and in between he discusses possible directions JavaScript could evolve in:
JS is not going away, so it ought to evolve. [...] You could argue that JS's stagnation, along with HTML's, was beneficial for the "Web 1.0" build-out of the last decade. But given all the ferment on the web today, [...] there should be a JS2, and even a JS1.6 on the way toward JS2.
Eich discusses a few Core features of JavaScript that should change. I'm the first to admit I don't understand Core JavaScript enough to judge these proposals at their worth. Therefore I gladly leave these changes in Eich's capable hands.
Three weeks ago Bobby van der Sluis published Unobtrusive dynamic select boxes, a simple way of creating dynamic select boxes without excluding noscript browsers — but remember: catering for noscript browsers does not make your site accessible in and of itself. Nonetheless Van der Sluis's script is an excellent example of the direction JavaScript as used by us web developers should be traveling in.
If you're not quite sure what unobtrusive scripting means, read this article carefully. Van der Sluis starts with the structural XHTML layer and then explains how to add an unobtrusive behaviour to this layer. Since he first made sure his structure is correct, usable and accessible, the removal of the behaviour only results in the loss of a bit of usability, but leaves the page otherwise intact.
Chris Heilmann put together an interesting list of bad practices in Six JavaScript features we do not need any longer. The list is:
document.write
(actually, there is one situation in which it remains useful; see below)<noscript>
javascript:
pseudo-protocolonclick="void(0)"
(I must admit I never saw this one in the wild)document.layers
, document.all
, and navigator.userAgent
I completely agree with him: we should get rid of these bad practices as fast as possible. There's one exception, though.
document.write
I have rediscovered document.write
as a powerful tool in one specific situation: when you
want to include styles that should only work if JavaScript is enabled.
style.display = 'none'
.
Thus the blocks are closed by JavaScript; if there's no JavaScript they remain open.onload
. If the user first has to download huge lots of graphics, the blocks
may 'suddenly' close while the user thought the page was already complete. Bad usability.document.write
an extra <link>
tag into the page directly
(ie. outside any function), which links to avanced styles that should only be used when JavaScript is enabled.
This has three advantages:
document.write
ing itself makes sure these styles are only loaded when there is JavaScript support.<link>
as soon as possible, and don't wait for onload
,
the styles are there when the browser starts parsing the XHTML. No more ugly flickers or movement: all
XHTML elements immediately get the advanced styles they need. The blocks are never open, so they
don't need to close suddenly.Example script; note that the <link>
is written into the page as soon as possible, it
doesn't wait for onload
:
var W3CDOM = (document.getElementsByTagName && document.createElement); if (W3CDOM) document.write('<link rel="stylesheet" href="advanced.css" />'); window.onload = function () { if (!W3CDOM) return; // start up W3C DOM scripts }
In my opinion this is the single situation in which document.write
is an asset rather
than a liability.
This is the blog of Peter-Paul Koch, web developer, consultant, and trainer.
You can also follow
him on Twitter or Mastodon.
Atom
RSS
If you like this blog, why not donate a little bit of money to help me pay my bills?
Categories:
Comments are closed.
1 Posted by Chris Hester on 22 June 2005 | Permalink
What on earth's wrong with noscript? I use it to tell the user part of my page requires JavaScript. It can also be used to supply extra styles and content for non-script users. Besides, the W3C recommend using it, don't they?
2 Posted by Chris Heilmann on 22 June 2005 | Permalink
Dang, you are right ;)
3 Posted by Robert Nyman on 22 June 2005 | Permalink
First, I don't think that your use of document.write is a good idea.
Use the DOM, man!
if (W3CDOM) document.getElementById("menuStyle").setAttribute("href", "advanced.css");
Second of all, I'd also recommend reading http://www.robertnyman.com/2005/06/20/rise-lord-javascript/ about JavaScript awareness.
4 Posted by Robert Nyman on 22 June 2005 | Permalink
Your system apparently stripped away my LINK tag in my previous comment, but of course there should be a LINK tag with an id of "menuStyle" and no HREF for that script to work properly.
5 Posted by Adam Taylor on 22 June 2005 | Permalink
Robert - won't that fail to work, 'cos it can't scan the DOM until the page loads, which is the whole problem in the first place?
6 Posted by 4rn0 on 22 June 2005 | Permalink
In regards to the noscript tag. Of course we prefer unobtrusive, well written JavaScript. That's what we should definitely aim for and that's why we don't need any noscript 'Your browser sucks, go and upgrade it!' messages.
However, it seems to me that it is equally desirable to inform our less-than-fortunate, JavaScript-less visitor that he or she is not experiencing the full potential of our well coded, handcrafted website. And THAT'S where the noscript tag comes in...
7 Posted by James Ojaste on 22 June 2005 | Permalink
The theory behind not needing the "noscript" tag is that you can simply use JS to hide a block of text that's displayed by default. Of course, it's subject to the same timing issues that ppk described with document.write.
I didn't see any reason why DOM manipulation should have to wait for the entire document, so I threw together a quick test. I put in a quick 2-liner (var n = document.getElementById("noscript"); n.parentNode.removeChild (n);) in a div followed by 20M of text. Worked like a charm in FF 1.0.4, but IE 6.0.2800 throws up an error message: "Internet Explorer cannot open the Internet site http://servername/testscript.html. Operation aborted". Guess IE didn't like the script removing itself.
You can still work around that problem by setting a base style of "#noscript { display:none; }" followed by your id="noscript" div, followed by JS to remove the id="noscript" div, finally followed by a style of "#noscript { display:block; }". The disadvantage to this, of course, is that if you have a really long block of text, it won't appear until after the 2nd style is downloaded.
8 Posted by Tino Zijdel on 22 June 2005 | Permalink
There is also no need to use document.write for the case mentioned in this article since the DOM is already present and accessible through javascript during rendering.
See my example page: http://therealcrisp.xs4all.nl/meuk/jsappendedstylesheet.html
I often use inline javascript to be executed right after the rendering of certain elements to immediately perform javascript functions on them. Althoug it is not a clean separation of markup and behavior it beats the downside of waiting for onload.
document.write is however certainly not dead yet; bannerproviders use it to generate bannercontent - it's the easiest way.
A lot of site also still use it to reduce bandwidth; huge chunks of markup go into cacheable scriptfiles and only the content wrapped in functioncalls is sent to the client. Offcourse this is legacy from the time where not all browsers could handle gzipped content that well (IE still has bugs on that point), but it is still very common.
9 Posted by Robert Nyman on 22 June 2005 | Permalink
Adam,
As Tino pointed out with his example page, it works fine manipulating the DOM before the whole page has loaded.
When it comes to ad content, wouldn't it be possible for ad providers to tell the web developer that's going to incorporate their ads to set a string variable with the ID of the element where they'd like the ad content to be added (the name of the variable should be specified by the ad provider)?
Then the ad provider's script could be proper DOM scripting and instead use appendChild to insert their ads to the element identified through above mentioned variable.
10 Posted by Tino Zijdel on 23 June 2005 | Permalink
Robert: as for advertising using document.write() it's the management tools like phpAdsNew that will need to change to accomodate that. At the moment when you insert a new ad (usually by uploading an image or flash movie, or inserting some HTML) the management tool will generate the necessary javascript for sites that request the ad in javascript format. Generally these tools wrap the content in document.write()'s so they can be 'inserted' on the requesting page at the spot of the JS call.
I don't expect a change in that corner anywhere soon (unless IE7 would by default block all javascript from another domain).
11 Posted by Tino Zijdel on 23 June 2005 | Permalink
By the way: the article from Bobby van der Sluis has a good example of necessary use of the navigator.userAgent property. I too had to resort to that recently to work around a JS-related bug in Opera 8
12 Posted by Robert Nyman on 23 June 2005 | Permalink
Tino,
Thanks for the info, I didn't know about phpAdsNew. I'm also a bit curious about Google AdSense and others, but my hope is (as every other web developer's) that they will update their products to instead use DOM scripting soon in the future.
13 Posted by Jim Ley on 23 June 2005 | Permalink
the write method of the document object is completely standard, now there are good arguments for it not to be used, but that it's not standard is not one of them see http://www.w3.org/TR/1998/REC-DOM-Level-1-19981001/level-one-html.html .
14 Posted by Littlecharva on 23 June 2005 | Permalink
What's wrong with using href="javascript:myFunction();"?
What should I use instead?
href="#" onClick="myFunction();"?
15 Posted by 4rn0 on 23 June 2005 | Permalink
You should add an ID to the anchor and add an onclick behaviour to it through an external JavaScript file!
href="#" id="myId"
document.getElementById('myId').onclick = myFunction;
(or even better, use a wrapper function that incorporates addEventListener and attachEvent)
16 Posted by Littlecharva on 23 June 2005 | Permalink
Can you point me in the direction of an example wrapper function?
17 Posted by hemebond on 23 June 2005 | Permalink
Always put proper URL's in the HREF attribute. If it shouldn't have a URL, don't make it a link.
18 Posted by Tom Clancy on 23 June 2005 | Permalink
"Can you point me in the direction of an example wrapper function?"
http://www.scottandrew.com/weblog/articles/cbs-events
19 Posted by Joost on 23 June 2005 | Permalink
noscript is still needed when select boxes auto-submit a form onchange(). inside the noscript tags, the submit button is shown.
20 Posted by Robert Nyman on 23 June 2005 | Permalink
Joost,
An alternative approach might be to first include the button in the HTML code, and then use unobtrusive JavaScript to hide/remove it for those who have JavaScript enabled.
21 Posted by Joost Diepenmaat on 23 June 2005 | Permalink
The biggest problem I can see with is that it doesn't help you with the cases when don't have "enough" javascript support (like no XMLHttpRequest, for instance). With the difference in browsers today, you'd have to test the available features anyway, which makes the tag sort of useless.
22 Posted by Fuzztrek on 24 June 2005 | Permalink
"noscript is still needed when select boxes auto-submit a form onchange(). inside the noscript tags, the submit button is shown."
One could question the accessibility and indeed usability of such a "solution". I personally hate anything that automatically submits a form for me, even though I do not have any accessibility concerns myself - and, of course, using this for navigation is not an option. Perhaps there are situations where this is not annoying, though.
As for the "bad practices", I mostly agree. However, I don't see going anywhere until JavaScript is completely supported -or- an appropriate alternative is suggested. I use it quite often, *especially* when validating forms serverside - my errors are hidden via css; a class is added to errors in JavaScript to show them; if JavaScript is not available, the form is submited and the appropriate CSS to show the errors is written in a noscript tag (other errors that I cannot check with javascript - database issues, etc. are placed in an array that my error showing function checks on page load).
This seems to work pretty well but I think it would get pretty ugly without the noscript tag. Open to suggestions of course. It really makes you realize how primitive HTML forms are - clientside AND serverside validation, oi!
23 Posted by Fuzztrek on 24 June 2005 | Permalink
"However, I don't see going anywhere until JavaScript is completely supported -or- an appropriate alternative is suggested."
hmm. that was supposed to be:
"However, I don't see noscript going anywhere until JavaScript is completely supported -or- an appropriate alternative is suggested."
24 Posted by Gerv on 24 June 2005 | Permalink
I think it's possible to avoid PPK's single remaining use of document.write(). Get some script which executes immediately (i.e. not onload) to add a style rule to the style DOM which hides the class you've given to the link blocks. Then, they'll get hidden as soon as they are rendered.
I'm fairly sure adding style rules is supported across all modern browsers, albeit perhaps with different syntax.
25 Posted by randfish on 27 June 2005 | Permalink
It's incredible to see such debate over this issue. I apprecaite all the hard work you've put into educating the rest of us and I hope to see more good advice in the future. Also - thanks for the link Tom C.
26 Posted by ppk on 28 June 2005 | Permalink
Great to see such a high-level discussion instead of the usual boring comments!
I'm not going to take any decisions now, but a few good arguments have been advanced, and I'll study them when the time comes to define bad practices.
If you have anything more to say, please continue the discussion.