Logo for "Nota Bene / non-blog" goes here.

Along with navigation links. NB main page

Web Color Pallette

Iíve just read Bulletproof Web Design by Dan Cederholm, in which he shows example web pages with unique layouts and bad code, and recasts the same effect using semantically-meaningful XHTML markup with the effect applied using CSS 2.1.

After seeing the “RTE Colour Pallete [sic]” used by a forum, Iím inspired to do the same.

A note on spelling: No dictionary contains the word as originally spelt. Of the corrections supplied by onelook.com, ďpalletteĒ was listed before ďpaletteĒ. The latter is more common. The former is a closer match, being one letter different instead of two. I like being contrary while still being correct—see ďspectacleĒ as described by an art teacher long ago: itís what makes the ordinary into art.

The Offender

The item is part of a free rich text editor, credited at the top as

<!-- Web Wiz Rich Text Editor ver.  is written and produced by Bruce Corkhill ©2002-2004
     	If you want your own Rich Text Editor then goto http://www.richtexteditor.org -->

It is 25,396 bytes in size. The W3C validator won’t even touch it without a little help, and then reports over 800 errors. HTML Tidy is more forgiving, generally reporting on what a browser might make of it and continuing. It finds 1045 HTML errors that it (and hopefully browsers) can automatically fix or put up with. Thatís nearly an error every 25 bytes, and averaging nearly three per line of HTML!

Syntax Checking

A lot of the errors are simply multiple occurances of the same basic mistake. Having 252 nearly identical lines of HTML is an issue in itself that we’ll come back to. For now, look at one of the lines. The rest are all the same except for the number shown twice toward the beginning of the line, 000000 in this particular case.

  <td id="#000000" bgcolor="000000" height="11" width="11"><img width="1" height="1"></td>

You might be interested to know that this line has 5 HTML errors on it, reported by HTML Tidy:

The Wc3 validator doesn’t find the problem with bgcolor, because the SGML parser is not checking constraints not present in the DTD. The DTD just says it is a string, as it doesnít have an easy way to enumerate the 16 color names and the syntax for RGB colors. The official specification explains it in a comment, so it is unknown to the formal DTD interpreter.

The bgcolor is easy to fix by adding the missing # character. The ids are fixed by removing the # character, but ids canít begin with a digit either so I prefixed them all with ďcolor_Ē.

Each IMG tag complains about missing src and missing alt. The alt tag is required for explaining what the picture is if the browser is not loading pictures. But missing the src attribute‽ What is an image without a file containing the image? Not that a 1×1 image could be very interesting anyway. The size of the table cell is already specified, and the color of that cell is the cellís own bgcolor, so what good is the image? Since it doesnít even exist, it can’t be doing much. So I deleted the entire IMG tag, and 508 errors with it.

The Javascript code uses the element’s id as the color to pick, so having the same color swatch in more than one place gives us duplicate ids. In fact, that is the only thing the id is used for. So why canít the code use the actual bgcolor of the item instead of the id? Perhaps in the distant past it was not easy to determine the bgcolor property, with different browsers having different object models and all. If that were still the case, a fix would be to add a nonce to the name and parse out the color number. But the whole concept is wrong if building to the standard, so Iíll take out the id attribute altogether.

Finally, the page looks exactly the same (it doesn’t work though, since the Javascript needs to be updated to match), is down to 16K, and only has 8 errors left. The remaining errors are:

The missing script type is "text/javascript". Since Iím not sure what a marginwidth is, I'll leave off showing the portable/standard way to write that. The margins around the entire panel will be specified in CSS, and might even be better off controlled by the parent documentís IFRAME.

The bordercolor attribute can be written as the border-color style property. The existing attribute style="none;" doesnít make sense as that is not valid CSS. Finally, the table height is simply removed, since the height is specified in every element anyway. The height of the table ought to be the sum of the heights of its rows and borders, right? If it is something else, then I donít see the point of specifying the latter.

At last, it is valid HTML, is less than ⅔ the size, and looks exactly the same. You can do a diff to find all the changes in detail, including a few I didnít elaborate on.

Improving The Structure

The HTML now looks like this:

<table border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%" style="border-color:black">
 <tr>
  <td bgcolor="#000000" height="11" width="11"></td>
  <td bgcolor="#000000" height="11" width="11"></td>
  <td bgcolor="#000000" height="11" width="11"></td>
  <td bgcolor="#000000" height="11" width="11"></td>
  <td bgcolor="#003300" height="11" width="11"></td>
  <td bgcolor="#006600" height="11" width="11"></td>
  <td bgcolor="#009900" height="11" width="11"></td>
  <td bgcolor="#00CC00" height="11" width="11"></td>
  <td bgcolor="#00FF00" height="11" width="11"></td>
  <td bgcolor="#330000" height="11" width="11"></td>
  <td bgcolor="#333300" height="11" width="11"></td>
  <td bgcolor="#336600" height="11" width="11"></td>
  <td bgcolor="#339900" height="11" width="11"></td>
  <td bgcolor="#33CC00" height="11" width="11"></td>
  <td bgcolor="#33FF00" height="11" width="11"></td>
  <td bgcolor="#660000" height="11" width="11"></td>
  <td bgcolor="#663300" height="11" width="11"></td>
  <td bgcolor="#666600" height="11" width="11"></td>
  <td bgcolor="#669900" height="11" width="11"></td>
  <td bgcolor="#66CC00" height="11" width="11"></td>
  <td bgcolor="#66FF00" height="11" width="11"></td>
 </tr>
 ...

Recall the earlier musing on the over-constrained table height. If every cell has the same height, doesnít that mean that each row height is the height of the cells, too? So why bother putting the same height on every cell? Put the height on the row instead.

Certainly writing

 <tr height="11">
  <td bgcolor="#000000" width="11"></td>
  <td bgcolor="#000000" width="11"></td>
  <td bgcolor="#000000" width="11"></td>
  <td bgcolor="#000000" width="11"></td>
  ...

is an improvement, it is not necessary to specify the height of all 12 rows individually as the same 11 pixels. Instead, use CSS to say “In this table make each row 11 pixels high.” once.

That canít go in a style attribute of the TABLE element, but has to go into the CSS rules for the page. It is a good habit to get into anyway, to separate the style from the HTML. You see, itís not just cleaner, it is more powerful. You can only attach a style attribute to the element to which it directly applies. But CSS rules can be general and automatically find everything it applies to. To make it work, I gave the TABLE an id. Here is a real use of an id!

table#pal  TR { height:11px; }
...
<table id="pal" border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" width="100%" style="border-color:black">

As an aside, I originally tried to write table#pal > TR, meaning only those TRs that are direct children of my table. That is a habit to prevent runaway formatting: in more general use, I donít want the rule to apply to the text (which may itself contain tables) within the item. But, TR is not directly contained in the table, despite the way the HTML source code looks. There is a <TBODY> that is omitted from the source but still there in the DOM. So the rule would have to be table#pal > * > TR, but since this is a special table and not a general-purpose style sheet, itís not worth the trouble.

Not Pixel-Perfect Identical

Looking at the html files in their own windows at some arbitrary size, they certainly look the same at a glance. But put them in their precisely-sized IFRAMEs side by side and there are some slight differences visible.

Side-by-side, you can see that the upper section and the main pallette table are both shorter than the original, resulting in extra room at the bottom when the frame is set to exactly 165 pixels high. Less obvious in its frame but apparent if you looked in a separate window (or can resize IFRAMEs with the mouse) is that the original will resize vertically to fill the room, while the new one keeps the same row height even if given more room.

The upper section is a bit of a mystery. Nothing changed in the first table or its contents. Yet it is one pixel shorter than it was originally! The problem lies in line 57:

  ...<div style="background-color: #000000; padding: 1; height: 15px; width: 40px">...

The Firefox error console tells me that there was an error parsing the value for the padding property so the declaration was dropped. That is true, 1 is not a legal value. It was intended to be 1px. Ignoring it made it zero instead. Yet it was not reported as an error in the original file, and took the padding as one pixel! The difference is the presence of the <!DOCTYPE… declaration. Without the DOCTYPE, the browser uses a ďquirksĒ mode, which is intended to render things the way it worked in browsers that existed before good standards were written. If you put the DOCTYPE into the original file you get the same behavior with the padding, so the height of the upper portion matches that from the new code. But if you try that youíll see that nothing else works, and the main pallette table is all black! Thatís because the bgcolor is missing the # character. The quirks mode guessed what was meant. Note that the behavior details can vary from browser to browser and between versions as well. Thatís the problem with banging on it until it looks right rather than following the standard and removing all errors.

The size of the main pallette table is an interesting case, too. Although the original file states that every table cell has a height of 11 pixels, inspecting the results shows that some of them turned out to be 12 and some 11. With the new code, every row was sized to 11, as specified. This is caused by the third thing noticed, that the original resizes vertically. As presented in the IFRAME, it has already been resized, stretching a little from what was specified.

According to the HTML Specification, the deprecated height attribute supplies user agents with a recommended cell height. Nothing else is said about row height, so what the browser does is really whatever it wants. That may be why there were the meaningless IMG tags in the cells; perhaps some browsers of the vintage would reduce the recommended height if the cell was seen to be empty, and using a &nbsp; wasnít always working either—bang on it ítill it works, and hope for the best moving forward.

Using CSS to specify the height has a well-defined meaning, that is explained in some detail. Specifying the height as 11 pixels does exactly that, without surprises. I like the self-sizing table, so letís see what CSS can do in that respect. The table should fill the room available, with no mention of any other height or width. Unfortunately, the CSS2.1 specification does not do that. It doesnít make you guess about it either. It quite clearly states, Any other value [than auto] is treated as a minimum height. CSS 2.1 does not define how extra space is distributed when the height property causes the table to be taller than it otherwise would be. Note. Future updates of CSS may specify this further.

Experimenting with using a height expressed in percentage did not prove fruitful. Even if that worked, the border has a problem, since that is sized in pixels and you canít express the box outside dimensions, only the content dimensions. Rather than going to great lengths to convince at least one browser to resize vertically, Iíll stick with a fixed height of 11 pixels. It will be simple to change the CSS property, in one place, using Javascript based on the available size.

Onward with Structure Improvements

As long as we have a separated style for this specific table, I might as well move the rest of the junk into there. The attributes border="0" cellpadding="0" cellspacing="0" bgcolor="#000000" become CSS properties. The cellpadding corresponds to the padding on the individual cells, which is a property of each cell, not of the whole table. The cellspacing property corresponds to the border-spacing property. We donít have to worry about subtle semantic differences because we just want them all to be zero. The tableís background color does not matter because it is completely covered with elements and their borders.

table#pal {
	empty-cells: show;
	border: none;
	border-spacing: 0px;
	}

table#pal TR {
	height: 11px;      /* update this using JavaScript, based on available room. */
	}

table#pal TD {
	padding: 0px;
	width: 11px;
	}

Finally, just because it is so long, the size of the download can be further reduced by eliminating hundreds of optional closing tags. This brings the file down to under 9K, which is a fraction of the size of the original.

Adjusting the Javascript

Because of an early change (fix, actually) in the HTML, the Javascript needs to be updated to match. The Javascript uses the text of the id attribute exactly as-is as the color string. This is not right for several reasons: Idís have to be unique, and they have to be syntactically correct. Instead, Iíll simply use the background color from the cell.

Several places the original code uses this.id to obtain the color string. An easy change that offers good maintainability and future enhancement is to make a function that encapsulates the work. The existing code simply needs to have this.id replaced with get_swatch_color(this).

Onward

Further improvement would involve refactoring the whole design. That will be the subject of another page.