bUt WhAtAbOuT sEmAnTiCs?

UIScript DevBlog, Part 18

Bence Meszaros
8 min readNov 5, 2024
The entirety of the HTML language

I always find it hilarious when HTML cultists are trying to explain what semantics are.

I mean, look at this poor guy, getting downvoted into oblivion just because he asked the exact same question. Not a single proper answer, just a petition to close this thread because apparently HTML semantics is not about programming.

If so, then please, enlighten us genius, what is it about?

Is it about layout structure?

Of course not. HTML semantics should never describe the layout. You should use CSS for that.

OK, is it about styling? I mean, we do have tags like <b> (bold), <i> (italic), <u> (underline) and <s> (strikethrough).

No. These tags are the Bring Attention To, the Idiomatic Text and the Unarticulated Annotation. Semantics should never be used to describe styling either. Except maybe the <s> tag. We still call that the Strikethrough element.

How about interactivity, then? We do have multiple button implementations and even the <a> tag acts like one. How else would a website be interactive without JS?

No, sorry, semantics is not about interactivity either. Things like linking external resources, loading files, submitting forms and making HTTP requests don’t count.

So, accessibility then?

No, we have ARIA for that. It defines its own semantics, API, even its own accessibility tree.

How about SEO? Is it about boosting your rankings?

No, it’s not. At least according to Google.

Then what? What is HTML semantics about?

Well, semantics is the meaning of the information. We use it to categorize and make sense of our data.

Like the type of the data, right?

Well, yeah, duh.

Well, I hate to break it to you, but you just reinvented data types. You know, the literal cornerstone of any programming language, ever.

Ouch.

OK, but seriously though, what does semantics mean?

As I see it, it just means “organize your code”.

The problem is, it is hard to do in HTML, because it is a badly organized language that discourages good practices and encourages bad ones.

You can bitch and moan about the fact that nobody cares about semantic HTML, but it is pretty disingenuous considering that the language itself is clearly missing the mark in the semantics department, to put it mildly.

Let’s see some examples.

Inside, outside or in-between

Our first stop is the various implementations of a thing called titles.

First, tables use the <caption> element, but it doesn’t work for <img> elements, because they are void. So we need to wrap images in a <figure> element, then use the <figcaption> (and not simply the <caption>) inside of it.

But then, we have the <fieldset> that isn’t void, but it uses neither <caption> nor <figcaption> and instead introduces <legend>, a third element, to achieve the exact same thing.

So, what about an article, then? Its title is literally called the TITLE. How does HTML handle that?

Well, there is a <title> element, but that works for the entire document. The title of an article is called heading. No, not <head> or <header>, but heading, you know <h1> through <h6>.

But wait, there is also the title attribute that is global, thus valid for every single HTML element.

Now what?

<html title="I am not the title of the document">
<head title="I am not the title either">
<title title="Me neither">I am the title</title>
</head>
</html>

Are you beginning to see the problem here?

Not only is HTML using various names for the exact same thing, but it also uses three naive and fundamentally different approaches.

Let’s say we want to set a title for a video. How would you do that?

Like this?

<video>
<title>My favorite video</title>
</video>

This?

<wrapper>
<title>My favorite video</title>
<video></video>
</wrapper>

Or this?

<video title="My favorite video">

Aside from the fact that you can choose from a multitude of names, you have three wildly different options: set the title inside the element, set the title outside of the element or set the title in between the two using an attribute.

Since there are no rules to settle this in HTML, all three are actively being used by the language:

  • the <img> element cannot have elements inside of it, so it has to set its title outside using a wrapper
  • on the other hand the document cannot have elements outside of it, so it does the opposite
  • and many elements are using the title attribute (eg. <p>, <input>, <abbr>, <th>) albeit for tooltips, that isn’t a semantic use of this attribute at all, but who cares about semantics right?

And since we don’t have a general rule, we don’t know which option to choose for which elements.

How does a title work for an svg for example? Or for a math formula?

What about <embed> or <object>?

Which approach is considered “semantic” for which elements and why?

Visible vs non-visible

Another intrinsic semantic issue is that HTML fails to understand the difference between data and metadata or visible and non-visible data.

The question here is simple: which elements are visible and which are not?

Elements like <head>, <meta>, <link> and <script> are all about metadata so they shouldn’t be visible. But it turns out that all of these and basically all elements can be made visible through CSS, even though this shouldn’t be possible.

That’s right, we can make any of these elements visible by simply changing their display properties:

<head style="display: block">
<meta style="display: block">
<link style="display: block">
<script style="display: block"></script>
</head>

You can say that this is an anti-pattern, this is invalid code, this is against the rules, but this code is actually perfectly valid HTML.

What we can’t do is to make for example the style attribute visible on its own, or a transition inside of it, which by the way are also objects, just like the element itself:

<div style="transition: top 4s ease-in-out">
//same element, but represented using actual objects
let div = {
style: {
transition: {
property: "top",
duration: 4,
easing: "ease-in-out"
}
}
}

The HTML syntax suggests, that elements are always visible, but data stored in their attributes aren’t, because they always act as metadata.

But then, you also have <input type="hidden"> that is truly invisible, regardless of CSS. Well, until you change the type attribute, that is.

But wait, there is also the hidden global attribute that works on any element. So, is it

  • <input hidden>, or
  • <input hidden="hidden">, or
  • <input type="hidden">, or
  • <input hidden type="hidden">, or
  • <input hidden="hidden" type="hidden">?

Or should we throw in some CSS too, just to be on the safe side?

<input hidden="hidden" type="hidden" style="display: hidden">

Again, I want to remind you that these are not theoretical examples, everything here is completely valid HTML.

At this point HTML cultists usually argue that having options is actually a good thing and yes, I do tend to agree.

But what we see here, however, has nothing to do with having options but rather, it is the identity crisis of HTML, the opposite of semantics.

HTML fails to recognize that its syntax has created two distinct classes of objects: actual elements and objects stored in their attributes. If we want actual, visible data, we should rely on elements and if we want meta, non-visible data, we should rely on attributes.

Take a look at this theoretical example:

<html head="meta: ...; link: ...; script: ...">

Anything that is stored inside an attribute will never clash with actual data, it is always hidden and we cannot change this or manipulate it in any way whatsoever using CSS. Plus, we don’t even need the hidden attribute, the separation is crystal clear and unambiguous.

It is hard to beat the semantics of this example, but sadly, this isn’t valid HTML.

Loading

Then, there is the problem of loading an external resource into an HTML document.

Again, a fairly simple thing to do and yet, we have a plethora of naive implementations that have basically nothing in common.

For example, there are only two supplementary languages to HTML — CSS and JavaScript — but the way HTML handles them couldn’t be more different:

  • <script> can work with both internal and external scripts, while <style> can only work with internal styles
  • we need the <link> tag to load external styles, even though we barely use <link> with anything else other than .css files
  • <script> uses the src attribute, <link> uses href but it also needs the rel attribute
  • <link> is a void element, but <script> can never lose its closing tag
<script>let foo = "foo";</script>
<script src="script.js"></script>

<style>#foo {color: black;}</style>
<link rel="stylesheet" href="style.css">

Going beyond these two, the landscape becomes even more chaotic.

We cannot load one html document into another by simply using href, src, rel or any other attribute directly on an <html> element, we need an additional <iframe> element for that.

<svg> suffers the same way, we either include an <image> element inside of it and use that to load an external file or use the <object> element. Neither allows further content manipulation.

Loading .json is even worse, since there isn’t any HTML element that supports it natively, so we need to rely entirely on JS to load it.

And the list goes on.

So, what if, instead of this mess, HTML would look something like this:

<image  url="image.jpg">
<svg url="svg.svg">
<audio url="audio.mp3">
<video url="video.mp4">
<track url="track.vtt">
<style url="style.css">
<script url="script.js">
<html url="html.html">
<xml url="xml.xml">
<math url="math.mml">
<object url="object.pdf">
<text url="text.txt">

Would you still think that the current state of HTML is more semantic than this?

Further examples

HTML is so badly structured that we find semantic issues everywhere:

  • whitespace elements: code formatting and data isn’t separated, so we need things like <br>, <wbr> and <pre> to make working with whitespace barely possible
  • form elements: they shouldn’t even be considered form elements because they happily work outside of them too, forms are just one specific use case
  • input elements: <textarea> and <select> should be input too, but <button> shouldn’t be, also, <input> should be several separate elements
  • table elements: chaotic names for tags and for attributes as well, eg. <td> instead of <tc>, <tr> for table row, but <col> for table column, <colgroup> with span vs <td> with colspan, and so on
  • attributes: fully inconsistent as well, like type in itself, type vs kind, src vs href vs rel vs data and so on

Now, I understand that it is paramount to debate whether <s> or <del> is the appropriate label for a piece of text, or to advocate for the use of elements like <header>, <section>, <main>, <aside> and <footer> in a text heavy environment instead of using generic or even incorrect containers, but the thing is, there are an overwhelming number of websites that just aren’t text heavy.

Instead, they are focusing on graphic design, multimedia and interactivity where text is just one of many media types we need to work with.

Unfortunately, more than half of all HTML elements (61 out of 116) are designed specifically for text and textual documents while the remaining narrow half includes everything else from metadata, multimedia (including raster and vector graphics, audio and video), interactivity, embedding, scripting and styling, to web components, forms, tables and even math.

You don’t have to be a genius to see where this leads.

Outro

That’s all I have for you today.

Thank you for making it to the end and I hope that you’ve found it interesting.

If you like my project, please consider clapping, commenting and sharing my work with others.

Thank you again, take care and stay tuned.

⬅️ Part 17 — How to fix HTML form inputs

--

--

Bence Meszaros
Bence Meszaros

Written by Bence Meszaros

Lead Software Engineer, Fillun & Decketts

Responses (1)