Deprecated & Legacy HTML

HTML · Lesson 41 of 44 9 min read Updated

HTML is over thirty years old, and browsers still display pages written in the 1990s. So you will keep meeting old tags in college projects, government sites, old textbooks and even exam papers. Many still work in the browser, which makes them look acceptable. They are not.

In this lesson you will learn what "deprecated" and "obsolete" mean, recognise the old elements and attributes, understand XHTML-style syntax and old doctypes, and replace each one with its modern equivalent.

Deprecated, obsolete and removed

These words describe a feature's life cycle:

  • Deprecated was the term used by HTML 4.01 (1999) for features that still worked but should no longer be used, such as <font> and <center>.
  • Obsolete is the term used by today's WHATWG HTML Living Standard. Obsolete features must not be used in new pages, and a validator reports them as errors.
  • Obsolete but conforming is a small group, such as type="text/javascript" on a script, that a validator only warns about because the feature is harmless but pointless.
  • Removed features no longer do anything in browsers at all, such as <blink>.

Browsers keep rendering many obsolete tags so that millions of old pages do not break. "It still works" says nothing about whether markup is correct. Today's rule: HTML describes meaning, CSS handles looks.

Presentational elements

Before CSS was widely supported, HTML itself had tags for appearance. Run this example to see some of them working in your browser, next to their modern replacements.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Old and new</title>
  <style>
    .sale-title { text-align: center; font-family: Georgia, serif; font-size: 1.5rem; color: maroon; }
    .ticker { overflow: hidden; white-space: nowrap; background: #fff3c4; }
    .ticker span { display: inline-block; animation: slide 12s linear infinite; }
    @keyframes slide { from { transform: translateX(100vw); } to { transform: translateX(-100%); } }
    @media (prefers-reduced-motion: reduce) {
      .ticker span { animation: none; }
    }
  </style>
</head>
<body>
  <h2>Old markup (obsolete)</h2>
  <center><font face="Georgia" size="5" color="maroon">Diwali Sale at Rohtak Sweets</font></center>
  <marquee>Kaju katli at ₹1,100 per kg, this week only</marquee>

  <h2>Modern markup</h2>
  <h1 class="sale-title">Diwali Sale at Rohtak Sweets</h1>
  <p class="ticker"><span>Kaju katli at ₹1,100 per kg, this week only</span></p>
</body>
</html>

Both versions look much the same, but the modern one keeps meaning in the HTML (a real heading) and looks in the CSS, and its ticker stops for people who asked their device to reduce motion. Better still is no moving text at all.

Old elementWhat it didModern replacement
<font>Typeface, size (1 to 7) and colourCSS font-family, font-size, color
<center>Centred its contentCSS text-align: center, or Flexbox and Grid
<big>Larger textCSS font-size, or <strong> or a heading if it means something
<tt>Typewriter text<code>, <kbd>, <samp> or <var>
<strike>Line through text<s> for no-longer-true text, <del> for edits
<marquee>Scrolling textNothing, or a gentle CSS animation that respects reduced motion
<blink>Blinking textNothing (no current browser blinks)
<acronym>Abbreviation<abbr title="...">
<dir>Directory list<ul>

Presentational attributes

Many old attributes also controlled appearance. They are obsolete on the web, although you will still see them in HTML Emails, where they help old email apps.

Old attributeFound onModern replacement
alignp, div, img, table, tdCSS text-align, Flexbox, Grid or margin-inline: auto
valigntd, trCSS vertical-align
bgcolorbody, table, tdCSS background-color
backgroundbody, tdCSS background-image
border, cellpadding, cellspacingtableCSS border, padding, border-spacing or border-collapse
width, heighttable, tdCSS width and height (still correct on img, video, canvas and iframe)
text, link, vlink, alinkbodyCSS color and the :link, :visited and :active pseudo-classes
hspace, vspaceimgCSS margin
clearbrCSS clear

Here is a typical old table and its clean modern version:

HTML
<!-- OLD -->
<table border="1" cellpadding="6" cellspacing="0" width="400" bgcolor="#fff3c4" align="center">
  <tr><td align="right" valign="top"><b>Fees</b></td><td>₹1,299</td></tr>
</table>

<!-- MODERN -->
<table class="fees">
  <tr><th scope="row">Fees</th><td>₹1,299</td></tr>
</table>
CSS
.fees { width: 400px; margin-inline: auto; border-collapse: collapse; background: #fff3c4; }
.fees th, .fees td { border: 1px solid #999; padding: 6px; vertical-align: top; }
.fees th { text-align: right; }

The bold "Fees" cell became a real header cell, <th>, which also helps screen readers.

Frames and other removed features

<frameset>, <frame> and <noframes> split the window into separate pages. They are obsolete; Page Layout Techniques explains why and shows the replacements: templates or server-side includes for shared menus, and <iframe> for embedding.

<applet> ran Java programs and is obsolete too. Flash, usually loaded with <embed> or <object>, no longer runs in any browser. Those two elements are still valid, but for media and animation use <video>, <audio>, <canvas> and JavaScript.

Elements whose meaning changed

Some old elements were kept but given a new meaning. They are valid when used for that meaning.

ElementOld meaningMeaning today
<b>BoldText you want to draw attention to without extra importance, such as a product name
<i>ItalicText in an alternate voice: a foreign word, a scientific name, a thought
<u>UnderlineA non-textual annotation, such as a misspelling mark; otherwise avoid it, as it looks like a link
<small>Smaller textSide comments and small print, such as terms and conditions
<s>StrikethroughContent that is no longer accurate, such as an old price
<hr>A horizontal lineA thematic break between topics
<cite>Any citation or reference to a sourceThe title of a work, such as a book or film

If text is important, use <strong>; if it is stressed, use <em>; if you only want bold or italic looks, use CSS. More in Text Formatting.

XHTML-style syntax

Around 2000, XHTML rewrote HTML with the strict rules of XML: lowercase tags, every element closed, every attribute quoted and given a value. You will recognise it by self-closing slashes and long attribute forms:

HTML
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
<br />
<img src="logo.png" alt="Logo" />
<input type="checkbox" checked="checked" />

All of this is still accepted in HTML. On void elements, those that can never have content such as <br>, <img>, <input> and <meta>, the slash is allowed but does nothing. The trap is using a self-closing slash on an element that is not void. HTML ignores the slash, so the element stays open and swallows what follows:

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Self-closing trap</title>
  <style>
    .box { border: 3px solid crimson; padding: 4px; }
  </style>
</head>
<body>
  <div class="box" />
  <p>This paragraph was meant to be outside the red box.</p>
  <p>So was this one. The slash in &lt;div /&gt; did not close the div.</p>
</body>
</html>

Both paragraphs end up inside the red box, because <div /> is read as an ordinary opening tag. The same mistake with <script src="app.js" /> is worse: everything after it is treated as script text. Always close non-void elements with a real closing tag, such as <div></div> and <script src="app.js"></script>.

Old doctypes and quirks mode

Old pages begin with long doctypes that named a version of HTML:

Text
HTML 4.01 Strict:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

HTML 4.01 Transitional (allowed the presentational tags):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

XHTML 1.0 Strict:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

Browsers never really checked these versions. They only use the doctype to choose a rendering mode:

  • No-quirks (standards) mode: modern behaviour. Triggered by <!DOCTYPE html> and the strict doctypes.
  • Limited-quirks (almost standards) mode: standards mode with one small difference in how images inside table cells are sized. Triggered by the transitional and frameset doctypes.
  • Quirks mode: copies old browser bugs so 1990s pages keep their look. Triggered by a missing doctype or some incomplete old ones. For example, CSS then accepts lengths without units, and class names match regardless of case.

This script parses sample pages and reads their compatMode: "CSS1Compat" means standards or almost standards mode, and "BackCompat" means quirks mode.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Doctype checker</title>
  <style>td { padding: 4px 10px; border-bottom: 1px solid #ddd; }</style>
</head>
<body>
  <table id="results"></table>
  <script>
    const samples = {
      "<!DOCTYPE html>": "<!DOCTYPE html><p>Hi</p>",
      "No doctype at all": "<p>Hi</p>",
      "HTML 4.01 Strict": '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><p>Hi</p>',
      "HTML 4.01 Transitional": '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><p>Hi</p>',
      "HTML 4.01 Transitional, no URL": '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><p>Hi</p>',
    };
    const table = document.querySelector("#results");
    for (const [name, source] of Object.entries(samples)) {
      const mode = new DOMParser().parseFromString(source, "text/html").compatMode;
      const row = table.insertRow();
      row.insertCell().textContent = name;
      row.insertCell().textContent = mode === "BackCompat" ? "Quirks mode" : "Standards (or almost)";
    }
  </script>
</body>
</html>

The missing doctype and the incomplete transitional doctype both fall into quirks mode. Today there is no reason to use anything except the short <!DOCTYPE html>, which always gives standards mode.

Upgrading an old page

When you inherit an old page, work through it in this order:

  1. Use <!DOCTYPE html>, <meta charset="utf-8"> and the viewport meta tag, then recheck the layout, because leaving quirks mode can change sizes.
  2. Replace <font>, <center>, align, bgcolor and similar markup with classes in a stylesheet.
  3. Replace layout tables and framesets with semantic elements and CSS Grid or Flexbox.
  4. Change <a name="..."> targets to id attributes, and drop type="text/javascript", language="javascript" and type="text/css".
  5. Run the result through the validator, as shown in Best Practices & Validation.

Common mistakes

  • Assuming that "it still works" means it is correct. Browsers render obsolete tags only for old pages.
  • Self-closing non-void elements. <div /> and <script /> do not close; write the end tag.
  • Replacing <b> with <strong> everywhere. <strong> means importance; use CSS when you only want bold.
  • Leaving out the doctype. The page falls into quirks mode and behaves unpredictably.
  • Moving text with <marquee>. It is obsolete and hard to read; keep text still.

Key points

  • Deprecated (HTML 4) and obsolete (today's standard) features must not be used in new pages, even if browsers still display them.
  • Presentational elements and attributes such as <font>, <center>, align and bgcolor are replaced by CSS.
  • Frames, applets, Flash and <blink> are gone; use templates, iframes for embedding, and modern media elements.
  • <b>, <i>, <u>, <small>, <s> and <hr> are valid today with new meanings.
  • XHTML slashes are harmless on void elements, but <div /> and <script /> do not close.
  • Only <!DOCTYPE html> is needed; a missing or incomplete doctype triggers quirks mode.

Exercise

Modernise this old snippet. Keep the same look but use valid, meaningful HTML and a <style> element: <body bgcolor="#fffbe6"><center><font size="6" color="green">Kochi Tea Traders</font></center><a name="prices"></a><p align="right"><font color="red"><b>New:</b></font> Assam tea at ₹480 per kg</p><br clear="all" /><marquee>Free delivery in Ernakulam</marquee></body>

Show solution
HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Kochi Tea Traders</title>
  <style>
    body { background-color: #fffbe6; }
    h1 { text-align: center; color: green; }
    .prices { text-align: right; }
    .new { color: red; font-weight: bold; }
  </style>
</head>
<body>
  <h1>Kochi Tea Traders</h1>
  <p class="prices" id="prices"><span class="new">New:</span> Assam tea at ₹480 per kg</p>
  <p>Free delivery in Ernakulam.</p>
</body>
</html>

The shop name is a real heading, every colour and alignment moved to CSS, the empty <a name> target became an id, and the scrolling <marquee> became a still, readable paragraph.

Quick Quiz

1. Which is the modern way to centre a heading?

2. What happens with <div class="note" /> in an HTML page?

3. What does <i> mean in today's HTML?

4. A page has no doctype. Which rendering mode does the browser use?

Learn HTML with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call