Using DOM Scripting to Plug the Holes in CSS

A talk I gave at @media 2006 in London.

Jeremy Keith: Can everyone hear me ok? Is this on? Is everyone reading me correctly? Okay, then I think, I think we’ll dive right in.

Good morning. Thank you all very much for coming to the techy one instead of the designery one. A bit of a tough decision. I’m kind of hoping that all of the techy people will go to the design one and all of the design people will go to the techy one. So we’ll see who goes that way. It’s not too late to change your mind if you want to run out, go for it.

My name is Jeremy Keith. I build websites. Can I actually… who was here last year? A show of hands? Oh, okay, great. So you saw me last year talk about JavaScript, right? And what I was trying to do last year was more or less a PR job. I was trying to convince people that JavaScript wasn’t evil, that it was a good language, that it didn’t deserve the reputation it had. And that’s not what I’m going to do this year. You know, in the last year, we’ve actually accomplished quite a bit in rehabilitating the language and the use of the language. It’s come a long way. The DOM Scripting Task Force, the WaSP Task Force, that came out pretty much as a direct result of @media last year. We all got together in a pub after the conference was over and we decided to form a little group to try to promote responsible scripting. So this year, I don’t really feel the need to have to convince anybody why you should be using DOM Scripting or how JavaScript isn’t evil or isn’t inherently inaccessible or any of these other myths that I sort of was battling against last year.

One of the other things that was happening this last year, was I had this book published. So, as you can see, I have a couple of copies here, which I am going to be giving away to lucky members of the audience. At the end of my talk, we’ll have some Q and A, some fights, some arguments, and discussion hopefully. And if anyone asks good questions or makes good points, I’ll give them a copy of the book. And also I’ll do a couple of spot prizes as well throughout. So actually, I’m going to start with the spot prize straight away. Spot prize will go to the first person who can tell me who this is. If you can name the whole band, that’d be great, but I’m actually looking specifically for the singer.

No, not me. Not me. My future self, but not me. Not Frankie Valley, no.

[crowd chatter]

Who? Nope. Well, the title at the top is a clue. That’s a song, this guy had a hit with it way back in the day.

[crowd answers]

Yes. Well done, sir. Come up and claim your prize. Buck Owens. This is Buck Owens and the Buckaroos is the name of the group. Now, this isn’t going to be country music 101. There is a reason why I have Buck Owens up here.

So Buck Owens had hits in the ’50s and ’60s. But mostly in the ’50s he really took off. And the reason was, he made use of the technology of the time. That was the time AM radio was getting pretty big. People had radios in their cars, but they were pretty crappy things. They didn’t have much bass, like the big car stereos of today. It’s a pretty tinny thing. Now Buck Owens exploited that. He deliberately kept the bass pretty low. He used a guitar to play the bass lines. Pretty much why all the surf rock bands form the same time did the same thing. So he was making use of the limitation of the technology. He decided to take the regular guitar and use it as the bass because that sounded great on the radios of the time. He was the first country music hacker. That’s what Buck Owens was doing here. He was hacking the country music to make best usage of technology. And that’s kind of the situation we’re in today. Let’s compare radios to browsers. Pretty sure in the future we’re going to have pretty fantastic browsers with lots of great bass. But right now they’re a little trebley, you know? They’re not quite there yet. But we can exploit the technical limitations that we have today. We can get around that, we can hack it. And one of the ways that we can do that is using DOM Scripting. By DOM Scripting, I mean the combination of JavaScript and the Document Object Model.

So in theory we have different technology to do different things. So in theory we have HTML for our structure. Start with your content, you mark it up, it’s for structure. It’s for semantics. And then you have CSS and that’s for your presentation. It’s all about how things would look. And then DOM Scripting is all about behavior. It’s all about how things should behave when the user interacts with the page. That’s the theory. Now in practice, sometimes it doesn’t quite work out that way. You start using CSS for behavior, you know? Hover? That’s behavior. And sometimes you need to use DOM Scripting for presentation. So it’s kind of doing a little Buck Owens. You’re going to take the regular guitar and use it like a bass.

So that’s what we’re going to do today. We’re going to take DOM Scripting and we’re going to kind of fill in some of the holes of the presentation layer.

Now they’re not too dissimilar, CSS and DOM Scripting. In fact there’s a lot of equivalence. If you think about it, both of them have to do with targeting elements in the page and doing something with the elements. It’s just the syntax that is slightly different. Since CSS we use selectors. We’ve got the element selector and all that. And with the DOM we use methods. It’s just another word for functions, if you can attach it to an object. As an example, we have the ID selector in CSS. So hash ID, then curly braces. You put your style declarations in there. Well that’s directly equivalent to the this DOM method, getElementByID. It’s a bit more verbose, it takes longer to type it out. But it’s a lot more readable, a lot more like the English. So an example would be: I want to get an element with the ID “footer” and do something with it. In CSS, it would be hash footer, I’d open my curly braces and I’d put in my style declarations. In the DOM, it’s document.getElementByID[“footer”]. So they’re both doing kind of the same thing. They’re getting an element based on an ID. An ID selector.

You’ve got the element selector in CSS, just the name of the tag, open your curly braces… when you’re in CSS. Well in the DOM, you’ve got getElementsByTagName and you pass it the name of the tag. So again, direct equivalence. So in CSS you might have p, this would get all your paragraphs in your document. To get all your paragraphs in your document using CSS, p curly braces. To do it using the DOM, document.getElementsByTagName[“p”].

We can combine things. It’s running off the screen, let me bump down the font size. So in CSS you can say, get me all the a elements in the element with the ID “nav”. So you’d go ID selector “nav” follow with element selector a. So you chained two of them together to be more specific. And you can do that with DOM Scripting as well. document.getElementsByID[“nav”].getElementsByTagname[“a”] does exactly the same thing. Gets all of the a elements within the element with the ID nav. So there’s a lot of equivalence.

What else? There’s the universal selector. In CSS we use the star, the one eyed jacks of CSS. And in the DOM it’s the same. You still use getElementsByTagName, just pass it the asterisk and you get all the elements in the whole document. Which is exactly what the element selector does there, the universal selector.

And what else is there? There’s the class selector in CSS. Dot classname. You’ve got all the elements that have that class name. Then in the DOM you don’t have documents.getElementsByClassname. We don’t have it. Which is a real shame. Because it’d be really, really useful. But when the DOM does not provide, we can make up for that ourselves. We can write our own. So, actually most people do write their own. It’s like building the better mouse trap with DOM Scripting. Everyone has written a getElementsByClassname function at some stage.

So here’s my attempt at building a better mouse trap. I’m going to write a function called getElementsByClassname. Actually I’m going to make it a method of the document. So I’m going to apply it just like any other DOM method. So let’s see. document.getElementsByClassname is the same as this function. And it’s the function that takes the single argument — the name — and that’ll be a class name. And pretty soon I’m creating an array, I’m running through all the elements for the document. I’m doing the getElementsByTagName[“*”]; get everything in the document. Then I check to see if it matches that name. By using a really crappy search there. The indexOf is probably not the best way of doing this. If anybody is better with regular expressions, you probably can come up with a much, much better way of doing this than me. I’m useless with regular expressions so I didn’t even go there. If you want to get the documents by class name, don’t use this. Just Google other people’s. People have written much better versions than me. Jonathon Snook has a nice one out there. There’s some other good ones if you just Google it.

This is an example of the kind of thing you can do. Basically I’m creating a new DOM method because it wasn’t provided straight out of the box. And that’s something you can do a lot. You can combine the existing building blocks to do your own thing. And that’s really useful.

So now I’ve got what I need. I’ve got this equivalent to the CSS class selector. So I’ve got my toolbox all ready to go. I’ve got getElementByID, I’ve got getElementsByTagname, and now I’ve got getElementsByClassName. So now I’ve got my arsenal all set. These are the weapons we’re going to use to plug the holes of CSS using DOM Scripting.

So, lets go. Let’s take a look at the problems we might encounter. Whoops, excuse me. So, here’s something that theoretically possible in CSS. But we’re not there yet. Striping tables.

I must thank Eric for setting me up perfectly with his key note. He segued very nicely into this I thought. One of the things we can’t yet do in CSS is to get the zebra table effect. Where every second row is a different color. We will be able to do it in CSS3. There’s the nth child pseudo class… property… I don’t know. But it’s getting pretty complex now, CSS3 at this stage. You’ve got this 2n+1. These are all basically the same way of saying the same thing. I’m not going to get into the syntax of CSS3. But essentially what you can do, you can select elements based on their order. Whether it’s odd, even, the third element, the fifth element, whatever. And that’s going to be really, really useful. One of the reasons it’s useful is to be able to say things like this. Get the basically every second table row and apply a class to it. For instance, apply this background color to every second row of the table. That’s going to be awesome. That’s going to be great. What we’re going to be able to do with that, is we’re going to be able to get these zebra tables, these striped tables.

So let’s say you have a table like this. Here’s a table of the schedule for this morning. It’s a fine table, it’s got the headers, it’s got the table rows and all that. It’s readable enough but the idea with striped tables, you make it more readable, you make it a bit more clear by having this color distinction between the rows. And that’s what we’re trying to get to. We can’t do that yet with CSS alone. We’re not quite there. We will be able to do it with CSS once CSS3 is out. So another 50 years and we’ll be able to do this no problem. But for now, we’re going to have to rely on DOM Scripting.

So I’m going to write out the script but I’m not going to write out the script in JavaScript, I’m going to write it out in English. This is the more important step. When you come to turn your script into JavaScript, that’s just translation. The most important thing is that you write out a step by step plan of what it is you’re trying to accomplish. And then just translate it into JavaScript and that’s the easy bit.

So here’s what I want to do. Get all the tables in the document — because I’m going to apply this to any table in this particular case, okay. It’s going to be a very simple function. It’s just going to make all the tables striped. Get all the tables in the document and start looping through them one by one. Now within each table I want to get all the table rows and I want to loop through every second table row, not every one but every second one. And apply a style on that row. So that’s my plan. Pretty straight forward. A five point plan. Now, I have to think which DOM methods do I need to accomplish my plan? And in this case, it’s just the one, all I need is getElementsByTagName. So I’m going to need to get all the tables in the document. Then later on I’m going to need to get every second table row within the table that I’m looping through. So those are the methods I’m going to use. Pretty straightforward. And now it’s just a translation job. Now we just translate this into JavaScript. So I end up with a little function like this. We’ll call it stripeTables. Loop through all the tables in the document. Get all the table rows. Then loop through every second one. See how the For loop is a bit different the second time. I’m looping through every second one instead of every single one. And then I set the style on the row.

So, that’s working. And that will result in the effect that I want. But it’s not really the best way of doing things. Because now I’m really intermingling my styles and my scripts. And that’s not ideal. I mean yes, we’re going to use DOM Scripting to plug the holes in CSS but that doesn’t mean we’re going to use DOM Scripting to do all of our CSS. So we’re going to avoid it. Don’t set the styles directly in the DOM Scripting. A much better idea would be to apply a class. And then you can set the color by using a class selector in your CSS style sheet. So later on when you want to change the color, you do it in CSS, not in your JavaScript file.

So I’m amending my plan slightly. Instead of setting the style directly, I’m going to set a class on the row. So to do that, what I need to do is to add a class. Because I just don’t want to give it a class. Because there might be classes that are already on the row. In fact, in my example table, there is already a class on every row. There’s a class vevent because it’s all marked up with microformats as an hCalendar. Which unfortunately the official schedule on the @media website isn’t, and that’s a shame. Maybe Tantek will give Patrick a scolding for that later on. So I want to add a class — not replace a class, add a class. So I’ve written a little function to do that. It takes two arguments. What’s the element I want to give a class to and what’s the name of the class? I just check, does it have a class name yet, then if it doesn’t, then great, then we just give it a class. If it does, then I just add the space separator and I join on the new class name.

So now I’ve written my little function to add classes. Again, this isn’t something that you get out of the box. There is no addClass function in the DOM or JavaScript so I built my own. Now I can amend my script. Instead of setting the background color directly like I was doing before, now I’m just going to add a class. And the result will be exactly the same, except it’s going to be easier to maintain. Because now, in my CSS, I have my style rules. In fact I can get a bit more complex. I can say if it’s table header, I want this background color. But if it’s table cell, make it this background color. So you can get, you know, a bit more complicated with the colors. You end up with something like that. Now on view source, you won’t actually see the classes I’ve added, you’ll just see the original markup as it was. So where it says class equals vevent, technically now in the DOM, it says class equals vevent, space, odd… the class name. But you don’t see that when you view source because you’re not actually viewing the DOM source itself. But we get our result, we have striped tables. And the nice thing is that when we do finally have CSS3 support and we get nth child selectors, we can take away this function and we can just leave it up to CSS. So to have these sort of things in place for now, sort of shoring up our sites. Then later on when this is there, we can replace them with CSS, the way things are meant to be. So that’s good, we’ve done something. We’ve plugged one of the holes in CSS using DOM Scripting.

There’s a variation on that. Let’s see, instead of just doing tables, we want striped lists. So let’s see the regular list of people. Like this is an ordered list. And I want to get that striped effect going on there. It basically is the same kind of thing, just slightly different. I’m talking about different elements and we might want to finesse it a little. For instance, I probably wouldn’t want to do this to every single list in the document. But maybe to lists with a specific class name. So what I would do is I’d have a plan to loop through all the ordered lists. And see, does it have a class name of striped, for instance? It’s searching for that class name. And if it does, then I’m back in that familiar territory, where I loop through every second list item and I set the class on it. So this is how it looks. Pretty similar to the other one except now I’m dealing with ordered lists instead of tables and I just have this little check to see does this match the class name. Again, probably the world’s worst regular expression doing the matching here. You’ll probably want something much better than this. Do as I say, not as I do when it comes to my code. Because I’m not the best coder. I’m using my add class function there to put in a new class, odd. Then in my CSS I can set that, so that result is that I do get that striped effect on the ordered lists. And again, you won’t actually see that class that I’ve added if you view source. But again it is good that I used add class instead of replace class because I see everyone already has a class of vcard. Because this is how I’ve marked up these people. There’s hcards, hugs and kisses lists, xfn, that’s cool. And a nice thing is then in my CSS, that’s where I’m keeping my styles, there. That’s where all the color and information is. So even though we’re using DOM Scripting to apply things like class names, we’re still keeping our presentation in our CSS. I could have set the styles directly using JavaScript. But we don’t want to go quite that far. We want to keep things reasonably separate. Okay, so that’s good. We’ve done one.

Let’s move on to another issue, problem, hole that we need to fix. Multiple background images, because we’re not there yet. Though Safari does support this by the way. How many people know that Safari does support? Safari does support multiple background images. In CSS3, this will be possible. You’ll be able to give more than one background image to the same element. And more than one background repeat position. And of course, there’s a reason why you want to do this. Because let’s say you’re building the coolest Web 2.0 Ajax app. And as well as having gradients, you gots to have rounded corners.

Now rounded corners are referred to as the Kobayashi Maru scenario. And the book for anybody that can explain the Kobayashi Maru scenario. I think his hand was up first.

[crowd inaudibly answers]

I think I want the exact film.

[crowd in unison answers]

Wrong. Sorry.

[Crowd answers]

You got it, Star Trek 2: The Wrath of Khan. The Kobayashi Maru scenario is essentially an unwinnable situation. Well, Captain Kirk won it but he cheated. He cheated. Come on, Star Trek 2: The Wrath of Khan? Who doesn’t remember this?

Great. No sound. Okay. Yeah, the reason why I refer to it as the Kobayashi Maru scenario is because it’s essentially an unwinnable situation. Your choices are kind of equally as bad. You can use CSS but it’s not supported yet. Well Safari supports it so you can have rounded corners in Safari. That’s one option. And you can just wait for the other browsers to catch up. Or, you can add a whole bunch of divs into your markup. Which is fine, and some people do that. But, it’s not ideal, right? I mean markup is for structure, it’s not there to add presentation. And really what we’re doing here, our goal is to get rounded corners. Which is a presentational thing. And to accomplish that is to shove in a whole bunch of divs. But it’s not ideal. It’s fine, and if you do that it’s fine. And the other option is to use JavaScript to generate those divs and use JavaScript to put them into the markup. And that’s really not much better. It’s kind of passing the buck. I wanted to say I’m going to show you how to do this. And don’t get me wrong we will see how to do it. But I didn’t want to sound like I was endorsing this necessarily. It’s an unwinnable situation at the moment. Because we don’t have the CSS support. We can fudge it in the markup or we can fudge it in JavaScript but we’re really just passing the buck to JavaScript. And it’s a no win situation.

So given that, let’s take a look how we might use DOM Scripting to do this. Here’s what we want to happen. So this is an element before. So in this case, it’s a blockquote element. And I’m not going to give any prizes for naming the poem but if anybody can recite a few lines?

[crowd speaks]

A few lines after this?

[crowd speaks, inaudibly]

Oh, frabjous day, callooh, callay… Excellent, Excellent, I’ll pass that down. So I’m going to quote Jabberwocky by Lewis Carroll up here. And it looks fine but what I really want to do is to have it look really cool and Web 2.0 with rounded corners. But I can’t do it just straight out of the box. I either use CSS which isn’t supported. Or add a whole bunch of divs into my markup. Or generate those divs with JavaScript. None of them are ideal. But let’s look at the third option.

So what I want to do is to create markup. I’m going to generate divs and dump them into an element. So now we’re actually going to see some DOM methods that we haven’t seen before. Methods for actually creating markup. We’re actually going to create elements. It’s very powerful to create markup using JavaScript. I can create elements, I can create text nodes. By itself, createElement is useless. Because you can create elements in markup but it’s just floating around in JavaScript limbo. What you need to do is get it into your document. To do that, you have a couple of methods at your disposal. And the simplest one would be to appendChild. So this newly created element we can append it somewhere in the document. So here’s this little function that I wrote. It’s going to create four divs. One for each corner. It’s going to create divs with a specific class name each time. Northwest, Northeast, Southeast, Southwest. Think of it like going around the clock. So it looped through four times, creates a div each time, and applies a different class name. So I’ve wrapped that all up in a function. And it takes a single argument which is an element. So some element in the document, I just need to pass that this function and it will instantly create these four divs and append them as children of the divs. So that’s how I create the markup. Now which documents do I want to apply this to? Well in this case, I’m going to use my getElementsByClassname method. Remember this isn’t supplied by the DOM straight out of the box, this is something I came up with myself and everybody else has come up with too. So I’m going to find any of them that has the class name of “rounded”. So my markup is going to say some blockquote with the class name of “rounded”. So the JavaScript is going to take care of generating the superfluous divs because I don’t want them cluttering up my markup. Loop through any elements with that class name and calls that function that I wrote. Called insertCorners. So this function is calling the previous function. And there’s the result. And it looks like this. And that JavaScript, as I say, we’ve got to get elements by class name so we need that. We’ve got to insert corners, and we’ve got the roundCorners function. But the real work is being done in the CSS. This is where the work is going on. What I do, is I take those divs, and I now position them. So I have the element itself is positioned relatively. And those four divs are positioned absolutely in the four corners. So the Northwest one is positioned in the top left, Northeast is top right, Southwest, Southeast. So again all the actual work is taking place in the style sheet. And if later on I want to change where things were positioned, I can do it in the style sheet. I don’t have to go hunting through my JavaScript. So again, keeping the styles as much as possible in CSS, where it belongs. Even though we’re using JavaScript to achieve presentational effects. So that’s rounded corners.

Let’s move on to something else. Generated content. Mmm. Now this is actually CSS2. And this is supported in a couple of browsers today. I can’t keep track of which ones. Generated content with CSS? I don’t know. That sounds like behavior to me. I’m not sure this is the right place to have content generated. I don’t know if CSS is the right tool for this. But anyway, for example you can do stuff like this. You can use the :after pseudo class thingymajiggy to add content using this content technique I’ve already showed you. So, as an example, a blockquote, see another blockquote. So here’s a blockquote and it’s also a very subtle plug for d.Construct, which is happening again this year by the way. Keep the first week of September free in your calendar and come on down to Brighton because we’re going to have an awesome time. But this is marked up in a blockquote. Now blockquotes are wonderful, wonderful elements for marking up semantic meaning. Not for layout. Don’t use it to indent content, that’s evil. No, it’s a wonderful way of marking up some piece of text you’re quoting. And then there’s the cite attribute. Now, how many people are familiar with the cite attribute of blockquotes? See? You’re a savvy audience. There’s a lot of people who aren’t familiar with this. It’s totally understandable why somebody wouldn’t know about the cite attribute. The reason why it’s understandable is because the default browser behavior. Because the default browser behavior is to do bugger all. It completely ignores the cite attribute. It’s like hidden meta data now. The user can’t actually do much with it. I think in Firefox you can right click and go to it or something. But there aren’t many browsers doing anything with it by default, with the wonderful cite attribute. So what I’d really like to do is to show this is where it came from, this is my source. That information is already there in the cite attribute but I want to make it visible. Because nobody likes invisible meta data. Right? So, if I had CSS2, if I had full CSS2 support, I could do that very, very easily using CSS. As a matter of fact, I can do that in Safari. Safari does have this generated content stuff.

So that’s cool, but most browsers don’t or a lot of browsers don’t. So again, we’re going to use DOM Scripting to do this. We’re going to create markup or going to create something and dump it into the page. So here’s my plan, and again we’re going to write it out in English first. Get all the blockquotes in the document, because I want it to apply to all blockquotes and not just blockquotes of a certain class. Loop through each blockquote, get the cite attribute. Now if the cite attribute exists, then in that case, I want to create a string of text that say that word source, followed by the source, the actual value from the cite attribute. So that’s the plan. That’s the plan in English. Here it is in DOM Scripting terms. I’ll need getElementsByTagName because I’ll need to loop through all the blockquotes. I’ll need to use getAttribute because I’m looking for an attribute on an element, in this case the site attribute. And this time I want to create a text node. I don’t want to create an element, I actually want to create a string of text. So there’s a method called createTextNode which is similar to createElement but instead of creating a new element, you create a new text node, like it sounds. And then I’m going to put it back into the blockquote so I’m going to use appendChild again. So here’s how it might look. I looped through all the blockquotes, get elements by tag name, loop through each one I get the cite attribute. If that exists, if that works, then I’m going to create a text node with the value of the string source plus whatever the cite attribute is and I’m going to put that at the end of my blockquote. And the result is this. I get to see the source of the quote. Which is good. I’d actually go a little bit further than that. I’d get a little fancier and I would actually make it a clickable hyperlink because it’s not much good having it as a string of text. And I’d probably apply a class so I can style that differently and float it over to the right like that. So now I can actually go and visit that link. So the expanded version is a little longer but it’s pretty much the same idea. You know, loop through all the blockquotes, get the cite attribute, if the cite attribute actually exists then, but now I just do a few more things. I create a text note but I also create an “A” element; I create a paragraph to put it in, because blockquotes do actually need to have block level elements in there for the doctype I’m using. I set the href value, I’m appending all that. I’m setting the class name there of “attribution”; that’s in my style sheet; I can do that floating to the right. So it’s getting a bit more complex but the basic plan is still pretty much the same and at the end I just dump it into the blockquote so we get that nice clickable link to the source. So that’s good; that’s something we’ve managed to do. What else can we do?

Audience: Excuse me?

Jeremy Keith: Oh What?

Audience: I don’t want to seem a bit smart ass but you don’t want to use a cite tag for that?

Jeremy Keith: Cite tag? Oh you’re right. That would actually be the semantically correct thing to do, wouldn’t it? I guess? Hmm if only we had a mark up expert in the room. I could. I’m using a “P” element but we could argue about angels on the head of pins and stuff. That’s worth… This is the smart arse award for… Sorry I do actually have a choice of books. If nobody wants my book it’s totally understandable. Hey you might have it already. You can request to have one of Stuart Language’s DHTML Utopia books. Forget the title, it’s not about DHTML. It’s all about scripting stuff. It’s cool.

Okay, so moving on from that one. Max width. Oh Max… I could go on on a rant here now because I love liquid layouts. I love love love liquid layouts. I think they’re more webby than fixed width. Liquid layouts are the way to go. But most people don’t implement liquid layouts. And one of the reasons is because “At really big sizes it just gets unreadably long… blah blah blah.” Well max width would solve that, the CSS declaration max width, and say once it gets to a certain width then we can, for instance, set a size. So on the body type, it could say it’s never going to get bigger than 1600 pixels, for instance. This is supported in most browsers today but not the one that everybody’s using so that’s a bit annoying. But it will be supported in IE7, correct? Yes, which is like… If I had one request for IE7 it was going to be max width so my prayers are answered. There’ll be no more excuses for the fixed width people in a couple of years.

So this is the idea that you have a maximum width that your body, for instance, or some element can reach before it just stops expanding. And the plan to implement that in DOM Scripting would be really straightforward. Find the current width of the browser. If it’s greater than 1600 pixels then set that style declaration on the body, set that width, so using DOM Scripting to plug the hole in CSS.

Alternately you’ve got min width. Same thing, also CSS2 spec, also not supported in the browser everybody’s using. And similar syntax there, and the plan would be much the same. Get the current width of the browser and if it’s less than 800 pixels then set a style of 800 pixels on the body. Great. So we can have a bit more control over how big things get. Which is perfect. ‘Cause the designers don’t like the fluid layouts ‘cause there’s just not enough control over how big things get. Well this will allow, you know, it will allow enough control on the part of the designer to limit how big or how small things can get but still allow the user to determine how they want to see things, which, in my opinion, always trumps the will of the designer, but that’s just me.

So how will we implement this using DOM Scripting? Actually we wouldn’t implement this using DOM Scripting. We would implement it using BOM scripting. Because what we’re talking about here is not the Document Object Model. Here we’re talking about the Browser Object Model. We didn’t need to get any elements in the document. We needed to find out “What’s the width of the browser?” And to do that you don’t use the DOM. To do that, you use the Browser Object Model, to do with the browser chrome. It’s everything to do with the window that the document’s being displayed in, not the document itself. So this is more like old school JavaScript using the Browser Object Model, not the Document Object Model. And actually this is where you get into a lot of incompatibilities. People complain about JavaScript and the browser incompatibilities. JavaScript is pretty well supported across the browsers, the core language itself is pretty well supported. The Document Object Model? Pretty well supported across most of the browsers. The differences come with the Browser Object Model. What one browser decides to call the width of the browser, another browser uses a completely different name for it. So everything to do with browser sizes and chrome, that’s where you run into the differences, and events and stuff like that, that’s where you run into all the browser differences that are really annoying.

So this case, you have to use the Browser Object Model, which I’m not that familiar with but I don’t have to be because The Man In Blue, Cameron Adams, has already done… Is he here, or has he gone next door to the designers? I hope he’s gone next door. Yeah, he’s gone next door. Well you can buy him a drink tonight cause he’s formed this really nice technique called resolution dependent layout. I don’t think I’ve got a net connection so I can’t show you some of the examples, but do check out website for examples from Rammstein, Industrial German Rockers who use this. If the browser width is a certain width you get one layout, if you shrink the browser you get a different layout. So it’s kind of a nice compromise. It’s a pretty cool solution. It’s pretty neat. I think Dave… Dave, you’ve been using this on Rosenfeld Media, I think? Yeah. So it’s, you know, even Dave Shea’s using this. It’s cool. It’s cool.

So that’s a nice way of using, not DOM Scripting necessarily, but using JavaScript to fix a hole we have in CSS.

What else might we have? Okay. Next job we want to tackle is anything you can possibly imagine! And we can do that using JavaScript very easily by using the IE7 script from Dean Edwards. He’s written this amazing piece of JavaScript that basically adds CSS support to IE6, which is the browser we have the most problems with with all of these selectors and things that aren’t quite yet supported. He’s written this script; he’s called it IE7, until he gets the cease and desist letter from Microsoft, and it’s pretty amazing because it basically turns Internet Explorer 6 into a better browser. It adds support for all this amazing stuff. And not many people are using it now and that’s kind of fair enough. I think it’s really going to come into its own as IE7 rolls out and we start implementing all the CSS stuff that you are seeing that’s going to be really cool, but we still need to support IE6 and older browsers then it’s going to be a great sort of stop gap measure. I can imagine, for instance, using conditional comments, or somehow just targeting IE6 to load in the IE7 script from Dean Edwards and just letting other browsers just get on with it. ‘Cause I mean one of the downsides is it is a bit big. It’s a reasonably large javascript file. But it’s a sight to behold. It’s pretty amazing. He’s a sort of mad genius JavaScripter, Dean, and he’s one of our own; he’s a Brit. He’s great.

So that’s cool. You can do pretty much everything that you want to do in CSS. You can do it using JavaScript if you get complex enough. I mean all the examples I’ve shown you have been very simple, just addressing very simple tasks and tackling one task at a time. This is something that tackles anything, anything you can possibly imagine.

But there’s certain things, you know, you want to go beyond just plugging the holes. Sometimes there’s things that CSS just can’t do and doesn’t have any plans to do. As far as I know there’s no draft specifications for some stuff for CSS. They’re not going to attempt to make it the all-singing, all-dancing technology to do everything, even though it looks like that sometimes. For instance, in javascript you have the arrow of time and that’s incredibly useful. In JavaScript you have things like setTimeout and setInterval and there’s a clearTimeout and clearInterval. What that allows you to do is do things over time. Which doesn’t sound like it’s that great an innovation, but when you combine that with CSS then you can do a lot of cool stuff because what you can do is update styles over time. Set a style and then half a second later change that style, half a second later change it again. We can get all sorts of nice effects. You can get animation. ‘Cause what’s animation? You’re just changing the position of something on the screen. How’s the position set? It’s set using CSS properties like top and left. So I can say setTimeout every couple of miliseconds I want to change the left position by one pixel. The result will be something moving across the screen. Animation. That’s pretty cool if it’s used the right way, it’s god awful annoying if it’s used the wrong way.

But something else that’s nice is fades, okay? As a nice way of giving feedback. I mean, right now we’ve got certain amounts of feedback we can give based on user behavior in CSS. We’ve got the :hover pseudo-class. When the mouse hovers over a link, for instance, we can change the background color. But it’s on or off. It’s binary. It’s either the background color is one color or it’s the other but there’s no changing it over time. You can’t gradually change the background color of something using CSS but you can using JavaScript. And just gradually change the background color over time. So you’ll see stuff like, who uses like 37 Signal’s applications, like Backpack and stuff like that, right? And they have that nice yellow fade technique where you do something and it shows that something’s happening. And this is enormously useful for Ajax applications where you need to indicate; one, that something is happening; two, that something has happened. And that’s where these sort of techniques come in really handy. We can use JavaScript to progressively change, for instance, the background color of an element so you get that yellow fade technique, which has since been taken up by other people and they’re also using the yellow fade, which I think is kind of good because it establishes a bit of a convention. I mean I don’t want to get all about Jakob Nielsen about this and say “Conventions are great! Blue underlined links are the way to go!” But it can be good. If the user goes to one site and they get familiar with the yellow fade techinique and then they go to a completely different site and it also does the yellow fade technique then there’s a point of reference and it’s not as scary as it could be and that’s good. But fades are great, like I said, particularly with Ajax applications.

So here’s, for instance, a contact form and I’m going to do some validation on it. In this case the validation is actually happening in Ajax; it’s happening on the server side. But this would apply for client side validation as well, but you don’t really want to do much client side validation. So let’s say I’ve got a contact form, somebody submits it without filling stuff in. Okay I’m, first of all, I’m adding some text in here ‘cause I know this is required. I’m updating the text of the label of the form to say “That’s required.” And, but also, as well as doing that, I’m using a little script to change the background color over time. So every couple of nanoseconds, miliseconds, I start with one color and I fade it down till it goes to white. And you’re also using the color as a little bit of extra information and give kind of a reddish color to indicate something’s wrong. And if I wanted to give positive feedback I’d use a different color. So let me sort of fill in, okay, no still got to fill out that field, hello world, worlds, world, and now I get a green sort of feedback. It’s a more sort of positive message. But it’s nice and it directs the eye toward that area and it says “Something has happened here.” So enormously useful particularly with Ajax applications, the fact that you can play around with the arrow of time using javascript.

And I think I’m going to stop it there and ask you guys if you have questions, ideas, arguments, and remember there’s books to be had, there’s choices. Oh we have a microphone, by the way, so if you just stick up your hand, I’ll pass the microphone around. Okay, Eric Meyer has a question for me. This gentlemen over here. Brace myself.

Eric Meyer: So you did that thing early on with the document dot get elements by class name equals function blah blah blah?

Jeremy Keith: Yes.

Eric Meyer: I was just wondering, could you have done element dot add class equals function blah blah blah or document dot add class equals function blah blah blah?

Jeremy Keith: Yeah, you can extend just about anything really. JavaScript’s very flexible in how you do things. I mean, I usually just write function, the name of the function, and the arguments. But using some variable name equals function is also a fine way to do it and you’ve even got JavaScript Object Notation which is, I could just as easily done all this using colons and curly braces. So there’s all different ways. And yeah I could have extended the actual element. I actually do that a lot where I’ve taken the element in the document and I need to store some information about that element, right? And I don’t want to use a global variable cause they’re bad. Don’t use a global variable. And I can’t use a local variable. I want the element itself to store some information. What I’ll do is I’ll create a property on the element. I’ll say “This element dot some piece of information equals, you know, some string.” And then later on I can query that element itself and say “Give me some piece of information or give me that property.” Well if I can set properties on elements then yeah, I could set methods as well. So I mean a method’s properties, a method’s functions they’re the same thing, right? It’s just whether you’re applying them to an object. So yeah, I could’ve done that.

Eric Meyer: Can you jump to slide 20?

Jeremy Keith: Slide 20? Okay. See if the technology is up to it you know. That S5 thing.

Eric Meyer: Well you hit two zero and hit return.

Jeremy Keith: Yeah, okay. Ooh, keyboard support. Yeah.

Eric Meyer: Yeah well it’s in there.

Jeremy Keith: Yeah… slide twenty, you wanted?

Eric Meyer: Well apparently I wanted to go further forward. Basically the bit where you were calling add class in the middle of the loop.

Jeremy Keith: Okay, so here’s the function itself, add class, and here’s… right.

Eric Meyer: So here, instead of calling add class, you could have done, elem dot add class blah if you had written it the other way?

Jeremy Keith: Yeah I think I would have had to rewrite this a little bit yeah but absolutely, yeah.

Eric Meyer: You’re just a javascript expert and I’m not so I don’t know. Thank you.

Jeremy Keith: You’re most welcome. Yeah, no that probably would have been a better way to do it thinking about it but, meh, this works. I’m not the world’s best coder.

Okay, I’ve got a, there’s a hand… who was first with the hands up down here? I’m not sure. Give the microphone to one of these gentlemen down here. Oh Eric, do you want the book or are you perfectly happy with… here have the book.

Audience: Hi. About Eric’s keynote presentation earlier on and Eric obviously went through the years and showed the restrictions, the things that he found frustrating with CSS. What do you find frustrating with the DOM script and what would you like to see in the future that would make life easier for you, you know, in the same way that CSS has advanced?

Jeremy Keith: Yeah, not much…

Audience: … with CSS over the years. What do you find frustrating with the DOM script at the moment and what would you like to see in the future that would make life easier for you in the same way that CSS has advanced?

Jeremy Keith: Yeah, not much to be honest because, as you see, even when stuff isn’t provided by the DOM you can just make up for it yourself. So it would be nice if there was a getElementsByClassname method.

Audience: That’s not ideal. You would obviously want some kind of invoked function there.

Jeremy Keith: You know, there’s also such a thing as scope creep and we don’t want people putting in a feature request that the DOM should do this and the DOM should do that. And frankly I think CSS has got some serious scope creep in CSS3. It’s like I want to be able to do flyout menus and generate content using CSS, that’s scope creep. And I think the DOM does one thing. It allows you to target nodes in a document and it uses a very small arsenal of methods to allow you to do that. There’s getElementByID and getElementsByTagName and that’s kind of it but I think it’s enough. That’s pretty good. I heard Brendan Eich talking about JavaScript 2, which is on the way, probably before the end of this year there will be a JavaScript 2 and has all sorts of improvements that are coming, but there again there’s a school of thought that suggests you leave it as it is. Yeah, there’s things we could fix and things could be better but people are using it as it is and that’s pretty good. I asked the same question to Douglas Crockford who’s like a muse for me when it comes to JavaScript coding and I asked him what would he like to see, what’s his wish list for the next version of JavaScript, and he said just leave it like it is mostly. Of course he has issues with things like semicolon insertion. You don’t have to put the semicolon at the end of the line. JavaScript will assume you mean it and that can lead to really sloppy coding. But I’m fine with it. I guess if I was a real programmer I’d be saying things like we’ve got to have strong typing in JavaScript because weak typing sucks. But it’s fine. Come on, it does the job. It’s kind of the same with the DOM. It would be nice if there were certain things. It would be nice if you had x-path support like instead of using the DOM any time you want to get to a node you could just give a path to that element. But these are all niceties and it would just lead to scope creep. I’m happy with it as it is. What I would like to see is browsers support the specs as they are rather than already talking about: all right, let’s move on to the next stage of the spec. It’s like, all right slow down. Let’s get to the stage where we’ve got a level playing field of browsers… which is emerging. That’s the real nice thing about DOM Scripting especially if you’ve come to it from CSS. Eric went through today all the heartaches and headaches you have with CSS and it is a lot better today than it was. It used to be a real nightmare. But CSS, as you pointed out, is this relatively straightforward technology. You look at the syntax and you can say, oh yeah, make that red, make that big. You can grasp it pretty easily so getting something done in CSS really quick is no problem. Making it work in all the browsers is a nightmare. That’s where the problem arises. Now DOM Scripting is kind of the opposite situation because to get to learn it you have to invest more time. There’s a bit more of a learning curve. It’s a programming language. JavaScript is a programming language so that requires more learning time and the DOM itself, there’s things to remember. You need a reference book to remember all these methods and all these properties you can use but the nice thing is, once you’ve written a DOM script using the W3C DOM standard, and then you come to test it in the browsers, that’s a sweet feeling because usually it just works. It just works across all the browsers. Now I’m not saying all the time. I don’t want to give people false expectations. There are still browser differences but that’s where I’d like to see change is in the browsers. Say, could you just fix that one thing you don’t quite get yet and not in the actual spec. I’m pretty happy with the Document Object Model as a spec. Also remember, my wish list for the DOM will be different to other peoples’ because I’m using the DOM, I’m using the Document Object Model, here specifically for targeting HTML documents within a web browser but the DOM isn’t just about HTML documents. It’s not just about web browsers. The DOM is for parsing any markup document. So I might want a getElementsByClassName because that would be really useful with HTML but it wouldn’t do you much good with an XML file if you needed to parse it using PHP or some other language that also supports the DOM. So the DOM deliberately needs to stay kind of lightweight and not bloat and not get too full featured. I’d much rather see change in the browsers than in the specs.

Audience: Thank you very much.

Jeremy Keith: This gentleman at the front had his hand up pretty quickly I think. You have to be sharp on the draw. Do you want to come up now or you can come up later, whichever you like. Ok, great.

Audience: Is this on? I think converting PowerPoint to clean and valid XHTML…

Jeremy Keith: Do you use Dave Raggett’s Tidy?

Audience: No, I wrote my own.

Jeremy Keith: Smart.

Audience: Last week I wrote a small function to automatically expand the fonts and the images so that the slide fits the browser window.

Jeremy Keith: Sort of like this one here where the font size will change?

Audience: That kind of thing. It works fine in Internet Explorer and Opera and in Mozilla but in Firefox it seems to get confused. It seems to be drawing the page too fast before it applies the job.

Jeremy Keith: So events are getting fired in the wrong order?

Audience: What am I doing wrong?

Jeremy Keith: You’re not doing anything wrong. It’s a browser issue again. It’s like Eric talked about earlier where CSS became this cabalistic thing where you needed to know the hacks and the little quirks about which browser is buggy and which browser isn’t. Kevin Smith, he’s got this whole big chart on his site of browser bugs when it comes to CSS and it’s this big convoluted thing and the real CSS masters are the ones that keep that stuff in their head. And for stuff like that — oh, there’s an issue with Firefox where if you resized a screen it doesn’t quite catch — that’s kind of the same thing and again that has nothing to do with the language, nothing to do with the core JavaScript language, nothing to do with the Document Object Model specification. In that case it would be down to events and, as I mentioned earlier with the Browser Object Model, that’s were we run into problems. Things like events are handled differently between browsers and that’s where we have to do code forking and, like I say, anything to do with the browser chrome, trying to get the widths and height and stuff like that, that’s where you run into browser issues. So you’re not doing anything wrong. It’s some browser maker who’s doing something wrong.

Audience: Is there something I can do?

Jeremy Keith: Talk to Eric. He’s fixed it somehow. [laughter] Does it screw up in Firefox? You need to get some JavaScript help. Sort it out. Talk to PPK behind you. He’ll fix it for you. Ask for some help on JavaScript lists and that kind of thing.

OK, hands up. Who’s got another question? Who was first with their hands up. Maybe back there, one of those two who can fight it out.

Audience: Recently I had the exact same thing you’re describing with the max width issue on the project and rather than a JavaScript solution I went for, very reluctantly in the end, using an expression in CSS, IE only.

Jeremy Keith: That’s fair enough.

Audience: My reason for that was primarily because I didn’t want to have to use JavaScript in browsers that supported MaxWidth and I didn’t want to fork based on the browser. So what are your feelings on using expressions pro or con?

Jeremy Keith: That seems to work fine and I believe that Chris Wilson will be with me on this that that’s the way to go with serving up different style sheets as well as conditional comments because they only work in IE. The thing is then you’re doing something in the markup. That’s the Kobayashi Maru, isn’t it? You’ve got to mess with something. Either you’re going to mess with the CSS or you’re going to mess with the markup and there you’ve had to add those comments to do the expression.

Audience: I created the comments to do an IE only style sheet and then put the expression in that.

Jeremy Keith: OK. So it’s kind of passing it along.

Audience: It was a reluctant decision. I was just interested in what…

Jeremy Keith: The main is that thing you’re thinking about it at all. How is this going to effect my markup? How is this going to effect my style sheets and how can I keep stuff separate? How can I keep stuff cordoned off? With CSS, for instance, I hate using hacks. I hate, hate, hate hacks and I avoid them at all costs. If I do have to use a hack then I will put it in its own style sheet and use some way at getting at that style sheet because I want it quarantined. They’re nasty things. So I think it’s good to keep stuff quarantined and it’s good just to be thinking about that instead of just, yeah, whatever, one big style sheet with loads of stuff or one big JavaScript file that’s getting messy. As for sniffing for browsers, yeah, conditional comments because if you’re specifically talking about IE that’s the way to go I think. I think I’ll be with Chris on that one. And in JavaScript when you need to sniff for browsers, don’t do it the old fashioned way which is if the name is Mozilla or the name is Internet Explorer or the version number is less than that, I mean how many Flash pages did this to try and detect the browser and then every time a new version of the browser came along they’d have to update their scripts, right, because the version number stuff didn’t work anymore. What you use in the DOM though is, let me get an example script, so here’s some JavaScript, in my stripeList function, slightly different from the plan I showed you in the slide, when I actually implemented this I added one extra line which was if document getElementsByTagName bla, bla, bla, bla, bla. The idea there is I’m just testing first is this browser capable of understanding what I’m going to throw at it. This is called object detection. It should really be called method detection because that’s what I’m testing. I’m testing is this method supported and it’s kind of like the fair ground, you must be this height to ride. It’s kind of like that. The browser must understand this to go any further because within my function I didn’t use that a couple of times and if I hadn’t done that test to see if it was supported, and old browser, now admittedly a very old browser we’d be talking about Netscape4, if that browser came along and tried to access and run the script it’s going to pop up errors because it doesn’t know what the hell I’m talking about in this document getElementsByTagName stuff. Pretty much this is politeness and good manners and it’s a version of browser sniffing that doesn’t involve browsers: object detection. That’s generally the way to go when you’re doing browser testing within JavaScript. Within the markup, within the CSS conditional comments I think whatever works for you. but in JavaScript never ever, ever, ever test for the name of a browser or the version number of a browser or anything like that. Just do it like this. If you’re going to use a method, test for the method. So that’s my little rant about object detection. Who’s next?

Audience: [inaudible]

Jeremy Keith: That’s what I’m saying. You don’t look for, or it can call itself anything it likes.

Audience: [inaudible]

Jeremy Keith: Don’t talk to me about the BOM. I’m just here to talk about DOM Scripting. [laughter]

Audience: [inaudible]

Jeremy Keith: Or you just write an angry email to Håkon and say fix this. The BOM stuff, like I say, is a bit more cabalistic, a bit more like you have to remember Firefox doesn’t do that, Opera doesn’t do that. But, yeah, that all has to do with the Browser Object Model which maybe you shouldn’t be messing with in the first place. Why mess with the user’s browser? Anyway, another question. Ann, you have a question back there? Somebody pass a microphone. Who can reach first? Right in the middle of the walkway. OK, Ann make it good.

Ann McMeekin: Hi. I am like any person who is into designing or into the technology stuff. The add ons and possibilities of the software are fantastic but the thing that’s concerning me with my other hat or my accessibility hat is where do the fallbacks come in? Is there something that, if the method for generating content, is it something that can actually be used initially to hide content from use at the moment of screen readers that don’t support, that definitely don’t support the DOM being updated? Can it hide the content from visual view but leave it there for screen readers or other access technology? Why don’t they catch up?

Jeremy Keith: Yeah, now the whole thing about generating content I have very strict guidelines about myself, what I will and will not do. I will never generate important content using the DOM. If I want something that should be in the document generated and it’s important, I will do it in the document. I will write it in markup. That’s what markup is there for. The example I showed there with the cite attribute, I was taking existing content from one place in the document, creating a new piece of markup, and inserting it into a document but the information wasn’t new. The information I was just making clearer and those are the kinds of uses I’ll use for generating content using DOM, very small stuff. So, let’s say you’ve got a long document and there’s a whole bunch of headers throughout. So you’ve got a H1 the top and then throughout it there’s a whole bunch of H2s. You could use the DOM to create a table of contents on the fly. Loop through the document, get all the H2s, get their names, insert them at the top as a list, generate a list. Now I’ve generated markup. I’ve generated text but I haven’t generated content because technically that content was already there. I’ve just reused it and I think that’s the way to use generated content is the small stuff because, as you say, you can run into difficulties when you start doing it big. This becomes a real issue with Ajax when you start updating the document tree and then the screen reader device is there. That’s a whole debate for another day and it’s a big issue and something we all need to really think of I would say. Of all the things you can do with DOM Scripting, generating content is the most powerful and also the most dangerous and don’t be so quick to do it. Be very careful. All the things I did today were niceties, striping tables, showing the site attribute. They were nice little things to have. The fallback is it doesn’t happen here. Someone has JavaScript switched off, someone’s user agent doesn’t support JavaScript, they don’t get striping tables. They don’t get the cite attribute visible. That’s OK. It’s kind of like someone doesn’t support CSS, they don’t get the nice design. That’s my fallback. I’m not using DOM Scripting to do anything mission critical. Now it becomes a lot tougher when you get into Ajax and you’ve got to try to fall back but my own theories on that, I’ll just say the word Hijax. That’s all I’m saying. But I think we’re done and I see some shuffling so thank you all very much indeed for coming today.


Have you published a response to this? :