Do and don't do on web pages
I recently wrote about a hectic project I assisted in (Make a (visible) difference). That project had some major UI design and development problems. chances so happened that just now, I was called to another project with UI problems.
The interesting thing, or funny, thing about that project is that it had the same characteristics as the first one. Quite similar mistakes, the same problems and same errors.
Working on that one, the past week or so, lead me to this post. A list of "Do" and "Don't Do". I think I will find some "Under no circumstances - Don't do!".
This list isn't complete and doesn't pretend to be so. I might add stuff later if I'll remember them, and I will be happy to hear yours.
So let's get started.
Things to do
Use a CSS file.
I know this one sounds the most trivial one, but yet, you'd be surprised how many people and projects don't do that. The advantage of a CSS file, is huge. CSS files can be monitored for changes, can be documented easily inline, and separated then your source code.
Further more, a designer can do that, working on top of stub HTML file, and free your developer to do something else (and I don't mean coffee).
Use CSS inheritance.
CSS 2 (and older versions too), offer a very nice inheritance between class (CSS classes, that is). It isn't C# of course, but still, it better then writing the same lines of code over and over again.
Write default CSS classes with over-ride classes which over-ride only the needed elements.
Suppose you have a few tables, all the characteristics of all the cells are the same, besides the background. Use one class that will hold everything which is the same, and then just a few which will over-ride the one parameter which is different.
Example:
<style type="text/css">
.FormTable
{
width: 100%;
height: 100%;
margin: auto;
color: Gray;
}
.FormTableHeader
{
background-color: Black;
color: White;
}
.FormTableBody
{
background-color: Silver;
}
</style>
And here's the HTML to go with that:
<table class="FormTable">
<tr>
<td class="FormTableHeader">Title 1</td>
<td class="FormTableHeader">Title 2</td>
</tr>
<tr>
<td class="FormTableBody">Value 1</td>
<td class="FormTableBody">Value 2</td>
</tr>
</table>
Use HTML entities to differentiate styles
In the above code sample you can see that I'm differentiating between the table's header to it's "data" (or body). If I would use HTML entities (as I should, by the way) I could have saved the extra "Class" directives, and just set the style to the table. This will produce a shorter code, ad easier to read.
Another plus is that your page will now be more accessible.
Example:
<style type="text/css">
.FormTable
{
width: 100%;
height: 100%;
margin: auto;
color: Gray;
}
.FormTable th
{
background-color: Black;
color: White;
}
.FormTable td
{
background-color: Silver;
}
</style>
<!-- ... -->
<table class="FormTable">
<tr>
<th>Title 1</th>
<th>Title 2</th>
</tr>
<tr>
<td>Value 1</td>
<td>Value 2</td>
</tr>
</table>
Document your CSS file
As with any code file, there's almost no such thing as "too much documentation". Use comments to separate different segments of the file. Describe shortly where in the site (or page) this class (or classes) goes. and so on and so fourth.
Use different files for different media types.
One of the things I see many times is page that uses the "onBeforePrint" event, to hide data that shouldn't be printed and/or to display data that should.
Why do you do that? (rhetorical)
Cascading Style Sheets can be defined for different media types using the "media" attribute in the declaration. It's there. It's working. Use it(!).
Define the same class in two different CSS files. One file will be used for the screen, and the other for print. In the print version, set the "display" attribute to "none" for those elements you don't want to display, and to empty string for those you do (and of course, vise versa).
Example: I have a div that contains page numbers.
My "Print CSS File" have this:
.PageNumbers
{
font-family: Courier;
font-size:small;
}
While my "Screen CSS File" have that:
.PageNumbers
{
display: none;
font-family: Courier;
font-size:small;
}
And on the page, the declaration looks like that:
<link href="Print.css" rel="stylesheet" type="text/css" media="print" />
<link href="Screen.css" rel="stylesheet" type="text/css" media="screen" />
Be consistent
If you decide that your style are in an external file, keep the same method thru out the project. If you decide to use inline "Style" element (inside the HTML file), use the same structure on all pages. Make sure that there're no surprises, no style that went externally some how, etc. If you use inline style directives, use just them.
Things you shouldn't do
Don't repeat directives in different class
If you're using the same fonts in all of your pages, and the only thing changes is the size or color, why do you repeat it in each and every class? Just assign it in the "body" directive so it'll become the default.
Don't assign a classes with the same name to different HTML elements
In the project which triggered this post, I saw this code:
a.Link
{
font-size: larger;
text-decoration: underline;
color: black;
}
span.Link
{
font-size: small;
color: navy;
}
The problem with that, is that one can easily think that "Link" is a general class that can be applied to anything. How ever, applying it to a "div" wouldn't produce nothing.
See the item "Use HTML entities to differentiate styles" for the correct way to achieve the above.
Don't separate the CSS file to different files just to keep it short
Very very bad move to do that. It wouldn't take too long before you'd forget which file occupies which class, and where did you put it. Not long after that you'll start to write duplicate classes, and if you would be lucky you wouldn't give it the same name.
I often see something like that in the code:
<link href="StyleSheet1.css" rel="stylesheet" type="text/css" />
<link href="StyleSheet2.css" rel="stylesheet" type="text/css" />
There's no real reason to separate them. When you HAVE to do it (i.e. when you're using some external style sheet that is only used for a special control you've downloaded), give the files a logical and understandable names.
Furthermore, make sure you're not repeating class names (one way, is to prefix all the classes, in the external file, with something descriptive).
Don't use different CSS files to the same site when it uses two applications, or folders.
Another common issue. You have a huge project, you've divided it to separate applications on your server, all of them uses the same colors and styles, but you have a style sheet on each and every application.
And now comes the day when you client wishes to apply his new branding colors. Oops... Now you need to change 4-5 files.
The solution is easy: Create an application that will hold just the CSS files (and the images too, why not?). In the "link" directive just use an absolute path, instead of relative.
Works like a charm, trust me.
Another advantage you might earn, is the ability to push this application to a less secure zone, and apply caching on that one alone. You wouldn't believe the performances change you'd earn.
Don't change styles from code behind (ASP.NET)
Unless you really really need it, don't change the style from the code behind. Change CSS classes, but not styles.
I saw this line in a code behind:
lblTitle.Style.ForeColor = "#ebebeb";
Now, what's the problem here? It isn't consistent. A developer might look for all the places a certain class appear, and not for the specific color; especially if the re-work is being done after quite a while when there's no style guide to look at.
Don't over-ride the same class over and over
If you use inline styles to over-ride something in your class (i.e. fore color for unique cells), make sure you're doing it only once. Or twice, the most. If you see that you need to over-ride the same thing over and over, just write a new class for it.
Don't use StringBuilder to build HTML content (ASP.NET)
Why not use all the nice elements from the "System.Web.UI.HtmlControls"? Can't find what you're looking for? Use "GenericHTMLContol". Here's an example of how to build a small table:
HtmlTable table = new HtmlTable();
HtmlTableRow tr1 = new HtmlTableRow();
HtmlTableCell th1 = new HtmlTableCell("th");
th1.InnerText = "Header 1";
HtmlTableCell th2 = new HtmlTableCell("th");
th2.InnerText = "Header 2";
tr1.Controls.Add(th1);
tr1.Controls.Add(th2);
HtmlTableRow tr2 = new HtmlTableRow();
HtmlTableCell td1 = new HtmlTableCell();
td1.InnerText = "Value 1";
HtmlTableCell td2 = new HtmlTableCell();
td2.InnerText = "Value 2";
tr2.Controls.Add(td1);
tr2.Controls.Add(td2);
table.Controls.Add(tr1);
table.Controls.Add(tr2);
Things you should never (ever! under no circumstances) do
Do not produce styled HTML from the code behind and just write it to the page.
One of the elements on the page, refused to let go of some horrible red color it had in the background. The developers looked at the markup, and then on the style sheet, and couldn't find the place it getting its color from.
A deeper look, found a few lines that looked like that:
StringBuilder sb = new StringBuilder();
//...
sb.Append("<tr><td bgcolor=\"#ee001c\">" + pageTitle + "</td></tr>");
Since the developer didn't knew the color name, he couldn't find it. At least not easily.
Look also above, at: "Don't use StringBuilder to build HTML content (ASP.NET)".
Do not use JavaScript to control ASP.NET controls' styles (or functionality, for that matter).
For me, I think this is the biggest "never ever" rule. In the last project I found a huge JavaScript file that was in charge of some grid's functionalities, such as highlighting the background, expanding details, and even sorting.
The amount of code on that file, just to find a link inside one of the cells was unbelievable. There's no reason, not one, to do that.
Using such method decreases the chances of maintaining the site, to tiny shred.