Common HTML mistakes

Some mistakes developers often make when writing HTML code, and how to fix them.


Over the years I have been guilty, like many others, of overcomplicating things when it comes to writing Web applications. In this post, I’ll explore some parts of HTML that developers often overlook, choosing to use more complex markup, hacks and/or JavaScript to achieve the same effect instead.

Form field labels

If you want to create a label that is associated with a form field, how do you go about it? The most common approach seems to be using an id attribute:

<label for="first_name">First name:</label>
<input name="first_name" id="first_name">

Everyone knows that IDs should be avoided if possible. Yet, I see this all over the Web. This is also the way Bootstrap works out of the box. For some reason, people don’t seem to be aware of the following approach:

<label>
First name:
<input name="first_name">
</label>

This is perfectly valid HTML, it associates the field with the label (so clicking on the label will focus the field) and if you need to separate the label text from the field you can always wrap that text in another element.

Submitting a form with the enter key

So you have a form, and you want it to be submitted when the user hits the enter key? If I had a dollar for every time I’ve seen JavaScript code catching keyboard events and checking the key code for the enter button like this:

if(e && e.keyCode == 13) {
form.submit();
}

The thing is, if you have built your form correctly, you should never need JavaScript to achieve this. Hitting enter on any form field (except a <textarea>, for obvious reasons) will submit the form by default, as long as your form has a submit button, i.e. either an <input> or <button> element with the type attribute set to submit. Where developers commonly go wrong with this is that they don’t use a <form> tag at all, typically using some JavaScript witchery to submit the data via Ajax with no fallback if JavaScript is disabled.

Form validation

Everyone knows that you shouldn’t rely on client-side form validation, for two main reasons:

  1. Security — client-side validation is easy to bypass.
  2. Graceful degradation — if your user has JavaScript disabled, the validation will be skipped altogether.

So many people seem to get the second part wrong, though. I’ve seen plenty of examples where developers have removed the submit button from a form altogether and replaced it with a regular button, binding to its click event to perform validation and then submitting the form (or in some cases a completely different form altogether, typically comprising a series of hidden fields). If you do this, your form is useless for users with JavaScript disabled as there is no submit button.

If you are validating a form with JavaScript, make sure your form has a submit button, and bind to the submit event of the form itself. If the validation fails, use the preventDefault method on the event object and the form will not submit, for example:

var validateForm = function(e) {
if(field.value.length < 1) {
e.preventDefault();
alert("Validation error message");
}
};
myForm.addEventListener("submit", validateForm, false);

Better still, use native HTML form validation to implement client-side validation with no JavaScript at all.

Option groups

The <optgroup> element is one that you don’t see used all that often. This element allows you to group the options in a <select> element. This is great for creating a hierarchical drop-down list. Often times, this solution would be perfectly acceptable, but instead we rush to implement multiple drop-down lists in a dependency chain — e.g. when you select from the first list, an Ajax request fetches the options for the next list from the server.

Note: Unfortunately, you can only use a single level of nesting with the <optgroup> element — that is, you can’t have an <optgroup> element within another <optgroup> element.

The <optgroup> element itself is not clickable, but merely acts a grouping label. The <option> elements within it will be indented to indicate the hierarchy. An example of using the <optgroup> element:

<select>
<optgroup label="Fruit">
<option>Apple</option>
<option>Banana</option>
<option>Orange</option>
</optgroup>
<optgroup label="Vegetables">
<option>Broccoli</option>
<option>Carrot</option>
<option>Parsnip</option>
</optgroup>
</select>

Note that you can also use this on multiple selection drop-down lists.

Scrolling to an element

If you want to allow a user to click on a link to navigate to a different part of a page, what do you do? I’ve seen plenty of examples where jQuery is used to animate scrolling to a specific element, using code such as:

$("#button").click(function() {
$('html, body').animate({
scrollTop: $("#elementtoScrollToID").offset().top
}, 2000);
});

This is nice and pretty, and using JavaScript to animate the effect is perfectly acceptable. But in so many cases, clicking on these links when JavaScript is disabled does nothing at all. The worst part is that implementing this functionality is so simple using named anchors:

<!-- Link --!>
<a href="#content">Scroll to content</a>
<!-- Named anchor --!>
<a name="content">...</a>

Sure, this won’t have any fancy animation, but at least it works. And nothing’s to stop you applying the jQuery to this link for those who have JavaScript enabled.

Table sizing

I’ve seen some phenomenally bad table markup in my time, usually trying to achieve a flexible sizing model for columns. The simplest and most effective way to size your tables is as follows:

  • Make your table width 100% — i.e. it should take up all of the horizontal space available within its parent element.
  • If you don’t provide any column widths, the browser will automatically size your table based on its content.
  • If you want to specify fixed widths for columns, identify at least one column that can have a variable width — the width of this column will then be flexible based on the size of the parent element (which may increase or decrease in size when the window is resized, for example).
  • If you want to specify percentage widths, either specify a percentage value for all columns that adds up to 100%, or leave two or more columns without a width — these columns will then have a flexible width based on the remaining horizontal space available.
  • Use the <colgroup> and <col> elements to define the column structure of your table. Define the width of columns using CSS on the <col> elements, rather than on <th> and <td> elements within your table.

The guidelines above won’t suit all scenarios, but pretty much every HTML table I have created in recent memory follows this pattern and works very well.

Summary

At a guess, I’d say most Web developers are guilty of at least some of the mistakes I’ve covered in this post. The funny thing is, in most cases, the correct solution is often not only easier to implement, but the code is also much cleaner and easier to maintain. So let’s help not just our users, but also ourselves, and stop overcomplicating things unnecessarily.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.