turnley.dev

PHP and MySQL code for faucet operators

Tools & Calculators

SEO-006

A responsive nav that folds without any JavaScript

A checkbox, a label and a sibling selector. Works with scripts disabled, ships nothing to parse, and cannot break on a slow connection.

A hamburger menu is usually a script that toggles a class. On a site whose whole argument is that it has no dependencies, that is an odd place to add one — and a menu that fails when a script fails is a site nobody can navigate.

A hidden checkbox holds the open state, its label is the button, and the general sibling selector styles the menu based on whether the box is checked. No script, no flash of unstyled content, and it works the moment the HTML arrives.

The parts people leave out are the accessibility ones: the checkbox must stay focusable rather than being set to display none, and the label needs a role and a name.

HTML
<nav class="nav">
  <input type="checkbox" id="nav-toggle" class="nav-toggle">
  <label for="nav-toggle" class="nav-button" role="button" aria-label="Menu">
    <span></span><span></span><span></span>
  </label>
  <ul class="nav-list">
    <li><a href="/">Library</a></li>
    <li><a href="/c/faucetpay">FaucetPay</a></li>
    <li><a href="/search.php">Search</a></li>
  </ul>
</nav>

<style>
/* Off-screen, not display:none — it has to stay focusable for the keyboard. */
.nav-toggle { position: absolute; opacity: 0; width: 1px; height: 1px; }
.nav-button { display: none; cursor: pointer; padding: 10px; }
.nav-button span { display: block; width: 22px; height: 2px; background: currentColor; margin: 4px 0; }
.nav-list { display: flex; gap: 18px; list-style: none; margin: 0; padding: 0; }

@media (max-width: 760px) {
  .nav-button { display: block; }
  .nav-list { display: none; flex-direction: column; gap: 0; }
  /* The whole mechanism: checked box, sibling list. */
  .nav-toggle:checked ~ .nav-list { display: flex; }
  .nav-list li { border-top: 1px solid rgba(255,255,255,.12); }
  .nav-list a { display: block; padding: 12px 4px; }
}

/* Visible focus ring on the button when tabbing. */
.nav-toggle:focus-visible ~ .nav-button { outline: 2px solid currentColor; outline-offset: 2px; }
</style>

Using it

Give the links generous padding on mobile. Forty-four pixels of height is the usual minimum for a comfortable tap target.

If the nav is a long list of categories, a horizontally scrolling strip often beats a fold — it keeps everything one tap away instead of two.

What bites people

display:none on the checkbox removes it from the tab order and the menu becomes unreachable by keyboard. Position it off-screen instead.

The general sibling combinator only reaches forward, so the checkbox has to appear before the list in the markup.

The menu stays open after navigation on a single-page setup. On a normal multi-page site the reload resets it, which is one more reason this approach is fine here.

Also in SEO and Frontend