HTML Coding Style Guidelines
Table of Contents
Where HTML Started and Why It’s Janky
HTML stands for “HyperText Markup Language.” “HyperText” refers to the links that connect one document or website to another. And “Markup” refers to a list of predefined tags that determine how a document is formatted and rendered. The purpose of HTML is to instruct a web browser how to draw a document on a screen. That’s literally all there is to it.
In the early days of the web, HTML only had a few different tags, and almost all of them were primarily used to change how a document looked. For example, <br> for line breaks, <p> for paragraph breaks, <center> to center align, <b> for bold, and <i> for italic. In HTML5, styling is handled using almost exclusively using CSS. There are still a lot of different tags, including <caption>, <dialog>, <footer>, and <section>, but most of them show structure and purpose rather than visual style.
HTML Tags
Almost every tag comes in pairs: an opening tag and a closing tag. The opening tag declares the tag type in brackets, like <title>, and end with brackets that have a closing slash before the tag name, like <\title>. And all of the text in between the tags is now part of the <title> element. For instance:
| Code Example | Rendered Text |
|---|---|
"em" is short for <em>emphasis</em> and renders as italic. | “em” is short for emphasis and renders as italic. |
"strong" tags make things <strong>bold</strong>. | “strong” tags make things bold. |
"u" tags are for <u>underlined</u> text. | “u” tags are for underlined text. |
Nonsense tags are <asdfg>ignored</asdfg>. | Nonsense tags are |
You can also <u>nest tags <em>inside other tags</em></u>! | You can also nest tags inside other tags! |
Note that the tags themselves don’t render, just the text. While it’s really, really important that you use the right tags for the right reasons (see the Semantic HTML section below), HTML is very forgiving. If you have a typo in the tag name, it will just be ignored. If you forget to properly open or close a tag, it will just drop it or close it for you.
Coding for Readability
Reading good, clean HTML code should be almost as easy as reading the rendered web page. Clean, consistent use of white space, and avoiding too much clutter on one line can make a big difference.
- By convention, all HTML tag names and all HTML attributes are always lowercase.
- Add indents for unclosed tags and line breaks where helpful. When rendered, HTML ignores whitespace more than a single space.
- If an element has a lot of attributes, it’s good practice to break them out over multiple lines.
- When an element can easily be opened and closed in a single line, it’s OK to do that.
- For tags that are
inlineinstead ofblock(like<em>,<strong>, and<span>), it’s okay to not add space, since that’s how they render.
BAD EXAMPLE:
<MAIN> <!-- Should be lowercase. -->
<h1> <!-- Should open and close in one line. -->
How to Write Clean HTML
</h1>
<DIV class="flex-row flex-wrap"><div class="card"> <!-- Multiple openers on the same row means we'll probably forget to close one. -->
<h2>Add Whitespace for Readability</h2>
<p>Breaking up the code in a way that <strong>mirrors the page content</strong> can help developers find problematic sections more quickly.</p>
</div><div CLASS="card"> <!-- Don't close one thing and open another on the same line. -->
<h2>Proper Nesting</h2>
<p>Elements built
<em>inside of other elements</em> <!-- This tag doesn't change page structure, so doesn't really need its own line-->
should be nested with an additional tab. This makes it simpler to find when complex elements start and end, and catch unclosed elements.</p>
</div>
<div
class="card"
> <!-- This would be cleaner on one line instead of broken up. -->
<h2>Listing Attributes</h2><p>Elements with <u>more than one attribute</u> should use spacing to make it easy to read them.</p>
<a href="https://ucf.edu" target="_blank" rel="noreferrer">UCF Home Page</a>
</div></DIV></MAIN> <!-- Yuck! -->
GOOD EXAMPLE:
<main>
<h1>How to Write Clean HTML</h1>
<div class="flex-row flex-wrap">
<div class="card">
<h2>Add Whitespace for Readability</h2>
<p>
Breaking up the code in a way that <strong>mirrors
the page content</strong> can help developers find
problematic sections more quickly.
</p>
</div>
<div class="card">
<h2>Proper Nesting</h2>
<p>
Elements built <em>inside of other elements</em>
should be nested with an additional tab. This makes
it simpler to find when complex elements start and
end, and catch unclosed elements.
</p>
</div>
<div class="card">
<h2>Listing Attributes</h2>
<p>
Elements with <u>more than one attribute</u> should
use spacing to make it easy to read them.
</p>
<a
href="https://ucf.edu"
target="_blank"
rel="noreferrer">
UCF Home Page
</a>
</div>
</div>
</main>
Inline Styles
When it comes to visual styles, you should never apply CSS style rules directly in the HTML. These are called “inline styles” and are bad because:
- They override all other CSS rules, which will almost always cause inconsistencies.
- They are a pain to debug.
- They make your HTML difficult to read.
- They cause a lot of duplicate code and are HORRIBLE to update.
Just say no to inline styles.
BAD EXAMPLE:
<div style="width: 100%; background-color: #f2f2f2; padding: 1em;">
<h1 style="color: blue; margin-top: 0;">Welcome to the Techrangers!</h1>
<p style="margin-top: 0;">First paragraph...</p>
<p>Second paragraph...</p>
<div style="margin: 1em; padding 1em; border: 1px solid gray; background-color: white; box-shadow: 2px 2px 4px #80808040;">
<h2 style="margin-top: 0;">Card Heading</h2>
<p style="margin-top: 0;">Paragraph in the card...</p>
<a href="https://ucf.edu" style="text-align:center; text-decoration: none;">UCF Homepage</a>
</div>
</div>
By mushing the CSS and the HTML together, the HTML code is hard to parse and the CSS is stuck in place. All of the CSS styles are only ever applied to the individual elements that they are on, and don’t help anywhere else. If you want a similar style elsewhere, you’ve got to copy and reuse code. Then if you change your mind about something, you have to edit the relevant styles everywhere this applies.
As a side note, this looks a lot like Tailwind, which is also horrible, and for much the same reasons.
GOOD EXAMPLE:
HTML Code
<main>
<h1>Welcome to the Techrangers!</h1>
<p>First paragraph...</p>
<p>Second paragraph...</p>
<div class="card">
<h2>Card Heading</h2>
<p>Paragraph in the card...</p>
<a href="https://ucf.edu">UCF Homepage</a>
</div>
</main>
CSS Code
main {
width: 100%;
background-color: #f2f2f2;
padding: 1em;
h1 {
color: blue;
margin-top: 0;
}
:is(h1, h2) + p {
margin-top: 0;
}
}
.card {
margin: 1em;
padding 1em;
border: 1px solid gray;
background-color: white;
box-shadow: 2px 2px 4px #80808040;
h2 {
margin-top: 0;
}
a {
text-align:center;
text-decoration: none;
}
}
Notice that both the CSS and HTML are easy to read. The CSS is reusable and easy to edit. By using semantic HTML for the <main>, <h1>, <h2>, and <a> tags, I was able to apply styling to the element types and only ever needed a single class, card, which can be used elsewhere.
Tag Attributes
All tags can have additional attributes inside to further define how the display or interact. These are listed in the opening tag after the tag name, and are always separated by spaces. For instance, <div>inner text here</div> creates a complete and functional <div> element, but <div id="hero-header" class="card--full-width">inner text here</div> makes it easier to target the element by its id or to give it specific styles with its class.
There are a LOT of different attributes, and a full list is here. But there only a few that you need to know at the beginning.
| HTML Attribute | Valid Elements | What It Does |
|---|---|---|
class | All (Global) | Puts the element in a class, which receives CSS styles. Any number of elements can have the same class. |
id | All (Global) | Identifies a single element, usually for scripting purposes. All id values on a page must be unique. |
role | All (Global) | Tells the browser to give an element a specific accessibility role that it doesn’t already have by default. Like if a list is acting as a nav bar, its opening tag may be <ul role="navigation">. Use semantic HTML instead, where possible. |
style | All (Global) | Allows you to add CSS styles inside the HTML. Unless asolutely required, use CSS instead. |
Semantic HTML
When you use the right tag for the right thing, a lot of the work gets done automatically. For example, if you wanted to make some text look and act like a button, you would need to put it in a <span> or <div> tag, with the role="button" attribute, JavaScript handlers for onclick and keydown events to make it activate, and manually add custom styles to make the cursor change to a pointer or give the “button” special hover or click styles. That’s a lot of steps, and easy to forget one. However, if you just create a <button> element, all that happens automatically. Browsers know how to make interactive buttons.
Imagine a header at the top of the screen with a logo, a list of links, and a user profile and settings popup in the corner. You can technically do all of that with a bunch of <div> and <span> elements, and style it all with some classes. This is horrible. Instead, use specific elements that are designed for the task. In addition to making the code simpler and more readable, it also give you accessibility, keyboard controls, and some other interactivity for free.
BAD EXAMPLE:
<div class="header-row">
<!-- Making a click work on a <div> requires custom JavaScript. -->
<div class="header-logo" onclick="goHome()">
<img src="logo.png" alt="Brand Logo">
</div>
<!-- Every div requires a different class in order to target it with CSS. -->
<div class="header-link-list">
<ul>
<li>
<a href="./home.html">Home</a>
</li>
<li>
<a href="./services.html">Services</a>
</li>
<li>
<a href="./about.html">About Us</a>
</li>
</ul>
</div>
<div class="header-user-widget">
<img src="user.png" alt="User Profile" onclick="openProfile()">
<!-- The openProfile and closeProfile functions will toggle the hidden class and aria-hidden attribute -->
<div class="user-profile hidden" aria-hidden="true">
<div class="user-profile-close" onclick="closeProfile()">x</div>
<div class="user-profile-name">User's Name</div>
<a href="userPreferences.html">Preferences</a>
<a href="purchaseHistory.html">Purchase History</a>
<a href="logout.html">Logout</a>
</div>
</div>
</div>
Notice that almost everything is a <div>. This gives no information to the accessibility DOM about what things do or what they’re for. There’s no way for the user to jump straight to the navigation or to skip over it. And the profile widget requires a LOT of work. And it’s still not a great user experience. Is it keyboard accessible? What if the profile is open and the user clicks somewhere else on the screen? Does it close automatically? This will require a lot of testing and even more JavaScript to make it work.
GOOD EXAMPLE:
<header>
<!-- Here, the image KNOWS it's a link, the cursor automatically turns into a pointer, etc.-->
<a href="./home.html" aria-label="Brand Home">
<img src="logo.png" alt="">
</a>
<!-- Wrapping the list of links in a <nav> element with a nice label makes it accessible. -->
<nav aria-label="Site Navigation">
<ul>
<li>
<a href="./home.html">Home</a>
</li>
<li>
<a href="./services.html">Services</a>
</li>
<li>
<a href="./about.html">About Us</a>
</li>
</ul>
</nav>
<!-- Using a button with a popover gives you all the interactivity for free. No JavaScript required. -->
<button popovertarget="user-settings" aria-label="User Settings">
<img src="user.png" alt="">
</button>
<!-- The popover attribute makes this invisible by default, and toggled by the button -->
<div id="user-settings" popover>
<div>User's Name</div>
<a href="userPreferences.html">Preferences</a>
<a href="purchaseHistory.html">Purchase History</a>
<a href="logout.html">Logout</a>
</div>
</header>
Using the <header>, <nav>, and <button> elements greatly increase usability, accessibility, and code readability AND mean there’s a lot less CSS and JavaScript required to accomplish the same effect. It’s a win-win.
Also notice, there are a LOT less class attributes. Instead of targeting the .header-row class in the first example, I can still use CSS and style the header element instead.
HTML Cheat Sheet
Required HTML Tags
The following tags are required in the Web Content Accessibility Guidelines, an international standard created and adopted by the World Wide Web Consortium (W3C). They outline a wide variety of ways to ensure that web content is accessible to as many users as possible. Using them properly makes sites much more easy to navigate using screen readers and keyboards.
| HTML Tag | Rule | Example | More Info |
|---|---|---|---|
<html> | MUST contain language attribute | <html lang="en"> | <html> info |
<head> | MUST exist, MUST contain title | <head><title>...</title></head> | <head> info |
<title> | MUST exist, MUST contain text | <title>Page Title \| Site Title</title> | <title> info |
<body> | Everything visible on the page | <body> info | |
<header> | SHOULD exist, but exactly once | <header>Site Title, Logo, etc.</header> | <header> info |
<nav> | MUST exist (can have multiples) | <nav><ul><li>Home</li><li>Contact</li></ul></nav> | <nav> info |
<main> | MUST exist exactly once, contains everything but header, nav, and footer | <main>ALL page-specific site content</main> | <main> info |
<h1> | MUST exist exactly once, should be equivalent to <title> text | <main><h1>Page Title</h1>...</main> | Heading info |
<h2> - <h6> | Should nest appropriately when used | <h1>... <h2>... <h3>... <h3>... <h2>... <h3>... | Heading info |
<footer> | SHOULD exist, but exactly once | <footer>Site Info, Social and Other Links</footer> | <footer> info |
See Structuring Documents for more information about these major page elements.
Additional HTML Tags
There are dozens of other additional semantic HTML tags that should be used instead of <div>s or <span>s, wherever appropriate. The most useful ones are listed here:
| HTML Tag | Use Case | More Info |
|---|---|---|
<article> | An area of independent, self-contained content** | <article> info |
<aside> | An area like a sidebar with content distinct from the main article or page content | <aside> info |
<blockquote> | A quote from an specific source | <blockquote> info |
<button> | ALL buttons should be in <button> tags, not just styled as buttons | <button> info |
<dialog> | A popup modal or dialog box which is hidden by default | <dialog> info |
<map> | An image map (an image with clickable areas) | <map> info |
<meter> | A progress bar or gauge that isn’t interactive | <meter> info |
<picture> | Used similar to <video> or <audio>, and can have multiple sources | <picture> info |
<section> | An area of a dependent section of a larger document** | <section> info |
**Note: <article>s and <section>s are defined in a really confusing way, and are used in whatever makes sense to the developer. It is very common in practice to find an <article> with several <section>s inside, as well as <section>s with several <article>s inside. Neither way is wrong; just try to stay consistent within your own project.
Deprecated Tags (Don’t Use)
| HTML Tag | Explanation |
|---|---|
<b> | Used to be used for bold text. See note below. |
<center> | Used to be allowed to center text. Use CSS instead. |
<dir> | Used to be used for a directory list. Use <ol> instead. |
<font> | Used to define font, color, and size. Use CSS instead. |
<frame> | <frameset>, <frame>, and <noframes> all deprecated. |
<i> | Used to be used for italics. See note below. |
<strike> | Used to be used for strikethrough. Use <del> or <s> instead. |
**Note: Instead of <b> or <i> for bold and italic text, it is better to use specific tags for specific purposes, then style each one in CSS to be bold, italic, underlined, or use different fonts or colors as needed.
<em>for emphasis (usually italicized)<strong>for important (usually bold)<mark>for highlighted text<cite>for the title of a work<dfn>for term definitions
Tag-Specific Guidelines
If you need help with specific types of tags, there are excellent resources available at MDN:
- Web Page Metadata (HTML Document Boilerplate):
<DOCTYPE>,<html>,<head>,<meta>,<title>,<body> - Headings and Paragraphs:
<h1>-<h6>,<p> - Emphasis and Importance:
<strong>,<em>,<mark> - Lists:
<ol>,<ul>,<li>,<dl>,<dt>,<dd> - Advanced Text Features:
<blockquote>,<cite>,<q>,<abbr>,<address>,<sub>,<sup>,<time> - Representing Computer Code:
<code>,<pre>,<var>,<kbd>,<samp> - Creating Links:
<a> - Images:
<img>,<figure>,<figcaption> - Video and Audio:
<video>,<audio>,<source>,<track> - Table Basics:
<table>,<tr>,<td>,<th>,<colgroup>,<col> - Table Accessibility:
<caption>,<thead>,<tbody>,<tfoot> - Forms and Buttons:
<button>,<form>,<label>,<input>,<select>,<option>,<fieldset>,<legend>,<textarea>