28 CSS Hamburger Menus27 / 28

Pure CSSMIT licensed

Brutalist Design Bordered CSS Hamburger Menu

Neo-brutalism with its rules intact: 3px black borders on everything, hard offset shadows that don't blur (box-shadow: 6px 6px 0), one shrieking yellow, Space-Mono-style uppercase type — and motion that CUTS instead of eases, because in this dialect a transition curve is a lie. The burger is a bordered plate that slams down onto its shadow when pressed; the menu is a stack of full-bleed rows that invert to black on hover, numbered like a manifest. Checkbox hack, naturally — raw HTML for a raw style.

Published Updated

Live Demo
Try it

The code

<section class="chm-27" aria-label="Brutalist bordered menu demo">
  <div class="chm-27__stage">
    <input type="checkbox" id="chm27-t" class="chm-27__state">
    <header class="chm-27__bar">
      <span class="chm-27__brand">RAW—GOODS<i class="chm-27__reg" aria-hidden="true">®</i></span>
      <label for="chm27-t" class="chm-27__plate">
        <span class="chm-27__ico" aria-hidden="true"><i></i><i></i><i></i></span>
        <span class="chm-27__lbl chm-27__lbl--m" aria-hidden="true">MENU</span>
        <span class="chm-27__lbl chm-27__lbl--c" aria-hidden="true">CLOSE</span>
      </label>
    </header>
    <nav class="chm-27__menu" aria-label="Site">
      <div class="chm-27__row"><a href="#shop"><b>01</b>SHOP ALL<span aria-hidden="true">→</span></a></div>
      <div class="chm-27__row"><a href="#drops"><b>02</b>DROPS<span aria-hidden="true">→</span></a></div>
      <div class="chm-27__row"><a href="#manifesto"><b>03</b>MANIFESTO<span aria-hidden="true">→</span></a></div>
      <div class="chm-27__row"><a href="#faq"><b>04</b>FAQ<span aria-hidden="true">→</span></a></div>
    </nav>
    <div class="chm-27__page" aria-hidden="true">
      <div class="chm-27__badge">EST. 2026<br>NO COOKIES<br>NO TRACKING</div>
      <div class="chm-27__box"></div>
    </div>
    <div class="chm-27__ticker" aria-hidden="true"><div class="chm-27__tape"><span>FREE SHIPPING OVER $80 ★ PRESS THE PLATE ★ EVERYTHING HAS A BORDER ★&nbsp;</span><span>FREE SHIPPING OVER $80 ★ PRESS THE PLATE ★ EVERYTHING HAS A BORDER ★&nbsp;</span></div></div>
  </div>
</section>
.chm-27,
.chm-27 *,
.chm-27 *::before,
.chm-27 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.chm-27 {
  background: var(--bg);
  width: 100%;
  min-height: 100vh;
  box-sizing: border-box;
  --paper: oklch(0.96 0.01 95);
  --ink: oklch(0.18 0.01 90);
  --acc: oklch(0.86 0.17 95);
  font-family: ui-monospace,'Cascadia Mono',Menlo,Consolas,monospace;
  color: var(--ink);
  display: grid;
  justify-content: center;
}

.chm-27__stage {
  position: relative;
  width: min(400px,88cqi,88vw);
  height: 560px;
  border: 3px solid var(--ink);
  background: radial-gradient(oklch(0.18 0.01 90/.14) 1.2px,transparent 1.3px) 0 0/18px 18px,var(--paper);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 8px 8px 0 var(--ink);
}

.chm-27__state {
  position: absolute;
  width: 1px;
  height: 1px;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

.chm-27__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px;
  border-bottom: 3px solid var(--ink);
  background: var(--paper);
  position: relative;
  z-index: 2;
}

.chm-27__brand {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: .04em;
}

.chm-27__reg {
  font-style: normal;
  font-size: 10px;
  vertical-align: super;
}

.chm-27__plate {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 46px;
  padding: 0 14px;
  border: 3px solid var(--ink);
  background: var(--acc);
  cursor: pointer;
  user-select: none;
  box-shadow: 6px 6px 0 var(--ink);
  transition: translate .06s linear,box-shadow .06s linear;
}

.chm-27__plate:hover {
  background: oklch(0.9 0.19 95);
}

.chm-27__state:focus-visible ~ .chm-27__bar .chm-27__plate {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__plate {
  translate: 6px 6px;
  box-shadow: 0 0 0 var(--ink);
}

.chm-27__ico {
  position: relative;
  width: 20px;
  height: 14px;
  display: block;
}

.chm-27__ico i {
  position: absolute;
  left: 0;
  width: 20px;
  height: 3px;
  background: var(--ink);
  transition: translate .06s linear,rotate .06s linear,opacity .06s linear;
}

.chm-27__ico i:nth-child(1) {
  top: 0;
}

.chm-27__ico i:nth-child(2) {
  top: 5.5px;
}

.chm-27__ico i:nth-child(3) {
  top: 11px;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__ico i:nth-child(1) {
  translate: 0 5.5px;
  rotate: 45deg;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__ico i:nth-child(2) {
  opacity: 0;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__ico i:nth-child(3) {
  translate: 0 -5.5px;
  rotate: -45deg;
}

.chm-27__lbl {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
}

.chm-27__lbl--c {
  display: none;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__lbl--m {
  display: none;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__lbl--c {
  display: block;
}

.chm-27__menu {
  position: absolute;
  inset: 79px 0 40px;
  z-index: 1;
  background: var(--paper);
  border-bottom: 3px solid var(--ink);
  display: none;
  flex-direction: column;
}

.chm-27__state:checked ~ .chm-27__menu {
  display: flex;
}

.chm-27__row {
  border-bottom: 3px solid var(--ink);
}

.chm-27__row a {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 64px;
  padding: 0 18px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .06em;
  color: var(--ink);
  text-decoration: none;
  transition: none;
}

.chm-27__row b {
  font-size: 11px;
  border: 2px solid var(--ink);
  padding: 2px 6px;
}

.chm-27__row span {
  margin-left: auto;
  font-size: 18px;
}

.chm-27__row a:hover,
.chm-27__row a:focus-visible {
  background: var(--ink);
  color: var(--paper);
}

.chm-27__row a:hover b,
.chm-27__row a:focus-visible b {
  border-color: var(--paper);
}

.chm-27__row a:focus-visible {
  outline: 3px solid var(--acc);
  outline-offset: -6px;
}

.chm-27__page {
  flex: 1;
  padding: 22px;
  display: grid;
  gap: 18px;
  align-content: start;
}

.chm-27__badge {
  width: max-content;
  border: 3px solid var(--ink);
  background: var(--acc);
  padding: 12px 16px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.7;
  letter-spacing: .06em;
  rotate: -1.5deg;
  box-shadow: 6px 6px 0 var(--ink);
}

.chm-27__box {
  height: 150px;
  border: 3px solid var(--ink);
  background: repeating-linear-gradient(-45deg,var(--paper) 0 12px,oklch(0.18 0.01 90/.12) 12px 24px);
}

.chm-27__ticker {
  margin-top: auto;
  border-top: 3px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  overflow: hidden;
  padding: 9px 0;
}

.chm-27__tape {
  display: flex;
  width: max-content;
  animation: chm27-tape 14s linear infinite;
}

.chm-27__tape span {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .14em;
  white-space: nowrap;
}

@keyframes chm27-tape {
  to {
    translate: -50% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .chm-27__tape {
    animation: none;
  }

  .chm-27 * {
    transition: none !important;
  }
}
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Hamburger Menu from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Brutalist Design Bordered CSS Hamburger Menu
Source: https://codefronts.com/navigation/css-hamburger-menus/brutalist-css-bordered-hamburger-menu/

Neo-brutalism with its rules intact: 3px black borders on everything, hard offset shadows that don't blur (box-shadow: 6px 6px 0), one shrieking yellow, Space-Mono-style uppercase type — and motion that CUTS instead of eases, because in this dialect a transition curve is a lie. The burger is a bordered plate that slams down onto its shadow when pressed; the menu is a stack of full-bleed rows that invert to black on hover, numbered like a manifest. Checkbox hack, naturally — raw HTML for a raw style.
## HTML
```html
<section class="chm-27" aria-label="Brutalist bordered menu demo">
  <div class="chm-27__stage">
    <input type="checkbox" id="chm27-t" class="chm-27__state">
    <header class="chm-27__bar">
      <span class="chm-27__brand">RAW—GOODS<i class="chm-27__reg" aria-hidden="true">®</i></span>
      <label for="chm27-t" class="chm-27__plate">
        <span class="chm-27__ico" aria-hidden="true"><i></i><i></i><i></i></span>
        <span class="chm-27__lbl chm-27__lbl--m" aria-hidden="true">MENU</span>
        <span class="chm-27__lbl chm-27__lbl--c" aria-hidden="true">CLOSE</span>
      </label>
    </header>
    <nav class="chm-27__menu" aria-label="Site">
      <div class="chm-27__row"><a href="#shop"><b>01</b>SHOP ALL<span aria-hidden="true">→</span></a></div>
      <div class="chm-27__row"><a href="#drops"><b>02</b>DROPS<span aria-hidden="true">→</span></a></div>
      <div class="chm-27__row"><a href="#manifesto"><b>03</b>MANIFESTO<span aria-hidden="true">→</span></a></div>
      <div class="chm-27__row"><a href="#faq"><b>04</b>FAQ<span aria-hidden="true">→</span></a></div>
    </nav>
    <div class="chm-27__page" aria-hidden="true">
      <div class="chm-27__badge">EST. 2026<br>NO COOKIES<br>NO TRACKING</div>
      <div class="chm-27__box"></div>
    </div>
    <div class="chm-27__ticker" aria-hidden="true"><div class="chm-27__tape"><span>FREE SHIPPING OVER $80 ★ PRESS THE PLATE ★ EVERYTHING HAS A BORDER ★&nbsp;</span><span>FREE SHIPPING OVER $80 ★ PRESS THE PLATE ★ EVERYTHING HAS A BORDER ★&nbsp;</span></div></div>
  </div>
</section>
```
## CSS
```css
.chm-27,
.chm-27 *,
.chm-27 *::before,
.chm-27 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.chm-27 {
  background: var(--bg);
  width: 100%;
  min-height: 100vh;
  box-sizing: border-box;
  --paper: oklch(0.96 0.01 95);
  --ink: oklch(0.18 0.01 90);
  --acc: oklch(0.86 0.17 95);
  font-family: ui-monospace,'Cascadia Mono',Menlo,Consolas,monospace;
  color: var(--ink);
  display: grid;
  justify-content: center;
}

.chm-27__stage {
  position: relative;
  width: min(400px,88cqi,88vw);
  height: 560px;
  border: 3px solid var(--ink);
  background: radial-gradient(oklch(0.18 0.01 90/.14) 1.2px,transparent 1.3px) 0 0/18px 18px,var(--paper);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 8px 8px 0 var(--ink);
}

.chm-27__state {
  position: absolute;
  width: 1px;
  height: 1px;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

.chm-27__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px;
  border-bottom: 3px solid var(--ink);
  background: var(--paper);
  position: relative;
  z-index: 2;
}

.chm-27__brand {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: .04em;
}

.chm-27__reg {
  font-style: normal;
  font-size: 10px;
  vertical-align: super;
}

.chm-27__plate {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 46px;
  padding: 0 14px;
  border: 3px solid var(--ink);
  background: var(--acc);
  cursor: pointer;
  user-select: none;
  box-shadow: 6px 6px 0 var(--ink);
  transition: translate .06s linear,box-shadow .06s linear;
}

.chm-27__plate:hover {
  background: oklch(0.9 0.19 95);
}

.chm-27__state:focus-visible ~ .chm-27__bar .chm-27__plate {
  outline: 3px solid var(--ink);
  outline-offset: 3px;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__plate {
  translate: 6px 6px;
  box-shadow: 0 0 0 var(--ink);
}

.chm-27__ico {
  position: relative;
  width: 20px;
  height: 14px;
  display: block;
}

.chm-27__ico i {
  position: absolute;
  left: 0;
  width: 20px;
  height: 3px;
  background: var(--ink);
  transition: translate .06s linear,rotate .06s linear,opacity .06s linear;
}

.chm-27__ico i:nth-child(1) {
  top: 0;
}

.chm-27__ico i:nth-child(2) {
  top: 5.5px;
}

.chm-27__ico i:nth-child(3) {
  top: 11px;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__ico i:nth-child(1) {
  translate: 0 5.5px;
  rotate: 45deg;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__ico i:nth-child(2) {
  opacity: 0;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__ico i:nth-child(3) {
  translate: 0 -5.5px;
  rotate: -45deg;
}

.chm-27__lbl {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .08em;
}

.chm-27__lbl--c {
  display: none;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__lbl--m {
  display: none;
}

.chm-27__state:checked ~ .chm-27__bar .chm-27__lbl--c {
  display: block;
}

.chm-27__menu {
  position: absolute;
  inset: 79px 0 40px;
  z-index: 1;
  background: var(--paper);
  border-bottom: 3px solid var(--ink);
  display: none;
  flex-direction: column;
}

.chm-27__state:checked ~ .chm-27__menu {
  display: flex;
}

.chm-27__row {
  border-bottom: 3px solid var(--ink);
}

.chm-27__row a {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 64px;
  padding: 0 18px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .06em;
  color: var(--ink);
  text-decoration: none;
  transition: none;
}

.chm-27__row b {
  font-size: 11px;
  border: 2px solid var(--ink);
  padding: 2px 6px;
}

.chm-27__row span {
  margin-left: auto;
  font-size: 18px;
}

.chm-27__row a:hover,
.chm-27__row a:focus-visible {
  background: var(--ink);
  color: var(--paper);
}

.chm-27__row a:hover b,
.chm-27__row a:focus-visible b {
  border-color: var(--paper);
}

.chm-27__row a:focus-visible {
  outline: 3px solid var(--acc);
  outline-offset: -6px;
}

.chm-27__page {
  flex: 1;
  padding: 22px;
  display: grid;
  gap: 18px;
  align-content: start;
}

.chm-27__badge {
  width: max-content;
  border: 3px solid var(--ink);
  background: var(--acc);
  padding: 12px 16px;
  font-size: 12px;
  font-weight: 700;
  line-height: 1.7;
  letter-spacing: .06em;
  rotate: -1.5deg;
  box-shadow: 6px 6px 0 var(--ink);
}

.chm-27__box {
  height: 150px;
  border: 3px solid var(--ink);
  background: repeating-linear-gradient(-45deg,var(--paper) 0 12px,oklch(0.18 0.01 90/.12) 12px 24px);
}

.chm-27__ticker {
  margin-top: auto;
  border-top: 3px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  overflow: hidden;
  padding: 9px 0;
}

.chm-27__tape {
  display: flex;
  width: max-content;
  animation: chm27-tape 14s linear infinite;
}

.chm-27__tape span {
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .14em;
  white-space: nowrap;
}

@keyframes chm27-tape {
  to {
    translate: -50% 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .chm-27__tape {
    animation: none;
  }

  .chm-27 * {
    transition: none !important;
  }
}
```

How this works

Brutalist depth is the shadow that admits it's fake — zero blur, pure offset, and interaction means physically closing the gap:

.plate{ border:3px solid var(--ink);
  box-shadow: 6px 6px 0 var(--ink);
  transition: translate .06s linear, box-shadow .06s linear; }
.plate:active,
#chm27-t:checked ~ header .plate{
  translate: 6px 6px;                /* move ONTO the shadow */
  box-shadow: 0 0 0 var(--ink); }

The element travels exactly its shadow's offset, landing flat on the surface — a mechanical, satisfying press that needs no easing because the duration (60ms) is a single beat. This is the one collection demo where near-instant state changes are correct: the aesthetic IS the timing function. (Note prefers-reduced-motion still applies — 60ms cuts are already calm, but the marquee below stops.)

The menu rows use the style's second signature, inversion instead of tinting:

.row a:hover, .row a:focus-visible{
  background:var(--ink); color:var(--paper); }

No 8%-alpha hover washes — full flip, plus the row's index number and arrow glyph swap color in the same cut. The ticker strip at the bottom is a CSS marquee (two copies of the text in a flex track, translate keyframe from 0 to -50%) — kitsch on any other site, native vocabulary here. Everything sits on a visible dot-grid background (radial-gradient, 18px cell) because brutalism shows its graph paper. The checkbox engine is demo 05's verbatim, same focusable-input discipline — the style is loud, the accessibility is not optional.

Make it yours

  • The palette is paper/ink/one-accent — swap --acc yellow for hot pink oklch(0.72 0.2 350) or acid green oklch(0.85 0.23 135); never add a fourth color, the tension IS the restraint.
  • Border weight and shadow offset are the same token pair everywhere (3px / 6px 6px). Scale to 4px/8px for poster-weight; keep offset = 2× border or the physics reads wrong.
  • Rotate a couple of elements ±1.5deg (the badge here) for the hand-pasted zine feel — more than two rotated elements and it tips into parody.
  • The marquee text is one string repeated twice in markup — edit both copies (they must match or the loop jumps).

Gotchas — read before shipping

  • Hard shadows must be box-shadow with 0 blur, NOT border tricks or filter:drop-shadow (which antialiases the edge soft) — crisp is the brand.
  • The press translate means the element MOVES 6px — don't attach tooltips or focus rings that follow it mid-press, and keep 6px of breathing room in the layout so neighbors aren't overlapped.
  • Uppercase mono at small sizes tanks readability — the style's real floor is ~13px; body copy stays sentence-case even on brutalist sites (this demo's rows are 15px).
  • A yellow (oklch 0.86) surface under black text is 13:1 — great; but black on yellow FOCUS rings vanish against black borders, which is why the ring here is offset 3px OUTSIDE the shadow zone.

Browser support

ChromeSafariFirefoxEdge
111+16.4+113+111+

Borders, hard shadows, checkbox state and keyframe marquees are 2012-era CSS — the floor is the oklch() palette alone. Ironically the most avant-garde-looking demo is the most backwards-compatible.

Search CodeFronts

Loading…