HTML Guide
The <ul> element is used to define unordered lists, where each element must be contained within a <li> element, like in this example:
<ul>
<li>first element</li>
<li>second element</li>
<li>third element</li>
</ul>
Ensure that there’s no content inside the <ul> element that is not contained within a <li> element.
Sometimes this error comes when trying to give a title to the list, for example:
<ul>
Fruits
<li>Apple</li>
<li>Orange</li>
</ul>
Instead, that title text should be outside the list, like:
<span>Fruits</span>
<ul>
<li>Apple</li>
<li>Orange</li>
</ul>
Other times, this can come as the concatenation of <li> elements which results in something like:
<ul>
<li>First item</li>
<li>Second item</li>
<li>Third item</li>
</ul>
Note how in this case that used to join the <li> is causing the problem, as it’s content that is not contained by a <li> element, as required by the <ul> element.
Read about Normalization in HTML and CSS.
The <th> HTML element defines a cell as a header of a group of table cells, and must appear within a <tr> element.
In the following example for a simple table, the first <tr> contains two <th> header cells naming the values for each column:
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr>
<td>Liza</td>
<td>49</td>
<tr>
<tr>
<td>Joe</td>
<td>47</td>
</tr>
</table>
The old <acronym> element in previous versions is now obsolete, in HTML5 you must use <abbr> instead.
<td> elements no longer accept an align attribute. This can be achieved using CSS like this:
<td style="text-align:center;">content</td>
The aria-controls attribute identifies an element or elements in the same document whose contents or presence are controlled by the current element. It must point to existing elements by their ID. Check that the IDs contained in that property exist within the same document.
ARIA can express semantic relationships between elements that extend the standard parent/child connection, such as a custom scrollbar that controls a specific region, for example:
<div role="scrollbar" aria-controls="main"></div>
<div id="main">
. . .
</div>
The aria-describedby attribute is used to indicate the IDs of the elements that describe the object. It should reference an existing ID on the same document, but that id was not found.
The aria-hidden attribute is redundat on an input of type hidden, so it should be removed.
Example:
<!-- Instead of this... -->
<input type="hidden" aria-hidden="true" id="month" value="10" />
<!-- You can just use this -->
<input type="hidden" id="month" value="10" />
The aria-hidden attribute is not allowed on the link element according to HTML and ARIA specifications.
aria-hidden is a global ARIA attribute used to hide elements from assistive technologies such as screen readers. However, it is not permitted on some elements, including the link element, because link is a void element intended for non-visible resources like stylesheets and icons.
Incorrect usage:
<link rel="stylesheet" href="styles.css" aria-hidden="true">
Correct usage (simply remove aria-hidden):
<link rel="stylesheet" href="styles.css">
If your intent is to control screen reader visibility, apply aria-hidden to visible content elements like <div>, <span>, or <img>—not to metadata elements such as <link>.
The aria-labelledby attribute establishes relationships between objects and their label(s), and its value should be one or more element IDs. It should reference an existing ID on the same document, but that id was not found.
The aria-owns attribute contains an ID reference that does not match any element in the same document.
According to the ARIA specification and the WHATWG HTML standard, the value of the aria-owns attribute must be a space-separated list of IDs of elements that exist in the same DOM document. This attribute is meant to modify the accessibility tree by creating relationships not present in the DOM structure, but all referenced elements must be part of the same document. If an ID in the aria-owns attribute does not match any element, is in another document (such as an iframe), or contains a typo, validation will fail.
Common reasons for this issue:
- Referencing a nonexistent ID.
- Referencing an ID from another document (e.g., across iframes).
- Typos in the ID value.
Correct usage:
<div id="container" aria-owns="owned-element">
<p>Container</p>
</div>
<div id="owned-element">
<p>Owned by container (in accessibility tree)</p>
</div>
Incorrect usage (missing or cross-document ID):
<div id="parent" aria-owns="child"></div>
<!-- Missing <div id="child"> or 'child' exists in a different frame/document -->
To fix the issue, ensure that all IDs referenced in aria-owns correspond to elements present in the same document.
Complete valid example:
<!DOCTYPE html>
<html lang="en">
<head>
<title>aria-owns Example</title>
</head>
<body>
<div id="menu" aria-owns="item1 item2">
Main menu (accessibility tree owner)
</div>
<div id="item1">
Menu item 1
</div>
<div id="item2">
Menu item 2
</div>
</body>
</html>
The article role indicates a section of a page that could easily stand on its own on a page, in a document, or on a website, is implicit when using the <article> tag.
This role indicates a section of a page that could easily stand on its own on a page, in a document, or on a website. It is usually set on related content items such as comments, forum posts, newspaper articles or other items grouped together on one page. It can be added to generic elements like <div> to convey this role, for example:
<div role="article">
<h2>Heading</h2>
<p>Content...</p>
</div>
Instead of using this role, it’s preferrable to use the native <article> element like this:
<article>
<h2>Heading</h2>
<p>Content...</p>
</article>
The <header> HTML element represents introductory content, typically a group of introductory or navigational aids, and has an implicit role of banner, so specifying this role is redundant.
The following example represents a banner using the role attribute:
<div role="banner">
<img src="companylogo.svg" alt="my company name" />
<h1>Title</h1>
<p>Subtitle</p>
</div>
By default, the HTML5 <header> element has an identical meaning to the banner landmark, unless it is a descendant of <aside>, <article>, <main>, <nav>, or <section>, at which point <header> is the heading for that section and not the equivalent of the site-wide banner.
This example uses the <header> element instead of the banner role:
<header>
<img src="companylogo.svg" alt="my company name" />
<h1>Title</h1>
<p>Subtitle</p>
</header>
The <big> tag is now obsolete. It was used to increase the size of text, you can do that using CSS instead. For example:
<p>Now this is <span style="font-size: larger;">big</span></p>
<img> tags no longer accept a border attribute. This can be defined using CSS instead, for example:
<img src="..." alt="..." style="border:0;" />
The button role is used to make an element appear as a button control to a screen reader and can be applied to otherwise non-interactive elements like <div>. If you’re already using a <button> element, then it’s redundant to apply it the role button, as that’s implicit.
<!-- Instead of this -->
<button role="button">Buy</button>
<!-- Do this -->
<button>Buy</button>
The button role is used to make an element appear as a button control to a screen reader and can be applied to otherwise non-interactive elements like <div>. If you’re already using an <input> element whose type is submit, then it’s redundant to apply it the role button, as that’s implicit.
<!-- Instead of this -->
<input type="submit" role="button">Buy</button>
<!-- Do this -->
<input type="submit">Buy</button>
The <summary> HTML element specifies a clickable summary, caption, or legend for a <details> element’s disclosure box. As the <summary> element has an implicit button role, it’s not needed to include it explicitly.
Here’s an example, clicking the <summary> element toggles the state of the parent <details> element open and closed.
<details>
<summary>I have keys but no doors. I have space but no room. You can enter but can’t leave. What am I?</summary>
A keyboard.
</details>
The <center> tag is no longer valid in HTML, you should use CSS instead, for example:
<p style="text-align:center">this text will be centered</p>
Add a meta tag specifying the character encoding in the document’s <head> section.
HTML documents must explicitly declare their character encoding to ensure browsers correctly interpret all characters. The recommended way is using the meta charset element, which should appear as early as possible within the <head>. UTF-8 is the most widely used encoding and should be preferred for web content, but based on the page content, the “windows-1252” encoding is suggested.
Example of a complete HTML5 document with UTF-8 encoding:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Character Encoding Example</title>
<meta charset="utf-8">
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
Place the <meta charset="utf-8"> tag before any content in the <head> to avoid encoding issues.
The W3C Validator is indicating that the charset attribute on the link element is obsolete. According to modern HTML standards, the charset attribute should not be used on the <link> element, and instead, the character encoding should be specified via an HTTP Content-Type header on the server response of the resource.
Here’s how you can address and fix the issue:
1. Remove the charset attribute from the <link> element:
You should simply remove the charset attribute from the <link> element in your HTML file.
Before:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="styles.css" charset="UTF-8">
<title>Example Page</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
After:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="styles.css">
<title>Example Page</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
2. Set the charset using HTTP Headers:
To ensure that the correct character encoding is used, you should configure your web server to send the appropriate Content-Type header with the CSS file.
-
For Apache: You can modify the .htaccess file or the server configuration file.
<FilesMatch "\.css$"> AddCharset UTF-8 .css </FilesMatch>
-
For Nginx: You can add the following directive to your server block or location block:
location ~* \.css$ { charset utf-8; }
-
For Express.js (Node.js): You can set headers in your response:
app.get('/styles.css', function(req, res) { res.setHeader('Content-Type', 'text/css; charset=UTF-8'); res.sendFile(__dirname + '/styles.css'); });
A <script> element has been found that is using the now obsolete charset attribute. You can safely remove this attribute.
For example, this is using both type and charset attributes, with their default values. Both can be removed:
<script src="app.js" type="text/javascript" charset="UTF-8"></script>
and just use this:
<script src="app.js"></script>
Using the <aside> element will automatically communicate a section has a role of complementary, so specifying the role="complementary" is redundant.
The <footer> element represents a footer for its nearest sectioning content, and has an implicit role of contentinfo, so specifying this role is redundant.
The following example marks a <div> as a footer specifying its role:
<div role="contentinfo">
<h2>Footer</h2>
<!-- footer content -->
</div>
Using the <footer> element instead is recommended:
<footer>
<h2>Footer</h2>
<!-- footer content -->
</footer>
The role="dialog" attribute is redundant when used on a <dialog> element because <dialog> has an implicit dialog role by default.
According to the WHATWG HTML living standard and ARIA in HTML, the <dialog> element already has the appropriate semantics for assistive technologies, so explicitly adding role="dialog" is unnecessary and causes warnings in validators.
Incorrect usage:
<dialog role="dialog">
This is a dialog box.
</dialog>
Correct usage:
<dialog>
This is a dialog box.
</dialog>
Simply remove the role attribute from the <dialog> element to resolve the warning.