Skip to main content

Top 10 Most Common Mistakes for Web Developers

Did you forget to use the new HTML5.2 elements like `<dialog>` and `<main>`? Check my list of things to go over to make sure you've got your HTML down pat.

I was viewing slack today, and I was again reminded of some of the things which I find very distasteful in web apps. It's now time to list them, and why we, as developers, should care:

1. Search without input[type="search"]

When you have an input that serves to search, then you must always make sure of two things:

  1. The parent element has the role="search" aria-role landmark
  2. The input is of type search

The former is vital for screen readers.

The latter ensures that the keyboard that appears on mobile devices is correct, and has the "search" button replaced with the "enter" button.

The irony here is that Slack's page was in HTML5 (as per the doctype). Perhaps all their mobile users are using the native Slack app?

Side-note: it's usually a good idea to surround your <input type="search"> with a <form role="search"> for much improved accessibility.

2. Tooltips without title attribute

I am seriously blown away at how many times developers will just go with something like Bootstrap's tooltip, or some other javascript library

3. Definition Lists without dl

There are so many occasions where I find markup that is explaining a list of terms and definitions, yet the developers refuse to use the proper dl element; instead, they'll use ul.

ul has a different semantic meaning than dl; whereas dl indicates a list of definitions and terms, ul represents a generic list. When you are adding content to a page that is a list, it makes every bit of sense to indicate the nature of that list.

Of course, I undertsand the limitations of dl; some developers are right in pointing out that the un-nested hiarchary of dl is limiting. For example:

    <dt>My term</dt>
    <dd>My definition</dd>

The above can be contrasted with the hierarchichal, less semantic version:

<ul class="definition">
    <li class="definition-item">
        <span class="definition-item-term">My term</span>
        <span class="definition-item-definition">My definition</span>

Notice how the definition term and definition are contained under the parent .definition-item? That makes for easy styling.

The unsemantic version allows better styling, and more customizability of the appearance:


        text-align right
        & ~ &
            margin-top 1em // usage of combinator
            float left

Contrast this with a more hacky solution required by the more semantic version:

        float left

This would seem fine, but what happens when you combine several dt and dds together?

It seems we have to fix this with a clearfix... but ewww, I hate clearfixes:

            clear left

So I digress: we must decide, as developers, which we want: accessibility, or prettiness; I tend to vote in favour of the former.

4. Abbreviations with no abbr

This one is pretty self-explanitory: when you do have an abbreviation, just use <abbr>. I often see people forget to include title; remember that title serves to indicate what is meant by the abbreviation.

<abbr title="Single-Page Application">SPA</abbr>

It's also a good idea to use cursor: help on the abbr element and, optionally, to let the abbreviated text stand out a little. I, personally, like to add a dotted underline with italic text:

abbr {
    font-style: italic;
    border-bottom: 0.1em currentColor dashed;
    cursor: help;

But I digress that, often, it's hard to come by use cases for abbr.

5. Progress bars with no progress elements

How many times have you seen a series of <div>s used to simulate a progress bar? Many, I imagine.

<progress> gives us a meaningful way to indicate progress of a task, while using the native loading bars in the given OS. When this page is loading, you will see an example. Or here.

Also worth mentioning there is a meter element, which can also be useful for displaying measurements.

6. Inline Styles and Javascript

It's a rather unfortunate day today, in which we live, where libraries and frameworks like angularjs and reactjs are commonplace. But that doesn't give you the right to litter your app with ng-click, onclick, onchange, or style attributes. Just stop it; no one wants to read through an entire document of offuscated logic and markup code at the same time.

7. Modals

OK, let's just be honest here, that modals do have a time and a place. Most notably, a modal makes sense when the user performs a non-revokable action such as:

  • Deleting an item (permanently)
  • Updating content
  • Performing transactions

It makes sense to ask the user if they are certain they want to continue. But I want to suggest an alternative approach which does not block the UI.

Attempt 1: Use alerts Instead

In many cases, using the alert can be a far more effective means of conveying a modal. Modals should be used for operations that are blocking. These include:

  • Confirmation messages
  • Error messages
  • Propmt Messages

Using non-blocking modals can often confuse the user, misleading him/her to wrong terms of context. Modals were initially intended to block operations from continuing. For example, a user deleting a blog post to be an action that is irreversible, and it makes sense to confirm that this is indeed what the user wants to do. A common mistake is to use a modal for creation of an item, for example a blog post. Some developers might be lulled into thinking that this makes it seem simpler to create a blog post, when in fact, users may become confused about where the new post is coming from. A better approach would be to simply show the fields required to create a blog post, within the context.

Likewise, for alert messages, you can simply use window.confirm:

window.confirm("Changes made are permanent.  Are you sure you want to continue?")

However, using alert, window.confirm, and other blocking methods has its downfalls:

  • The user may feel violated, as their progress is interrupted
  • The options presented to the user: OK and cancel don't offer much context; javascript APIs provide no method of customizing this button text
  • The javascript API for window.alert and window.confirm offer no customizability for the content within the modals, aside from generic text; further to thise, we cannot stylize the text with <strong>, <em>, or other useful elements

Attempt 2: Just Get Rid of Modals

But, wait a second, why did we even need modals to begin with? How about a simple confirmation, which replaces the button or interaction element, so that there's no interruption at all?

Contrary to the general suggestion, I advise against using modals to avoid context changes; instead, look towards other means of conveying context or creating context through nested views, routes, or showing or hiding content.

8. px

Most people with whom I interact at conferences, and local events, know me for my hatred towards pixels. I digress, perhaps much of it is unjustified. But often, I hear from other developers that they also cringe when they see the dreaded px. Using px may well be the general practice at the moment, but that doesn't mean it's right; in the same way that using ' over " seems to be the norm in Javascript, yet common sense dictates otherwise.

A large portion of our hate towards px stems from its inability to scale well with responsive designs. Take the following, for example:

article {
    font-size: 16px;

article > section {
    font-size: 12px;

article > section > section {
    font-size: 12px;

/* ... */

You see the problem? We're unnecessarily bloating our code. Instead, we can refactor the code to work infinitely well, with nested <section>s:

article {
    font-size: 16px;

article section {
    font-size: 80%;

This is better, but the 16px is still problematic in that it does not scale when the user agent zooms in (more below).

em do have their downsides: namely, they can pose a problem to teams of large developers, as they work together on stylsheets. Because an em is relative to its parent element, developers can struggle to understand what the sizings are in px when designing:

body {
    font-size: 80%; // means 12px in most browsers

main {
    font-size: 1.2em; // since base is 12px, we end up with 12 * 1.2 or 14.4px

article {
    font-size: 0.8em; // back to 12px?  Nope!  11.52px

Those in favour of px may retort that phone screens are built to support text at certain sizes (as in specific px measurements), and that text can appear unclear, or pixelated as a result. This is certainly the case for OS-bundled fonts like Sanfransisco (Mac OS), Segoe UI (Microsoft), Ubuntu (Ubuntu Linux), and Roboto (Android); in cases where the font-size is smaller than 16pt, it is advised to use normal font-weight; lower than 12pt, you should use the condensed version (for Sanfransisco).

Notice, however, that I'm using pt instead of px; pt is the unit used in the Android and iOS documentation because of the varying pixel density of Android and iOS devices. Remember: even though px seem quite standard, they are, in fact, relative to the human eye; terminology like hdpi and retina are used to describe the phenomena where more pixels than usual can be packed into a single screen's device.

So, whatever, it still must be OK to use px instead of em, as browsers will upscale when you use proper <meta viewport> tags, right?


Even though using px guarantees the relative size as per pixel density, it does not allow you to easily scale your design. As the 2011 CSS tricks article states:

Let's say you look through your stylesheet and find 50 different font-size declarations in px. That's 50 places you need to change that font size through a media query when the screen size changes. That's 50 suck points.

The point here is that it's all relative anyway. Just because a font is a certain size on your screen doesn't mean it will be the same size on other screens.

Circumventing the Relativity of em

Sure, rem. Nope: I've got an even better solution:

font-size: initial

Where rem can help solve the problem of getting units relative to the base font size, in most cases, we simply want to reset the font-size to what it was initially. In those cases, we can just use font-size: initial, which will reset the font-size to what it was initially when the page loaded. Simple, right?


$sidebarWidth ?= 25em
$sidebarPadding ?= 1em
$sidebarMargin ?= 1em
$sidebarFontSize ?= 0.8em

    float right
    clear right
    max-width $sidebarWidth
    padding $sidebarPadding
    margin $sidebarMargin
    border 0.1em solid currentColor
    font-size $sidebarFontSize
    @media screen and (max-width: 55em)
        font-size initial
        float none

The nice thing to note in the above example is that, because the border-width is set in em, the width of the border will scale along with the font-size. Try this on your next page, and notice the difference.

em Works Great with Zoom

Using em over px lets us efficiently scale our designs with media queries for users who Zoom in and Zoom out on our pages.

As Brad Frost puts it:

I love to lean back in my chair when at my computer, so I find myself hitting Cmd + on a lot of websites to zoom in the text. When we use pixels to declare our breakpoints, page zooming enacts a horizontal scrollbar and things don’t work so great.

Authoring pages in relative units allows browsers to adjust the design based on the user zoom level, resulting in a more pleasant, more accessible reading experience.

To this, the px person may retort:

But I'm not building responsive pages. I'm not using <meta viewport>, and my designer will be pissed if the dimensions don't match

In that case, px can work perfectly fine. I have no problem with px if that's the case; but you might just get a groan from me when I lament over the fact that the page isn't responsive, and that is likely penalizing the site's SEO.

9. Omitted lang attribute on html

I still forget often, to include the lang attribute in my html element. Including lang in your html improves SEO in that your page will appear more prominently in regions where the language it's written in is spoken. Instead of making search engines guess the language of your page, it's easy enough to simply declare it at the top of your page.

10. HTML4

Now that HTML5 has been standardized, there should be no excuse not to use it. No one likes to see long strings of DOCTYPEs spanning an entire line in our editors. Elements, like <progress>, <details>, <meter>, <mark>, as we've discussed above, provide useful and meaningful elements to describe markup. Until web components are standardized, HTML5 provides an excellent way of writing readable code to other front-end developers.

Even in older browsers, which don't support HTML5, there's a polyfill.

So please, stop writing in HTML4.


As developers, we often get tied up in what one should or shouldn't do to get the best results when building an app. But in reality, I have to digress that these little things, though they do ultimately impact experience, don't tend to make or break the value in a given app/website. Perhaps much of this post has been an overreaction, and a result of so many repositories on Github browsed, and shakes of my head; perhaps It's my ego getting in the way of my own productivity, and -- rightly so -- this is time that could have been spent on developing on any given project. But more likely, I think these things are things all of us, as developers, need to take into account when building our websites. I often quote the phrase:

It's not about what [tool] you use; it's about how you use it

Ultimately, it doesn't matter if you follow these rules or guidelines when building your app/website; what matters is that you deliver the value to your customer/audience, and that you do it effectively. It's easy to get side-tracked, as developers, with the newest and latest libraries or conventions, but none of it matters unless it helps you to achieve a goal or result.

My hope is that it does.