---
title: "02 — HTML — Describing Meaning, Not Painting Pixels"
uid: html-fundamentals
tags: ["seo", "accessibility", "forms", "html", "semantic-html", "roadmap:frontend", "fundamentals"]
excerpt: "HTML describes meaning; how it looks is someone else's job. An <h1> isn't 'big bold text' — it's a claim about what the page's top-level heading is."
date: 2026-08-12T18:12:05+0000
source: https://www.aveshina.my.id/en/blog/html-fundamentals
---

"The tags that make text bold or draw a box" was how I treated HTML, which explained nothing about why the tags exist. The line that everything else hangs off: **HTML describes meaning. How it looks is someone else's job.** [1]

An <h1> doesn't mean "big bold text." It means "this is the top-level heading of the page." Big and bold is just what the browser's built-in stylesheet happens to do with that meaning. Swap the stylesheet (CSS) and the looks change completely; the meaning doesn't budge. I had the relationship backwards for years — I was picking tags for the appearance I wanted, when the only question I needed to answer was *what is this content?*

The payoff of getting that right is that three things I used to think were separate collapse into one. Semantic markup, accessibility, and SEO aren't three skills — they're one activity, "describe the meaning correctly," read by three different machines:

```figure
<svg viewBox="0 0 740 280" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-2xl" role="img" aria-label="One HTML document read by three different consumers. A box on the left labelled HTML declares what each piece of content is. Three arrows point right to three boxes: Browser plus CSS decides appearance as pixels on screen, Screen reader reads the meaning aloud for accessibility, and Search crawler builds a search index for SEO. Same meaning, read three ways.">
  <defs>
    <marker id="harrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">
      <path d="M0,0 L10,5 L0,10 z" fill="#64748b"/>
    </marker>
  </defs>
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">
    <!-- source: HTML doc -->
    <rect x="40" y="95" width="200" height="90" rx="10" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="140" y="128" font-size="14" font-weight="700" fill="#1e1b4b" text-anchor="middle">HTML document</text>
    <text x="140" y="150" font-size="11" fill="#475569" text-anchor="middle">declares what each</text>
    <text x="140" y="166" font-size="11" fill="#475569" text-anchor="middle">piece of content *is*</text>

    <!-- three consumers -->
    <rect x="500" y="30" width="210" height="60" rx="8" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
    <text x="605" y="56" font-size="13" font-weight="700" fill="#422006" text-anchor="middle">Browser + CSS</text>
    <text x="605" y="74" font-size="10.5" fill="#475569" text-anchor="middle">decides appearance · pixels</text>

    <rect x="500" y="110" width="210" height="60" rx="8" fill="#fce7f3" stroke="#db2777" stroke-width="1.5"/>
    <text x="605" y="136" font-size="13" font-weight="700" fill="#500724" text-anchor="middle">Screen reader</text>
    <text x="605" y="154" font-size="10.5" fill="#475569" text-anchor="middle">reads meaning aloud · a11y</text>

    <rect x="500" y="190" width="210" height="60" rx="8" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
    <text x="605" y="216" font-size="13" font-weight="700" fill="#052e16" text-anchor="middle">Search crawler</text>
    <text x="605" y="234" font-size="10.5" fill="#475569" text-anchor="middle">indexes meaning · SEO</text>

    <!-- arrows -->
    <path d="M240,125 C360,125 400,60 498,60" fill="none" stroke="#64748b" stroke-width="1.5" marker-end="url(#harrow)"/>
    <path d="M240,140 L498,140" fill="none" stroke="#64748b" stroke-width="1.5" marker-end="url(#harrow)"/>
    <path d="M240,155 C360,155 400,220 498,220" fill="none" stroke="#64748b" stroke-width="1.5" marker-end="url(#harrow)"/>

    <text x="370" y="262" font-size="11" fill="#64748b" text-anchor="middle" font-style="italic">same meaning — read three different ways</text>
  </g>
</svg>
```

This post you're reading is, at the bottom of the stack from last time, just such a document — the server sends HTML, and the browser turns meaning into the page on your screen. So what's actually in it?

## Elements, attributes, and the tree

HTML is made of **elements** — usually an opening tag, some content, and a closing tag, like <p>some text</p>. Elements carry **attributes**, key/value pairs on the opening tag that refine meaning or attach data: <a href="...">, <img src="..." alt="...">, <input type="email" required>. A handful of elements are **void** — <img>, <br>, <meta> — they have no content and no closing tag [2].

The thing I had to see clearly is that elements **nest**, and the nesting forms a tree. A <ul> contains <li>s; a <section> contains a heading and paragraphs. That parent/child structure *is* the source of the DOM the browser builds and everything (CSS, JavaScript, accessibility) reads from. Tags aren't a flat list of styling hints; they're a tree of meaning, where a tag's role depends on where it sits.

## Semantic HTML — describing what things *are*

This is the part I had to straighten out most. For years I reached for <div> for every block and <span> for every inline bit, because it "worked." But <div> and <span> carry **zero** meaning — they're generic containers, the fallback for when nothing semantic fits [3]. Wrapping a navigation menu in <div class="nav"> tells a browser nothing; the word nav in the class name is for me, not for the machine.

The semantic elements describe roles instead [3][4]:

- <article> — a self-contained piece that would make sense on its own (a blog post, a product card).
- <section> — a thematic grouping, almost always with a heading of its own.
- <nav> — a set of navigation links.
- <header> / <footer> — introductory / closing material for a page *or* a section.
- <main> — the dominant content of the page, exactly once per page, with nothing repeated across the site.
- <aside> — tangentially related content (a sidebar, "related posts").
- <figure> / <figcaption> — an image or diagram with a caption tied to it.

The test I use now: before I write a <div>, I ask *what is this block, in one word?* If I can name it — it's a navigation, an article, the page's main content — there's almost always a tag that already says that. Only if there genuinely isn't do I fall back to <div>.

A page laid out this way has a recognizable skeleton, and once you've seen it you start spotting it everywhere:

```figure
<svg viewBox="0 0 560 360" xmlns="http://www.w3.org/2000/svg" class="my-6 w-full max-w-xl" role="img" aria-label="A webpage skeleton labeled with semantic landmark tags. A top header band with a thinner nav band beneath it for primary links. The large middle area is main, split into an article (a self-contained post) with a section beneath it, and an aside on the right for related content. A bottom band is footer.">
  <g font-family="ui-sans-serif, system-ui, sans-serif" text-rendering="geometricPrecision">
    <!-- page frame -->
    <rect x="40" y="20" width="480" height="320" rx="10" fill="#f8fafc" stroke="#cbd5e1" stroke-width="1.5"/>

    <!-- header -->
    <rect x="40" y="20" width="480" height="44" fill="#e0e7ff" stroke="#6366f1" stroke-width="1.5"/>
    <text x="280" y="47" font-size="13" font-family="ui-monospace, monospace" font-weight="700" fill="#1e1b4b" text-anchor="middle">&lt;header&gt;</text>

    <!-- nav -->
    <rect x="40" y="64" width="480" height="30" fill="#c7d2fe" stroke="#6366f1" stroke-width="1.2"/>
    <text x="280" y="83" font-size="11" font-family="ui-monospace, monospace" font-weight="700" fill="#1e1b4b" text-anchor="middle">&lt;nav&gt; · primary links</text>

    <!-- main -->
    <rect x="40" y="94" width="332" height="216" fill="#fef9c3" stroke="#ca8a04" stroke-width="1.5"/>
    <text x="60" y="114" font-size="12" font-family="ui-monospace, monospace" font-weight="700" fill="#422006">&lt;main&gt;</text>
      <!-- article -->
      <rect x="56" y="124" width="300" height="84" rx="6" fill="#fffbeb" stroke="#ca8a04" stroke-width="1.2"/>
      <text x="206" y="162" font-size="12" font-family="ui-monospace, monospace" font-weight="700" fill="#422006" text-anchor="middle">&lt;article&gt; · a self-contained post</text>
      <text x="206" y="180" font-size="10" fill="#64748b" text-anchor="middle">with its own &lt;h1&gt; and headings</text>
      <!-- section -->
      <rect x="56" y="216" width="300" height="82" rx="6" fill="#fffbeb" stroke="#ca8a04" stroke-width="1.2"/>
      <text x="206" y="252" font-size="12" font-family="ui-monospace, monospace" font-weight="700" fill="#422006" text-anchor="middle">&lt;section&gt; · a thematic group</text>
      <text x="206" y="270" font-size="10" fill="#64748b" text-anchor="middle">a related chunk — still gets a heading</text>

    <!-- aside -->
    <rect x="372" y="94" width="148" height="216" fill="#fce7f3" stroke="#db2777" stroke-width="1.5"/>
    <text x="446" y="116" font-size="12" font-family="ui-monospace, monospace" font-weight="700" fill="#500724" text-anchor="middle">&lt;aside&gt;</text>
    <text x="446" y="136" font-size="10" fill="#64748b" text-anchor="middle">related / sidebar</text>

    <!-- footer -->
    <rect x="40" y="310" width="480" height="30" fill="#dcfce7" stroke="#16a34a" stroke-width="1.5"/>
    <text x="280" y="329" font-size="11" font-family="ui-monospace, monospace" font-weight="700" fill="#052e16" text-anchor="middle">&lt;footer&gt; · contact, copyright</text>
  </g>
</svg>
```

## Accessibility is semantics done well

This is where the model pays off first. A screen reader doesn't look at pixels — it reads the meaning the tags declare [5]. The heading elements <h1> through <h6> build an outline that a blind user navigates like a table of contents. The landmark elements — <main>, <nav>, <aside>, <header>, <footer> — let them jump straight to the part of the page they want, skipping chrome they've heard a hundred times. The alt attribute on <img> describes the image when it can't be seen; a <label> ties a caption to its form field so the field announces itself correctly.

The flip side matters as much: skipping heading levels for visual effect, or using <div onclick> instead of <button>, doesn't just look sloppy — it erases the meaning that someone's navigation literally depends on. A <button> is focusable, keyboard-operable, and announced as "button" to assistive tech; a clickable <div> is none of those unless you rebuild them by hand. Accessibility isn't a separate layer bolted on later. It's a question of whether the semantics actually made it onto the page.

## SEO is the same trick again

A search crawler is just *another reader* of the same meaning [6]. <title> and <meta name="description"> are the first thing it sees. A single <h1> tells it what the page is fundamentally about; well-structured headings and <article> tags tell it how the content is organized. Writing good semantics for humans and writing good semantics for Google turn out to be the same activity — which is exactly what you'd expect if the tags are describing meaning rather than painting pixels.

## Forms — where meaning gets interactive

Forms are the one corner of HTML where the meaning *does something* without JavaScript. <form> groups fields; <input> types like email, number, date, range, and color give the right on-screen control; <label>, required, pattern, and <select> wire up captions and validation [7]. Declaring type="email" on an input gets me the right mobile keyboard *and* built-in validation *and* an accessible control — one attribute, three wins. I reach for a native input before a JavaScript reimplementation almost every time. The browser already did the work; the trick is to tell it what I mean instead of reimplementing it.

## How I use this

The habit these notes left me with is a single pause: when I reach for a <div>, I stop and ask *what is this thing?* Most of the time a semantic tag already exists for the answer, and I should use it — the looks get sorted out later in CSS, and accessibility and SEO come along for free. <div> and <span> are the last resort, not the default.

That pause is the whole reason HTML ever felt hard. I was using it for a job it isn't meant to do — controlling appearance — and finding it arbitrary. Used for what it actually is, a way to describe meaning, it's almost embarrassingly straightforward.

## References

[1] Mozilla, "HTML basics," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/HTML_basics](https://developer.mozilla.org/en-US/docs/Learn/Getting_started_with_the_web/HTML_basics)

[2] WHATWG, "HTML Living Standard," 2024. [Online]. Available: [https://html.spec.whatwg.org/](https://html.spec.whatwg.org/)

[3] Mozilla, "HTML elements reference," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Web/HTML/Element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element)

[4] Google, "Use semantic HTML," web.dev, 2023. [Online]. Available: [https://web.dev/articles/semantic-html](https://web.dev/articles/semantic-html)

[5] Mozilla, "HTML: A good basis for accessibility," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML)

[6] Google, "Discover semantic HTML for better search results," web.dev, 2023. [Online]. Available: [https://web.dev/articles/discover-semantic-html](https://web.dev/articles/discover-semantic-html)

[7] Mozilla, "Web forms — Working with user data," MDN Web Docs, 2024. [Online]. Available: [https://developer.mozilla.org/en-US/docs/Learn/Forms](https://developer.mozilla.org/en-US/docs/Learn/Forms)

```quiz
Q: An <h1> tag means "big bold text." Is that what the tag *means*?
- Yes — <h1> literally means big bold text
- No — it means "top-level heading"; big-and-bold is just the default look
correct: 1
explain: <h1> declares the page's top-level heading. The bold, large rendering is the browser's default stylesheet reacting to that meaning — swap the CSS and the look changes while the meaning stays.

Q: You want to wrap the primary navigation links in the most meaningful element. Use…
- <div class="nav">
- <nav>
- <section class="menu">
correct: 1
explain: <nav> declares the role "navigation." A <div class="nav"> means nothing to machines — the word "nav" is only in a class name for the author.

Q: Why does writing good semantic HTML also improve accessibility and SEO?
- It doesn't — they each need their own separate tooling
- Because screen readers and search crawlers read the same meaning your tags declare
correct: 1
explain: A screen reader and a search crawler are just two more consumers of the document's meaning. Describe the meaning well and both benefit for free.

Q: You want an email field with the right mobile keyboard and built-in validation, for the least effort. Use…
- <input type="text"> plus a JavaScript validation library
- <input type="email" required>
correct: 1
explain: Declaring type="email" gives the correct mobile keyboard, native email validation, and an accessible control in one attribute — the browser already does the work.

Q: <div> and <span> are best described as…
- the default elements you should reach for first
- generic, meaning-free containers — the fallback when nothing semantic fits
correct: 1
explain: They carry no semantic role. Reach for a semantic tag first (article, nav, main, button…), and use <div>/<span> only when no meaningful element applies.
```
