Tuesday, 26 November 2013

Semantic HTML, CSS Classes, JS Selectors and all that

This is blog I wrote a few years ago. I thought it’d be useful to republish it here as it’s an excellent starting ground for creating semantic markup that can be rendered well across all devices.

If you write any HTML, then you’ll soon realise that careful choice of HTML elements and class namings will reap many a reward. The HTML document you create ‘'’is an interface’’’, an interface that is not only read by a browser to render your page to the user’s screen, but also the interface in which:

  • JavaScript can traverse, interact with the page and extract content to post back to the servers (AJAX).
  • Drive automated & scripted web test tools - Geb (and spock), Selenium
  • Third parties can access content from the page and re-purpose on other web sites.

A well chosen interface will allow your HTML code to stand the test of time, be picked up and maintained by others, drive increasingly interactive JavaScript driven experiences and survive site redesigns. Below are listed a few key drivers which I follow.

Readability

Write Classes with Meaning, a.k.a Semantic HTML

Plain Old Semantic HTML (POSH) gives us the POSH check list and helps drive some semantic HTML that I create.

  • The first rule of POSH is that you must validate your POSH.
  • Second, drop the use of TABLEs for purely presentation purposes, spacer GIFs, and presentation HTML in general.
  • Next, fix your Bed and BReakfast markup.
  • Eliminate Anorexic Anchors.
  • Re-use pre-existing posh-patterns.
  • Use good semantic class names.
  • Choose naming that gives meaning, not naming that indicates presentation, for example, “indent”, “red” and “bottom-margin” are bad choices.

Define classes for reuse and allow context selection

Use

    <div class="event">
      <div class="time">18:00</div>
    </div>

instead of

    <div class="event">
      <div class="eventTime">18:00</div>
    </div>

since this allows the class time to be used in other contexts to identify times of different items, but still allows you to pick out the event time with .event .time

Avoid Obtuse Acronyms and Word Shortenings

The following :

    .checkbox.email.selected { ... }
    .address { ... }

are better than

    .cbem.sel { ... }
    .addr { ... }

The extra characters saved by shortening the words does not make the pain for reading of code by third parties worthwhile. And, anyhow, downstream automatic optimisers could always deal with minification if it was worth while. Don’t let the goal for keeping pay load to a minimum, lead to unreadability.

Reliability

Don’t make your selector rules too specific

Be careful of using too much specificity in a CSS selector rule, e.g.

    .events ul .event .time { ... }

Today, you may have

    <section class="events">  
      <ul>
        <li class="event">
          <div class="time">18:00</div>
        </li>
      </ul>
    </section>

but you may move it out to a ol our out of a list tomorrow. Only use the ul in selector if you only wanted to apply the rule if it was in a <ul>. Also in the runtime stack this ul might be adapted to alternative elements on another, perhaps legacy, device - so locking the style selector unnecessarily to the <ul> could have an adverse affect on alternative renderings of the site.

The dangers of relative traversal to locate items in the DOM

Be careful with locating an element through relative traversing APIs, like parent(), prev() and next()

    $(this).parents().parent().prev().show();

If you move an element slightly this logic might mis-fire. Consider locking down the rule a little, e.g.

    $(this).parents(".event").find(".time").show();

i.e. go up to find the ancestor with class event and then within that find the element with class set to time. This second approach is more robust to HTML shuffles.

For example you may have a display control that displays a content item, but also provides an edit button update the content item. You might toggle between the display and update controls as follows:

    // Click edit 
    $(".event .action.edit").click(function () {
      $(this).parents(".event").find(".read-control").hide();
      $(this).parents(".event").find(".update-control").show();
    }); 
    // Click save<br />$(".event .action.save").click(function () {
      saveEvent();
      $(this).parents(".event").find(".update-control").hide();<
      $(this).parents(".event").find(".read-control").show();
    });

IDs vs classes

ids must be unique in a complete HTML page, so ensure that it is. Don’t use an id on an element that is likely to be repeated or reused across a page, e.g. a date control. If in doubt, then you probably should be using a class.

Allowing The Browser to Render The Page More Efficiently

The way you write your selectors can have an adverse effect on how efficiently a browser can render your site.

Further Reading