Posts Tagged ‘css’

Be Lazy, Let the Browser Do the Work for You

Friday, April 11th, 2008

Imagine you work for a company that has an online product catalog and that your job is to maintain the product images. Now imagine your boss comes to you and says, “here’s a list of a thousand products that need to have ’40% off’ put on them, and we need it for tomorrow, noon.” So you work all night only to have him come to you in the morning and say, “did I say forty? I meant fifty.” Now you’ve got till noon to update a thousand images, go! The more efficient way to handle that situation would be to have a macro, or a template, or some other automated way to either update those images or just superimpose the discount on each of those images.

The moral of the story is, work smarter not harder. When a computer can do the work for you, let it. There’s no glory in doing it yourself. This same moral can be transposed to front-end web development.

There is this thing called “flow” in the browser environment. Think of it as a really crude physics engine. All of the elements rendered in a page are initially a part of the document’s flow. When an image within the flow is enlarged, the text adjacent to it gets shoved over. When it’s reduced, the text is drawn closer. This is good because you don’t need to worry about positioning the text when playing with the size of an image. It’s handled automatically by the browser.

Now imagine if you were to break the flow and opt to position everything yourself. Maintenance would become a nightmare. Sadly this often happens when people get their hands on CSS and don’t know how to properly leverage it. Instead of letting the browser handle the positioning of the elements and just nudging them in place with a few strategically placed rules, they opt to brute force everything into position. Of course, what happens when an image size changes? or a bit of text goes longer than anticipated? Everything breaks. Then they’re up all night fixing a ton of style sheets.

The thing to remember with CSS is: less is more. Really, the cascade works best in conjunction with document flow. Restraining either too much defeats the purpose and leads inevitably to unnecessary headaches.

The C in CSS Stands for Cascade

Thursday, April 10th, 2008

People have a propensity to see a one-to-one relationship between an element and its look. In other words, they see an element as being styled much like if you were to paint something with a paint brush, a one-off job. At least that’s the way things were circa the early 1990′s with font tags and inline styling attributes such as bgcolor. This meant a lot of work to style a page, and once it was done, it was on to the next page and a whole lot more work. Of course work isn’t a bad thing, and nobody can fault you for working hard. But working needlessly? That’s another story.

In 1994 Håkon Wium Lie and Bert Bos collaborated on Cascading Style Sheets. The idea was that styles could inherit or cascade from one another. This marked a fundamental shift in the way an HTML document could be styled. It was now possible to affect the look of all of the elements of a certain type in a page and throughout a site with just one rule.

p {
    color: red;
}

This rule for example would colour the text in all paragraph elements red. If, however, you wanted one particular paragraph’s text to be coloured blue, you could assign it an ID and target it specifically.

p#intro {
    color: blue;
}

Here the text of the paragraph element with the ID intro will be coloured blue. Note however that all paragraphs are coloured red and only one is blue. The latter is originally red as well but is then overridden by a more specific rule and becomes blue. Hence the cascade. Taking advantage of this sort of broad stroke styling allows for very easy maintenance and updating of a site.

It’s therefore tragic when an old school one-to-one mentality is applied using CSS. Take for example this bit of code:

p#welcome {
    color: black;
    font-size: 115%;
}

p#about {
    color: black;
    font-size: 115%;
}

p#sale {
    color: red;
    font-size: 115%;
}

p#contact {
    color: black;
    font-size: 115%;
}

Here we have four style rules that do pretty much the same thing. The only difference is that the paragraph with the ID sale is coloured red. This CSS would be much more efficient if it took advantage of the cascade.

p {
    color: black;
    font-size: 115%;
}

p#sale {
    color: red;
}

Note how the sale paragraph doesn’t have a font-size rule. That’s because it inherits its font size from the basic rule that applies to all paragraphs. This makes maintenance much easier.

So remember: leverage the cascade, it will make life a lot easier for you when maintaining (and even debugging) a site.

When Browser Detection Isn’t a Bad Thing

Wednesday, April 9th, 2008

One of the pillars of the Web Standards movement–reinforced in Zeldman‘s seminal Designing With Web Standards–is the idea that browser detection is a bad thing and should be avoided. As with another idea spawned at around the same time, that “tables are bad”, it isn’t wholely true. There are situations where tables are good and even appropriate, likewise there are situations where browser detection is appropriate.

Old School: Browser Detection

Traditionally, browser detection was used for code forking in order to support two or more highly incompatible browsers. So if Netscape 3 was detected, one block of JavaScript was executed, and if Internet Explorer 3 was detected then an entirely different block of JavaScript was executed. The trouble with this model was, and still is, that it’s expensive to maintain. To say nothing of it being error prone. It also doesn’t do a great job of anticipating future versions of browsers.

An example of this was on the Microsoft Games site. Visiting it with the new beta of Internet Explorer 7 would cause the site to hide its content and display a message asking that the visitor please upgrade to Internet Explorer 6 or newer.

New School: Feature Detection

The alternative to browser detection is feature detection. Feature detection means checking to see if a feature exists prior to implementing it. So for example, if a developer wanted to use getElementById, he’d first check for it like so:

if (document.getElementById) {
    var foo = document.getElementById("foo");
}

The New Browser Detection

This works great, unless a browser says it can do something and actually can’t. In other words, if browser X implemented getElementById but it was buggy, it would still pass the test but fail in the code. This is where browser detection comes back into play, but not like in the bad old days. No, this time around browser detection would be used to target and fix–or deny–a feature in a browser known to have issues with it.

An example of this sort of thing would be Safari 2.x’s trouble with cellIndex. Normally, checking a table cell’s cellIndex property would return a number representing its position within a row. Not so with Safari 2.x, in its case cellIndex always returns 0. So testing for cellIndex doesn’t help since it is there, it just doesn’t work.

There are also edge cases that simply can’t be tested for. For example, background images inside an animated iframe in Internet Explorer 6 will flicker throughout the animation sequence. There is no way to do feature detection in this case, however the issue is known. So, the solution may well be to simply test for the browser and if Internet Explorer 6 is detected, to simply deny it the animation and just snap to the last frame.

Summary

So, the new browser detection if you will, is all about damage control in cases where features can’t be detected yet problems are known to exist. I those cases, specific versions of specific browsers are targeted and dealt with appropriately. The mechanism for this may be in the form of conditional comments or JavaScript code written for the purpose.

Worry Free Web Development

Sunday, March 23rd, 2008

Yesterday I gave a presentation at Coder’s Saturday called Worry Free Web Development. Here are the slides.

Understanding and solving the JavaScript/CSS entanglement phenomenon

Wednesday, February 14th, 2007

About a year ago I wrote “The graceful degradation myth” in which I talked about the entanglement phenomenon that occurs when you mix JavaScript functionality with CSS “initial states”. By that I mean, if you’ve got a block of content that is initially hidden via CSS (i.e. display: none;) and is only made visible through JavaScript functionality (like an onclick event), you run the risk of barring access to that hidden content to visitors who don’t have JavaScript running on their browser–if you don’t do it right that is.

Since I wrote that post I came up with a technique that solved the problem (as well as the “flicker” problem that occurs with some fixes). This past week I came up with what I believe is an even better solution which I plan on using in upcoming projects. I’ll share both with you here in this post.

How to layer

Before I get to the solutions, I’d like to touch briefly on the subject of the three layers of separation. Those being of course content (HTML), presentation (CSS), and behaviour (JavaScript). Most people in the web standards community know of these, but what I seldom hear is the idea that one layer should never break the other. See, you start with HTML on top of which you place CSS and then comes JavaScript (if you’re using all three that is, though the sequence of the last two is debatable). When you go from CSS to JavaScript you should never do something in the CSS that relies on the JavaScript. In other words, dependency should be unidirectional–downward. A layer should only be dependent on one that it’s applied to, not the other way around. Therefore, when implementing a show/hide mechanism in the behavioural layer, you should do so in a way that still allows the first two layers to be accessible should the third not be available.

The reason I just covered the three layers of separation is because a lot of JavaScript implementations break the rule of non obstruction. A lot of implementations will hide content in CSS and only make it available through JavaScript, thus tangling the two layers together and breaking the separation model. The following solutions avoid this phenomenon.

The first solution

Create a CSS file that will contain all of the “initial state” rules for your behavioural layer. So for example in the case of a flyout menu system, if all sub-menus with the class name “flyout” are to be initially hidden when the page loads your CSS file would contain the following rule:

.flyout{display: none;}

Then, link the CSS file to your page using JavaScript. That way, if JavaScript isn’t available the CSS file never gets loaded and the rule never gets applied. Thus the content remains visible and accessible. The way I used to do this was with the following line of JavaScript code in the <head> of the page:

document.write("<link rel='stylesheet' href='initial_states.css' type='text/css' \/>");

The problem with this technique is that I’m using document.write() which is bad. It’s bad because it ties the instruction to a specific place in the document, it’s archaic and isn’t supported in pure XHTML implementations (such as this site that’s delivered with the application/xhtml+xml MIME type).

The better solution

The better solution builds on the basic concept of the original but does it without document.write(). This time your initial state CSS rules will look like this:

body.hasJS .flyout{display: none;}

And you can go ahead and load the CSS file in the traditional way without using JavaScript. The key rather is to assign the “hasJS” class to the body element through JavaScript. If JavaScript doesn’t exist, it doesn’t get set and the rule doesn’t get applied. You can still keep the initial states in a separate file if you’d like but it isn’t necessary. So long as the rule exists somewhere. The simplest implementation of this technique is to have the following line of JavaScript code on the first line inside the body element:

document.body.className += "hasJS";

The reason for this is because doing it in an onload event will cause a flicker where the page will load, then the content will be hidden. This way, the class is applied before any content is parsed. There are of course better ways of applying the class name (such as an addClassName() function that only adds the class name if it doesn’t already exist).

I haven’t fully tested the better technique on a wide variety of platforms as I have with the standard one, so if you have any success with it, please let me know.

I’ve mocked up a quick example page so you can see it in action.