HTML Guides for css
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The <font> element was originally introduced to give authors control over text rendering directly in markup. A typical usage looked like <font face="Arial" size="3" color="red">. While browsers still render this element for backward compatibility, it has been obsolete since HTML5 and will trigger a validation error. The W3C validator flags it because it violates the principle of separation of concerns: HTML should define the structure and meaning of content, while CSS should handle its visual presentation.
Using <font> causes several practical problems:
- Maintainability: Styling scattered across
<font>tags throughout your HTML is extremely difficult to update. Changing a color scheme could mean editing hundreds of elements instead of a single CSS rule. - Accessibility: The
<font>element carries no semantic meaning. Screen readers and other assistive technologies gain nothing from it, and its presence can clutter the document structure. - Consistency: CSS enables you to define styles in one place and apply them uniformly across your entire site using classes, selectors, or external stylesheets.
- Standards compliance: Using obsolete elements means your HTML does not conform to the current specification, which can lead to unexpected rendering in future browser versions.
To fix this issue, remove every <font> element and replace its visual effects with equivalent CSS properties. The three attributes of <font> map directly to CSS:
<font> attribute | CSS equivalent |
|---|---|
color | color |
size | font-size |
face | font-family |
You can apply CSS as inline styles for quick fixes, but using a <style> block or an external stylesheet with classes is the preferred approach for any real project.
Examples
Incorrect: using the obsolete <font> element
<p>
<fontface="Arial"size="4"color="blue">Welcome to my website</font>
</p>
This triggers the validator error: The "font" element is obsolete. Use CSS instead.
Fix with inline styles
If you need a quick, direct replacement:
<pstyle="font-family: Arial, sans-serif;font-size:18px;color: blue;">
Welcome to my website
</p>
Fix with a CSS class (recommended)
Using a class keeps your HTML clean and makes styles reusable:
<style>
.welcome-text{
font-family: Arial, sans-serif;
font-size:18px;
color: blue;
}
</style>
<pclass="welcome-text">Welcome to my website</p>
Nested <font> elements replaced with CSS
Old markup sometimes used multiple nested <font> tags:
<!-- Obsolete -->
<p>
<fontcolor="red"size="5">
Important:
<fontface="Courier">code goes here</font>
</font>
</p>
The correct approach uses <span> elements or semantic tags with CSS classes:
<style>
.alert-heading{
color: red;
font-size:24px;
}
.code-snippet{
font-family: Courier, monospace;
}
</style>
<p>
<spanclass="alert-heading">
Important:
<spanclass="code-snippet">code goes here</span>
</span>
</p>
If the text carries a specific meaning — such as marking something as important or representing code — consider using semantic HTML elements like <strong>, <em>, or <code> alongside your CSS:
<style>
.alert-heading{
color: red;
font-size:24px;
}
</style>
<pclass="alert-heading">
<strong>Important:</strong>
<code>code goes here</code>
</p>
This approach gives you full control over appearance through CSS while keeping your HTML meaningful, accessible, and standards-compliant.
The <tt> element was a purely presentational element — it described how text should look (monospaced) rather than what the text meant. HTML5 removed it as part of a broader effort to separate content from presentation. Browsers still render <tt> for backward compatibility, but validators will flag it as obsolete, and its use is discouraged in all new code.
The key issue is that <tt> was used for many different purposes — displaying code snippets, keyboard input, sample output, variables, filenames, and more — yet it conveyed none of that meaning to assistive technologies or search engines. HTML5 provides dedicated semantic elements for most of these use cases, making your content more meaningful and accessible.
Choosing the Right Replacement
Before reaching for a generic <span>, consider what the monospaced text actually represents:
- Code: Use
<code>for inline code fragments (e.g., variable names, short statements). - Keyboard input: Use
<kbd>for text the user should type. - Sample output: Use
<samp>for output from a program or system. - Variables: Use
<var>for mathematical or programming variables. - No semantic meaning: Use a
<span>with CSS when the monospaced styling is purely visual and none of the above elements apply.
All of these elements render in a monospaced font by default in most browsers (except <var>, which is typically italic). You can further style them with CSS as needed.
Examples
❌ Obsolete usage with <tt>
<p>Run the command <tt>npm install</tt> to install dependencies.</p>
<p>The variable <tt>x</tt> holds the result.</p>
<p>The output was <tt>Hello, world!</tt></p>
These all trigger the validator error: The "tt" element is obsolete. Use CSS instead.
✅ Fixed with semantic elements
<p>Run the command <kbd>npm install</kbd> to install dependencies.</p>
<p>The variable <var>x</var> holds the result.</p>
<p>The output was <samp>Hello, world!</samp></p>
Each replacement conveys the meaning of the text. <kbd> tells assistive technologies this is something the user types, <var> marks a variable, and <samp> indicates program output.
✅ Fixed with <code> for inline code
<p>Use the <code>Array.prototype.map()</code> method to transform each element.</p>
✅ Fixed with a <span> and CSS when no semantic element fits
If the monospaced text doesn't represent code, input, output, or a variable — for example, a stylistic choice for a filename or an arbitrary design decision — use a <span> with CSS:
<p>Edit the file <spanclass="mono">config.yaml</span> to change the settings.</p>
.mono{
font-family: monospace;
}
This keeps your HTML valid and your styling in the CSS layer where it belongs.
✅ Block-level code with <pre> and <code>
If you previously used <tt> inside a <pre> block for multi-line code, the standard approach is to combine <pre> with <code>:
<pre><code>function greet(name) {
return "Hello, " + name;
}</code></pre>
Summary
Replace every <tt> element with the semantic HTML element that best describes its content — <code>, <kbd>, <samp>, or <var>. If none of these fit, use a <span> styled with font-family: monospace in CSS. This keeps your markup valid, meaningful, and accessible.
In earlier versions of HTML (HTML 4 and XHTML), the type attribute was required on the <style> element to declare the MIME type of the styling language being used. The value was almost always text/css, as CSS has been the dominant stylesheet language for the web since its inception.
With HTML5, the specification changed. The type attribute on <style> now defaults to text/css, and since no browser supports any other styling language, the attribute serves no practical purpose. The WHATWG HTML Living Standard explicitly notes that the attribute is unnecessary and can be omitted. The W3C validator flags its presence as a warning to encourage cleaner, more modern markup.
Why This Matters
- Cleaner code: Removing unnecessary attributes reduces file size (even if marginally) and improves readability. Every attribute should earn its place in your markup.
- Standards compliance: Modern HTML encourages omitting default values when they add no information. Including
type="text/css"signals outdated coding practices. - Consistency: The same principle applies to
<script>elements, wheretype="text/javascript"is also unnecessary. Keeping your markup consistent by omitting both makes your codebase easier to maintain.
How to Fix It
The fix is straightforward: find every <style> element in your HTML that includes a type attribute and remove it. No other changes are needed — the browser behavior will be identical.
If you're working on a large codebase, a simple search for <style type= across your files will help you find all instances.
Examples
❌ Incorrect: Redundant type attribute
<styletype="text/css">
p{
color: red;
}
</style>
<p>This text will be red.</p>
The type="text/css" attribute is unnecessary and triggers the W3C validator warning.
✅ Correct: type attribute omitted
<style>
p{
color: red;
}
</style>
<p>This text will be red.</p>
Without the type attribute, the browser still interprets the contents as CSS — the behavior is exactly the same.
❌ Incorrect: Other variations that also trigger the warning
The warning is triggered regardless of how the type value is formatted:
<styletype="text/css"media="screen">
body{
font-family: sans-serif;
}
</style>
✅ Correct: Other attributes are fine, just remove type
<stylemedia="screen">
body{
font-family: sans-serif;
}
</style>
Note that other valid attributes like media or nonce should be kept — only the type attribute needs to be removed.
The valign attribute was part of earlier HTML specifications (HTML 4.01 and XHTML 1.0) and accepted values like top, middle, bottom, and baseline to control how content was vertically positioned within a table cell. In HTML5, this attribute is obsolete because the specification separates content structure from presentation. All visual styling should be handled through CSS.
This matters for several reasons. First, using obsolete attributes triggers W3C validation errors, which can indicate broader code quality issues. Second, browsers may eventually drop support for legacy presentational attributes, potentially breaking your layout. Third, CSS provides far more flexibility and maintainability — you can style entire tables or groups of cells with a single rule instead of repeating valign on every <td>.
The valign attribute was also valid on <th>, <tr>, <thead>, <tbody>, and <tfoot> elements, and it is obsolete on all of them. The fix is the same: use the CSS vertical-align property.
To fix this issue, remove the valign attribute from your <td> elements and apply the equivalent CSS vertical-align property. The CSS property accepts the same familiar values: top, middle, bottom, and baseline.
Examples
❌ Incorrect: using the obsolete valign attribute
<table>
<tr>
<tdvalign="top">Top-aligned content</td>
<tdvalign="middle">Middle-aligned content</td>
<tdvalign="bottom">Bottom-aligned content</td>
</tr>
</table>
✅ Fixed: using inline CSS
<table>
<tr>
<tdstyle="vertical-align: top;">Top-aligned content</td>
<tdstyle="vertical-align: middle;">Middle-aligned content</td>
<tdstyle="vertical-align: bottom;">Bottom-aligned content</td>
</tr>
</table>
✅ Fixed: using a class-based approach (recommended)
For better maintainability, define reusable CSS classes instead of repeating inline styles:
<style>
.valign-top{vertical-align: top;}
.valign-middle{vertical-align: middle;}
.valign-bottom{vertical-align: bottom;}
</style>
<table>
<tr>
<tdclass="valign-top">Top-aligned content</td>
<tdclass="valign-middle">Middle-aligned content</td>
<tdclass="valign-bottom">Bottom-aligned content</td>
</tr>
</table>
✅ Fixed: applying a default to all cells in a table
If every cell in a table should share the same vertical alignment, target them with a single CSS rule:
<style>
.data-tabletd,
.data-tableth{
vertical-align: top;
}
</style>
<tableclass="data-table">
<tr>
<th>Name</th>
<th>Description</th>
</tr>
<tr>
<td>Item A</td>
<td>A longer description that may<br>span multiple lines</td>
</tr>
</table>
This approach is the most maintainable — you set the alignment once and it applies consistently to every cell, without needing to modify individual <td> or <th> elements.
In earlier versions of HTML (HTML 4 and XHTML 1.0), the width attribute was a standard way to control the dimensions of tables and their cells. HTML5 marked this attribute as obsolete on table-related elements, meaning browsers may still render it, but it is no longer conforming HTML. The W3C validator will report a warning or error whenever it encounters this usage.
This matters for several reasons. First, using obsolete attributes means your markup doesn't conform to the HTML living standard, which can cause validation failures that obscure more critical issues. Second, relying on presentational HTML attributes mixes content with presentation, making your code harder to maintain. CSS provides far more flexibility and control — you can use relative units, media queries for responsive layouts, and centralized stylesheets that apply consistently across your site. Third, while current browsers still support the obsolete width attribute, future browser versions are not guaranteed to do so.
The fix is straightforward: remove the width attribute and apply the equivalent sizing with CSS. You can use inline styles for quick fixes, but a class-based or external stylesheet approach is generally preferred for maintainability.
Examples
❌ Incorrect: using the obsolete width attribute
<tablewidth="600">
<tr>
<tdwidth="200">Name</td>
<tdwidth="400">Description</td>
</tr>
</table>
This triggers the validator message: The "width" attribute on the "table" element is obsolete. Use CSS instead. — and the same for each <td>.
✅ Fixed: using inline CSS
<tablestyle="width:600px;">
<tr>
<tdstyle="width:200px;">Name</td>
<tdstyle="width:400px;">Description</td>
</tr>
</table>
✅ Better: using CSS classes
<style>
.data-table{
width:100%;
max-width:600px;
}
.data-table.col-name{
width:33%;
}
.data-table.col-desc{
width:67%;
}
</style>
<tableclass="data-table">
<tr>
<tdclass="col-name">Name</td>
<tdclass="col-desc">Description</td>
</tr>
</table>
Using classes keeps your HTML clean and makes it easy to adjust sizing in one place. Percentage-based widths also adapt better to different screen sizes.
❌ Incorrect: width on <col> and <colgroup>
<table>
<colgroupwidth="100">
<colwidth="50">
<colwidth="50">
</colgroup>
<tr>
<td>A</td>
<td>B</td>
</tr>
</table>
✅ Fixed: CSS on <col> elements
<table>
<colgroup>
<colstyle="width:50px;">
<colstyle="width:50px;">
</colgroup>
<tr>
<td>A</td>
<td>B</td>
</tr>
</table>
❌ Incorrect: width on <th>
<table>
<tr>
<thwidth="150">Header</th>
</tr>
</table>
✅ Fixed
<table>
<tr>
<thstyle="width:150px;">Header</th>
</tr>
</table>
Tips for migrating
- Search your codebase for
width=inside table-related tags. A regex like<(table|td|th|col|colgroup)[^>]+width=can help locate all instances. - Convert pixel values directly — a
width="200"attribute is equivalent towidth: 200pxin CSS. - Consider responsive design — this is a good opportunity to switch from fixed pixel widths to percentages,
emunits, or other flexible values. - Use
table-layout: fixedon the<table>element if you need columns to respect exact widths rather than auto-sizing based on content.
In earlier versions of HTML (HTML4 and XHTML), it was common to use attributes like align="center", bgcolor="#ff0000", or border="1" directly on elements to control their appearance. HTML5 enforces a clear separation between structure (HTML) and presentation (CSS). These presentational attributes are now considered obsolete, and the HTML specification instructs authors to use CSS for all visual styling.
This matters for several reasons:
- Standards compliance: Using obsolete attributes produces invalid HTML5, which can lead to unpredictable rendering across browsers.
- Maintainability: Scattering styling across HTML attributes makes it harder to update your site's design. CSS allows you to manage styles from a single location.
- Accessibility: Screen readers and assistive technologies work best with well-structured, standards-compliant HTML. Mixing presentation into markup can confuse these tools.
- Future-proofing: Browsers may eventually drop support for obsolete attributes entirely, breaking your layout.
To fix this issue, identify the obsolete attribute in your HTML, determine the equivalent CSS property, remove the attribute, and apply the CSS rule using a style attribute, an internal <style> block, or an external stylesheet.
Here is a reference of common obsolete attributes and their CSS equivalents:
| Obsolete Attribute | CSS Equivalent |
|---|---|
align="center" | text-align: center or margin: auto |
bgcolor="#fff" | background-color: #fff |
border="1" | border: 1px solid |
cellpadding="10" | padding: 10px (on td/th) |
cellspacing="5" | border-spacing: 5px (on table) |
width="500" | width: 500px |
height="300" | height: 300px |
valign="top" | vertical-align: top |
Examples
Obsolete align on a paragraph
❌ Incorrect: Using the obsolete align attribute on a <p> element.
<palign="center">Welcome to my site.</p>
✅ Fixed: Use the CSS text-align property instead.
<pstyle="text-align: center;">Welcome to my site.</p>
Obsolete bgcolor on a table
❌ Incorrect: Using bgcolor on a <table> element.
<tablebgcolor="#f0f0f0">
<tr>
<td>Data</td>
</tr>
</table>
✅ Fixed: Use background-color in CSS.
<tablestyle="background-color:#f0f0f0;">
<tr>
<td>Data</td>
</tr>
</table>
Obsolete cellpadding and cellspacing on a table
❌ Incorrect: Using cellpadding and cellspacing attributes.
<tablecellpadding="10"cellspacing="5">
<tr>
<td>Item</td>
<td>Price</td>
</tr>
</table>
✅ Fixed: Use border-spacing on the table and padding on the cells.
<tablestyle="border-spacing:5px;">
<tr>
<tdstyle="padding:10px;">Item</td>
<tdstyle="padding:10px;">Price</td>
</tr>
</table>
Obsolete width on an image
❌ Incorrect (in some contexts): Note that width and height on <img> elements are actually not obsolete — they are valid in HTML5 and recommended for layout stability. However, these attributes are obsolete on elements like <table>, <td>, <th>, and <hr>.
<tablewidth="600">
<tr>
<td>Content</td>
</tr>
</table>
✅ Fixed: Apply width via CSS.
<tablestyle="width:600px;">
<tr>
<td>Content</td>
</tr>
</table>
Using an external stylesheet (preferred approach)
For maintainability, move styles out of inline style attributes and into a stylesheet.
<!DOCTYPE html>
<htmllang="en">
<head>
<metacharset="utf-8">
<title>My Page</title>
<style>
.data-table{
width:600px;
background-color:#f0f0f0;
border-spacing:5px;
}
.data-tabletd{
padding:10px;
}
</style>
</head>
<body>
<tableclass="data-table">
<tr>
<td>Item</td>
<td>Price</td>
</tr>
</table>
</body>
</html>
This approach keeps your HTML clean and semantic while giving you full control over presentation through CSS.
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
Pro Trial
Full Pro access. Cancel anytime.
Start Pro Trial →Join teams across 40+ countries