Landmarks

랜드마크

Marking a page into regions with semantic tags — header, nav, main, aside, footer — so a screen reader user can jump between them instead of scrolling line by line.

Also known as: ARIA landmarksPage regions
···
html
<div class="stage">
  <div class="pane">
    <div class="tag">div soup</div>
    <div class="mini">
      <div class="b"></div>
      <div class="b"></div>
      <div class="b tall"></div>
      <div class="b"></div>
    </div>
    <div class="list empty">landmarks: (none)</div>
  </div>
  <div class="pane">
    <div class="tag">semantic tags</div>
    <div class="mini">
      <div class="b l" id="r0"></div>
      <div class="b l" id="r1"></div>
      <div class="b l tall" id="r2"></div>
      <div class="b l" id="r3"></div>
    </div>
    <div class="list" id="rotor">banner</div>
  </div>
</div>
css
.stage{width:94%;height:88%;display:flex;gap:4%}
.pane{position:relative;flex:1;border-radius:14px;border:1px solid var(--line);background:var(--surface);display:flex;flex-direction:column;padding:10px 8% 8px;gap:6%;overflow:hidden}
.tag{flex:none;font:700 10px/1 ui-monospace,monospace;color:var(--muted)}
.mini{flex:1;min-height:0;display:flex;flex-direction:column;gap:6%}
.b{border-radius:6px;background:var(--muted);opacity:.25;flex:1;min-height:0}
.tall{flex:2}
.l{opacity:.4;transition:opacity .3s ease,outline-color .3s ease;outline:2px solid transparent;outline-offset:-2px}
.l.hit{opacity:1;outline-color:var(--accent)}
.list{flex:none;font:700 10px/1 ui-monospace,monospace;color:var(--accent-3);text-align:center}
.list.empty{color:var(--muted);opacity:.5}
js
const rows = [
  { el: document.getElementById('r0'), name: 'banner' },
  { el: document.getElementById('r1'), name: 'navigation' },
  { el: document.getElementById('r2'), name: 'main' },
  { el: document.getElementById('r3'), name: 'contentinfo' },
];
const rotor = document.getElementById('rotor');
let i = 0;
function tick() {
  rows.forEach(function (r) { r.el.classList.remove('hit'); });
  const cur = rows[i % rows.length];
  cur.el.classList.add('hit');
  rotor.textContent = cur.name;
  i++;
}
tick();
setInterval(tick, 1000);

Screen readers have a shortcut to pull up a landmarks list — VoiceOver's rotor, NVDA's landmarks list, and so on. A page built entirely out of `<div>`s leaves that list empty, forcing a user to read from the very top just to find where the content starts. `<header>` (banner), `<nav>` (navigation), `<main>`, `<aside>` (complementary), and `<footer>` (contentinfo) each carry an implicit ARIA role, so using them populates that list automatically.

`<main>` should appear once per page, and if there's more than one `<nav>`, `aria-label` should tell them apart ('Primary' vs 'Footer'). Explicit ARIA roles like `role="main"` achieve the same thing, but native semantic tags are the first choice whenever they're available.

The demo shows the same layout two ways: an all-`<div>` page (empty landmarks list) and one built with semantic tags, where the list sweeps through banner → navigation → main → contentinfo in order.

When to use

Start every new page's layout skeleton with semantic tags — it's accessibility you get for free, independent of styling. If you have two or more nav elements, always give each an aria-label.