Going back to Web Basics: Structuring HTML

As web developers, there’s no escaping the fact that we have typed HTML since we did our first web development tutorial or published our first website. Right now, we can manipulate HTML to our own whim, creating beautiful and interactive websites with CSS and Javascript out of XML structured documents. Tutorials on how to use libraries and the next hottest frameworks crop up here and there on how to manipulate HTML to create ever more exciting sites for users to interact with.

But we might have forgotten the true purpose and magic of HTML. HTML is a parse-able document that is the main place for content. And this content is, for all its intents and purposes, is both readable by computers and all kinds of users. Baked into its tags are little helpers for users.

Little helpers that help computers understand the structure of your document, which help people search the most important information they need.

Little helpers that help computers add that extra information when things fail to load or when you need to load the right asset provided .

Little helpers that help computers add voices or visual ques to help disabled users or people who has accessibility issues.

The problem with forgetting these little helpers from HTML is where we add unnecessary attributes or additional tags just to hack the HTML behavior, or delegate it to Javascript and CSS. All of which adds bloat and bytes to your website, impacting the user experience by delaying the first time to paint and first time to interact.

Tutorials and In-the-Wild HTML

There are still some good tutorials on how to write good HTML but there are some that has overused div and spans to structure content, then we delegate to Aria or use additional attribtues, CSS, and Javascript to make it readable or understandable. We see spans turned into titles…

<header id="top" class="main-header">
<span class="title">
This is the Title Text
with another title here.

or divs turned into buttons

<div class=”join-button”>
Join us

or emphasizing texts using span…

<span class="italics">Emphasis on this text</span>

In short, the convenience and abuse of delegating to CSS and Javascript to “enhance” HTML has robbed it of its primary function: to describe and give meaning to content.

Returning to Basics

So this article’s purpose is to bring back the descriptive delegation to HTML. Later on we will delegate styling content to CSS, taking note of when to styling properties of CSS and descriptive properties of HTML to show a particular text. Lastly, we add to the mix Javascript for logic delegation to enhance interaction and how we can use web components and frameworks to the mix.

How I (hope I will) write my HTML

I still have those bad habits, especially when you are a developer who wants to get things done because of deadlines and bad tutorials. But I am hoping what I can share to you my current practice and opinion on how to structure your HTML.

Starting with the structure

My landing page would have a structure like this:

Now given above, let’s dissect this one.

Doctype HTML

<!doctype html>

This allows the document to be treated as an HTML 5 document. Nothing much to explain here…


<meta charset="utf-8">

I like my documents to be in utf-8 so as to help the browser and other bots to not use their time to infer the encoding.


<meta name="viewport" content="width=device-width, minimum-scale = 1.0, initial-scale = 1.0, maximum-scale = 5.0, user-scalable=yes, shrink-to-fit=no">

Now this is where it gets interesting. The viewport allows us to make our site mobile responsive. The one above just says that the viewport size should be at least equal to the size of the viewport of the phone. But what really gets me interested is the last two parts.

maximum-scale = 5.0, user-scalable=yes

Most of the tutorials I’ve seen puts maximum-scale=1, user-scalable=no. These two sets stops the user to pinch-zoom your mobile website. Now, that is good for design, but bad for accessibility. It doesn’t help people who have problems with their eyesight if they can’t read your text and they can’t zoom into it. So in my opinion, maximum-scale=5, user-scalable=yes. You can see more of the explanation here.

I added also this…


Because of Safari 9. This makes Safari 9 at least follow the standard for Responsive Websites. You can check it out here: http://adrianroselli.com/2015/10/dont-disable-zoom.html


<meta name="generator" content="Page Generator v1.0.0">

This helps browsers and statistics lovers know what is your favorite IDE or page generator or something. I like to keep this around and put my own Slush builder later.

Page Description

<meta name="description" content="This is the description of the page">

The helps search engines provide a description of your page on search results. Descriptions are like Twitter texts: 160 character snippet of what your page is about. You can check here on tips on how to write your page description. Knowing some good micro-copy might give you advantage.

Facebook Meta

<meta property="og:title" content="Title of the Page to be shown in Facebook">
<meta property="og:type" content="website">
<meta property="og:image" content="https://example.com/image-to-be-shown-in-facebook.jpg">
<meta property="og:description" content="This is the description of the page that will show in the facebook card">

These are meta tags that are helpful in making your page a bit more share-able in Facebook.

Twitter Meta

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@twitterHandleOfSite">
<meta name="twitter:creator" content="@twitterHandleOfCreator">
<meta name="twitter:title" content="Title of the Page to be shown in Twitter">
<meta name="twitter:description" content="This is the description of the page that will show in the twitter card">
<meta name="twitter:image" content="https://example.com/image-to-be-shown-in-twitter.jpg">

And these are meta tags that are helpful in making your page a bit more share-able in Twitter.

As you can see both of the Facebook and Twitter meta tags have areas to put your title and description. These will show up as the title and description cards when you share your page. Much like the meta description and the title tag, it will be useful to use the same ideas here on how to write a good description.

Web App Manifest and Fallback

<link rel="manifest" href="manifest.json">

Using the manifest.json, it allows the user to add your website as an app in their phone/tablet’s homepage. The Web App Manifest essentially standardize the way we set icons, app behavior, splash screens, even the site’s short name that will show on the home screen. But…

Only Chrome and Opera supports it. That’s why we have fallback mechanisms for other browsers…

<!-- Add to homescreen for Chrome on Android. Fallback for manifest.json -->    
<meta name="mobile-web-app-capable" content="yes">
<meta name="application-name" content="Title of this Page">

<!-- Add to homescreen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Title of this Page">
<link rel="apple-touch-icon"  sizes="48x48" href="images/manifest/images/icons/icon-48x48.png">    
<link rel="apple-touch-icon" sizes="72x72" href="images/manifest/images/icons/icon-72x72.png">
<link rel="apple-touch-icon" sizes="96x96" href="images/manifest/images/icons/icon-96x96.png">
<link rel="apple-touch-icon" sizes="128x128" href="images/manifest/images/icons/icon-128x128.png">
<link rel="apple-touch-icon" sizes="144x144" href="images/manifest/images/icons/icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="images/manifest/images/icons/icon-152x152.png">
<link rel="apple-touch-icon" sizes="192x192" href="images/manifest/images/icons/icon-192x192.png">
<link rel="apple-touch-icon" sizes="384x384" href="images/manifest/images/icons/icon-384x384.png">
<link rel="apple-touch-icon" sizes="512x512" href="images/manifest/images/icons/icon-512x512.png">
<!-- Tile icon for Windows 8 (144x144 + tile color) -->    
<meta name="msapplication-TileImage" content="images/manifest/images/icons/icon-512x512.png">
<meta name="msapplication-TileColor" content="">
<meta name="msapplication-tap-highlight" content="no">

Now of course these are not exhaustive but it currently suffices my needs.

Above the Fold Inline Style

// Styles for the above fold

For performance purposes, I split my styles into two separate parts. Styles that show above the fold, and styles that are under the fold. The purpose of the separation is that CSS blocks the rendering of content. And loading a stylesheet (or any file) in the head blocks the rendering of the body part. To minimize the performance impact and reach the time-to-first-paint (or showing the content immediately), I would put the essential styles at the top and defer loading the other styles at the bottom. The styles above the fold are put in the head so that it is part of the content document when it is being loaded first, parsing it quickly to show the design when the body renders. You can check good practices here and here. You can also understand how rendering works by reading it here.


The body outputs this document structure outline using this and this:

HTML 5 Outliner
Nu Html Checker

See that I have separated the page into three main sections: header, main, footer. This corresponds to a lot of pages in the wild where you have a header, main content, and footer, and it reflects to the structural outline as well. Nice job on not using just divs and making it easier to understand by users, screen readers, bots, and devs.


With Title


In the main header, the logo is inside the h1 tag so that it can tag that the header section with a title. picture/img tags can be inside h1 tags because they are considered phrasing content. Now it also has a nav list for a list of links. We can add parts here like search forms and login buttons, but we’ll save it on another article.

Quick detour: Aside

<aside class="drawer">      
With Title


<h2>Side bar footer</h2>

Although there are three main sections, in our document there are actually four parts. The aside is a tag that represents content that is tangentially connected to the main content of the document. I used it as a drawer in this example for mobile phones. I could also just use a simple nav tag as a drawer and it would suffice. Now because this is an aside tag, it quickly becomes under the outline of the header based on the html outline algorithm. Again, the drawer for me is optional and I am still debating with myself about it (if should just use a nav with tab icons as a primary navigation (either positioned above or below the screen) or use the hamburger/drawer combo for smaller screens.


<header class="banner">
<h1>Banner Title</h1>
<p>This is the section with a CTA</p>
<a href="/cta" class="cta">
Click here
<h2>Section 1 here</h2>
<h2>Section 2 here</h2>
<h2>Section 3 here</h2>
<h2>Section 4 here</h2>

Now the main content shows you the structure that is usual to most landing pages. You have a banner and several sections. I have used a header tag instead of a section tag to differentiate the banner from the other sections so that I can tell the computers that this is the title of the main content. If this becomes an article type of page, I would just wrap this in another tag called an article, but that would be for another article.


<h1>Main Footer here</h1>

Of course, the footer has all the essential information about the authors, or copyright data, or footer nav links.

Lazy-loading CSS

<link rel="stylesheet" href="style.css">
// adds styles later
var style = document.createElement('link')
style.rel = 'stylesheet'
style.href = 'style.css'
var first = document.getElementsByTagName('link')[0]
first.parentNode.insertBefore(style, first)

Because we have put only the above-the-fold styles at the top, we put here a script that lazy-loads the remaining css files. Lazy-loading CSS files are different in such a way that you can’t just put a defer or async attribute to a link tag (much like in script tags). Once you put a link tag, either in the head or the body, it will always block the rendering of the body. So the best way is to use javascript to load the stylesheets.

I added a noscript tag as well as a fallback mechanism if javascript is turned off.

Lastly JS

// Polyfills and other script essentials here

Lastly, we load all the scripts that you need to make the site a little bit more interactive. I would put here my Google Analytics, Facebook Analytics, Error monitoring scripts, Polyfills, and libraries to create a richer experience.

A word of caution though for this type of pages: If you are going to add the JS at the last part but your page is dependent on the JS to make it interactive, it will have a big performance impact, pushing the time-to-interactive further. This will eventually frustrate your users. If you can have your HTML + JS (and maybe CSS) to have only a size of 150KB (ideal is 50KB) to show and interact with essential content, then you are good.

In Conclusion

This is my own opinionated (and at the minimum, documented) way of structuring my HTML files. I would like to know yours or if this can be improved better. In my later articles, I would try to include how to structure your page using web components that uses ShadowDOM and how it impacts screen readers.