An introduction to HTML
Discover HTML from its history and the basic building blocks
HTML is a standard defined by the WHATWG, an acronym for Web Hypertext Application Technology Working Group, an organization formed by people working on the most popular web browser. This means it’s basically controlled by Google, Mozilla, Apple and Microsoft.
In the past the W3C (World Wide Web Consortium) was the organism in charge of creating the HTML standard.
The control informally moved from W3C to WHATWG when it became clear that the W3C push towards XHTML was not a good idea.
If you’ve never heard of XHTML, here’s a short story. In the early 2000, we all believed the future of the Web was XML (seriously). So HTML moved from being a SGML-based authoring language to a XML markup language.
It was a big change. We had to know, and respect, more rules. Stricter rules.
Eventually browser vendors realized this was not the right path for the Web and they pushed back, creating what is now known as HTML5.
W3C did not really agree on leaving control of HTML and for years we got 2 competing standards, each one aiming to be the official one. Eventually on 28 May 2019 it was made official by W3C that the “true” HTML version was the one published by WHATWG.
I mentioned HTML5. Let me explain this little story. I know, it’s kinda confusing up to now, as with many things in life when many actors are involved, it’s also fascinating.
We had HTML version 1 in 1993. [Here’s the original RFC].
HTML 2 followed in 1995.
We got HTML 3 in January 1997, and HTML 4 in December 1997.
Busy times!
20+ years went by, we had all this XHTML thing, and eventually we are now at this HTML5 “thing”, which is not really just HTML any more.
HTML5 is a term that now defines a whole set of technologies, which includes HTML but adds a lot of APIs and standards like WebGL, SVG and more.
The key thing to understand here is this: there is no such thing (any more) as an HTML version now. It’s a living standard. Like CSS, we call it 3 but in reality it’s a bunch of independent modules developed separately. Like JavaScript, we have one new edition each year, but it does not matter much any more rather than which individual features are implemented by the engine.
Yes we call it HTML5 but HTML4 is from 1997. It’s a long time for anything, imagine for the web.
This is where the standard “lives”: [https://html.spec.whatwg.org/multipage].
The HTML basics
HTML is the markup language we use to structure content that we consume on the Web.
HTML is served to the browser, in different ways.
It can be generated by a server-side application that builds it depending on the request or the session data, for example a Rails or Laravel or Django application.
Or it can be generated by a JavaScript client-side application that generates HTML on the fly.
Or, in the simplest case, it can be stored into a file, and served to the browser by a Web server.
Let’s dive into this case, although in practice it’s probably the least popular way to generate HTML, it’s still essential to know the basic building blocks.
By convention, an HTML file is saved with a .html
or .htm
extension.
Inside this file, we organize the content using tags.
Tags wrap the content, and each tag give a special meaning to the text it wraps.
Let’s make a few examples.
This HTML snippet creates a paragraph using the p
tag:
<p>A paragraph of text</p>
This HTML snippet creates a list of items using the ul
tag, which means unordered list, and the li
tags, which mean list item:
<ul>
<li>First item</li>
<li>Second item</li>
<li>Third item</li>
</ul>
When an HTML page is served by the browser, the tags are interpreted and the browser renders the elements according to the rules that define the visual appearance of them.
Some of those rules are built-in. Like how a list renders, for example. Or how a link is rendered in blue, underlined.
Some other rules are set by you with CSS.
HTML is not presentational. It’s not concerned with how things look. Instead, it’s concerned with what things mean.
It’s up to the browser to determine how things look, with the directives defined by who builds the page, with the CSS language.
Now, those 2 examples I made are HTML snippets taken outside of a page context.
An HTML page structure
Let’s make an example of a proper HTML page.
Things start with the Document Type Declaration (aka doctype), a way to tell the browser this is an HTML page, and which version of HTML we are using.
Modern HTML uses this doctype:
<!DOCTYPE html>
Then we have the html
element, which has an opening and closing tag:
<!DOCTYPE html>
<html>
...
</html>
All tags have an opening and closing tag. Except a few self-closing tags which don’t need a closing one because they don’t contain anything in them.
The closing tag is same as the opening one, but with a /
.
The html
starting tag is used at the beginning of the document, right after the document type declaration.
The html
ending tag is the last thing present in an HTML document.
Inside the html
element we have 2 elements: head
and body
:
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
...
</body>
</html>
Inside head
we will have tags that are essential to creating a web page, like the title, the metadata, and internal or external CSS and JavaScript. Mostly things that do not directly appear on the page, but only help the browser (or bots like the Google search bot) display it properly.
Inside body
we will have the content of the page. The visible stuff.
Tags vs elements
I mentioned tags and elements. What’s the difference?
Elements have a starting tag, and closing tag.
In this case, we use the p
starting and closing tags to create a p
element.
<p>A paragraph of text</p>
So, an element constitutes the whole package:
- starting tag
- text content (and possibly other elements)
- closing tag
If an element has no closing tag, it is only written with the starting tag, and it cannot contain any text content.
That said, I might use the tag or element term in the book meaning the same thing, except I explicitly mention starting tag or ending tag.
Attributes
The starting tag of an element can have special snippets of information we can attach, called attributes.
Attributes have the key="value"
syntax:
<p class="a-class">A paragraph of text</p>
You can also use single quotes, but using double quotes in HTML is a nice convention.
We can have multiple of them:
<p class="a-class" id="an-id">A paragraph of text</p>
and some attributes are boolean, meaning you only need the key:
<script defer src="file.js"></script>
The class
and id
attributes are two of the most common you will find used.
They have a special meaning, and they are useful both in CSS and JavaScript.
The difference between the two is that an id
is unique in the context of a web page, it cannot be duplicated.
Classes, on the other hand, can appear multiple times on multiple elements.
Plus, an id
is just one value. class
can hold multiple values, separated by a space:
<p class="a-class another-class">A paragraph of text</p>
It’s common to use the dash -
to separate words in a class value, but it’s just a convention.
Those are just 2 of the possible attributes you can have. Some attributes are only used for one tag. They are highly specialized.
Other attributes can be used in a more general way. You just saw id
and class
, but we have other ones too, like style
which can be used to insert inline CSS rules on an element.
Case insensitive
HTML is case insensitive. Tags can be written in all caps, or lowercase. In the early days, caps were the norm. Today lowercase is the norm. It is a convention.
You usually write like this:
<p>A paragraph of text</p>
not like this:
<P>A paragraph of text</P>
White space
Pretty important. In HTML, even if you add multiple white spaces into a line, it’s collapsed by the browser’s CSS engine.
For example the rendering of this paragraph
<p>A paragraph of text</p>
is the same as this:
<p> A paragraph of text</p>
and the same as this:
<p>A paragraph
of
text </p>
Using the
white-space
CSS property you can change how things behave. You can find more information on how CSS processes white space in the CSS Spec
I’d say use the syntax that makes things visually more organized and easier to read, but you can use any syntax you like.
I typically route for
<p>A paragraph of text</p>
or
<p>
A paragraph of text
</p>
Nested tags should be indented with 2 or 4 characters, depending on your preference:
<body>
<p>
A paragraph of text
</p>
<ul>
<li>A list item</li>
</ul>
</body>
Note: this means that if you want to add an additional space, it can make you pretty mad. I suggest to use CSS to make more space when needed.
Note: in special cases, you can use the
HTML entity (an acronym that means non-breaking space) - more on HTML entities later on. I think this should not be abused. CSS is always preferred to alter the visual presentation.
The document heading
The head
tag contains special tags that define the document properties.
It’s always written before the body
tag, right after the opening html
tag:
<!DOCTYPE html>
<html>
<head>
...
</head>
...
</html>
We never use attributes on this tag. And we don’t write content in it.
It’s just a container for other tags. Inside it we can have a wide variety of tags, depending on what you need to do:
title
script
noscript
link
style
base
meta
The title
tag
The title
tag determines the page title. The title is displayed in the browser, and it’s especially important as it’s one of the key factors for Search Engines Optimization.
The script
tag
This tag is used to add JavaScript into the page.
You can include it inline, using an opening tag, the JavaScript code and then the closing tag:
<script>
..some JS
</script>
Or you can load an external JavaScript file by using the src
attribute:
<script src="file.js"></script>
The
type
attribute by default is set totext/javascript
, so it’s completely optional.
There is something pretty important to know about this tag.
Sometimes this tag is used at the bottom of the page. Why? For performance reasons.
Loading scripts by default blocks the rendering of the page until the script is parsed and loaded.
Doing so, the script is loaded and executed after all the page is already parsed and loaded, giving a better experience to the user over keeping it in the head
tag.
My opinion is that this is now bad practice. Let script
live in the head
tag.
In modern JavaScript we have an alternative, more performant than keeping the script at the bottom of the page - defer
attribute:
<script defer src="file.js"></script>
This is the scenario that triggers the faster path to a fast loaded page, and a fast loaded JavaScript.
Note: the
async
attribute is similar, but in my opinion a worse option thandefer
. I describe why in details in the page https://flaviocopes.com/javascript-async-defer/
The noscript
tag
This tag is used to detect when scripts are disabled in the browser.
Note: users can choose to disable JavaScript scripts in the browser settings. Or the browser might not support them by default.
It is used differently whether it’s put in the document head, or in the document body.
We’re talking about the document head now, so let’s first introduce this usage.
In this case, the noscript
tag can only contain other tags:
link
tagsstyle
tagsmeta
tags
to alter the resources served by the page, or the meta
information, if scripts are disabled.
In this example I set an element with the no-script-alert
class to display if scripts are disabled, as it was display: none
by default:
<!DOCTYPE html>
<html>
<head>
...
<noscript>
<style>
.no-script-alert {
display: block;
}
</style>
</noscript>
...
</head>
...
</html>
Let’s solve the other case: if put in the body, it can contain content, like paragraphs and other tags, which are rendered in the UI.
The link
tag
The link
tag is used to set relationships between a document and other resources.
It’s mainly used to link an external CSS file to be loaded.
This element has no closing tag.
Usage:
<!DOCTYPE html>
<html>
<head>
...
<link href="file.css" rel="stylesheet">
...
</head>
...
</html>
The media
attribute allows to load different stylesheets depending on the device capabilities:
<link href="file.css" media="screen" rel="stylesheet">
<link href="print.css" media="print" rel="stylesheet">
We can link to different resources than stylesheets.
For example we can associate an RSS feed using
<link rel="alternate" type="application/rss+xml" href="/index.xml">
We can associate a favicon using:
<link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png">
This tag was also used for multi-page content, to indicate the previous and next page using rel="prev"
and rel="next"
. Mostly for Google. In 2019 Google announced it does not use this tag any more because it can find the correct page structure without it.
The style
tag
This tag can be used to add styles into the document, rather than loading an external stylesheet.
Usage:
<style>
.some-css {}
</style>
As with the link
tag, you can use the media
attribute to only use that CSS on the specified medium:
<style media="print">
.some-css {}
</style>
You can also add this tag in the document body. Speaking of this, it’s interesting the scoped
attribute to only assign that CSS to the current document subtree. In other words, to avoid leaking the CSS outside of the parent element.
The base
tag
This tag is used to set a base URL for all relative URLs contained in the page.
<!DOCTYPE html>
<html>
<head>
...
<base href="https://flaviocopes.com/">
...
</head>
...
</html>
The meta
tag
Meta tags perform a variety of tasks and they are very, very important.
Especially for SEO.
meta
elements only have the starting tag.
The most basic one is the description
meta tag:
<meta name="description" content="A nice page">
This might be used by Google to generate the page description in its result pages, if it finds it better describes the page than the on-page content (don’t ask me how).
The charset
meta tag is used to set the page character encoding. utf-8
in most cases:
<meta charset="utf-8">
The robots
meta tag instructs the Search Engine bots whether to index a page or not:
<meta name="robots" content="noindex">
Or if they should follow links or not:
<meta name="robots" content="nofollow">
You can set nofollow on individual links, too. This is how you can set
nofollow
globally.
You can combine them:
<meta name="robots" content="noindex, nofollow">
The default behavior is index, follow
.
You can use other properties, including nosnippet
, noarchive
, noimageindex
and more.
You can also just tell Google instead of targeting all search engines:
<meta name="googlebot" content="noindex, nofollow">
and other search engines might have their own meta tag, too.
Speaking of which, we can tell Google to disable some features. This prevents the translate functionality in the search engine results:
<meta name="google" content="notranslate">
The viewport
meta tag is used to tell the browser to set the page width depending on the device width.
<meta name="viewport" content="width=device-width, initial-scale=1">
Another rather popular meta tag is the http-equiv="refresh"
one. This line tells the browser to wait 3 seconds, then redirect to that other page:
<meta http-equiv="refresh" content="3;url=http://flaviocopes.com/another-page">
Using 0 instead of 3 will redirect as soon as possible.
This is not a full reference, other less used meta tags exist.
After this document heading introduction, we can start diving into the document body.
The document body
After the closing head tag, we can only have one thing in an HTML document: the body
element.
<!DOCTYPE html>
<html>
<head>
...
</head>
<body>
...
</body>
</html>
Just like the head
and html
tags, we can only have one body
tag in one page.
Inside the body
tag we have all the tags that define the content of the page.
Technically, the start and ending tags are optional. But I consider it a good practice to add them. Just for clarity.
In the next chapters we’ll define the variety of tags you can use inside the page body.
But before, we must introduce a difference between block elements and inline elements.
Block elements vs inline elements
Visual elements, the ones defined in the page body, can be generally classified in 2 categories:
- block elements (
p
,div
, heading elements, lists and list items, …) - inline elements (
a
,span
,img
, …)
What is the difference?
Block elements, when positioned in the page, do not allow other elements next to them. To the left, or to the right.
Inline elements instead can sit next to other inline elements.
The difference also lies in the visual properties we can edit using CSS. We can alter the width/height, margin, padding and border or block elements. We can’t do that for inline elements.
Note that using CSS we can change the default for each element, setting a
p
tag to be inline, for example, or aspan
to be a block element.
Another difference is that inline elements can be contained in block elements. The reverse is not true.
Some block elements can contain other block elements, but it depends. The p
tag for example does not allow such option.
→ I wrote 17 books to help you become a better developer, download them all at $0 cost by joining my newsletter
→ JOIN MY CODING BOOTCAMP, an amazing cohort course that will be a huge step up in your coding career - covering React, Next.js - next edition February 2025