26 CSS Dividers10 / 26

Pure CSSMIT licensed

Neo-Brutalist Heavy Border Divider CSS

Brutalism's whole grammar in one divider: a 6px black slab, a hard unblurred offset shadow, zero border-radius, and a marching hazard-stripe rule built from a single repeating-linear-gradient. The trick that makes stripes scroll seamlessly is animating background-position by exactly one tile — get that number wrong and the pattern visibly stutters every loop.

Published Updated

Live Demo
Try it

The code

<section class="div-10" aria-label="Neo-brutalist heavy border divider demo">
  <div class="div-10__stage">
    <div class="div-10__card">
      <p class="div-10__eyebrow">SECTION 01 / SPECS</p>
      <h2 class="div-10__title">HEAVY<br>BORDERS</h2>
    </div>
    <hr class="div-10__slab">
    <div class="div-10__hazard" role="separator" aria-label="Hazard divider">
      <span class="div-10__stamp">DIVIDER</span>
    </div>
    <hr class="div-10__slab div-10__slab--thin">
    <p class="div-10__note">Unblurred offset shadows. Zero radius. √2 stripe travel.</p>
    <p class="div-10__chip">repeating-linear-gradient(45deg) · background-position × 1.414</p>
  </div>
</section>
.div-10 {
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  background: var(--div-10-bg);
  --div-10-bg: oklch(0.93 0.13 105);
  --div-10-ink: oklch(0.18 0.012 265);
  --div-10-acc: oklch(0.99 0 0);
  --div-10-acc2: oklch(0.68 0.21 355);
  --div-10-tile: 30px;
  font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
  color: var(--div-10-ink);
}

.div-10 *,
.div-10 *::before,
.div-10 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.div-10__stage {
  min-height: 100svh;
  display: grid;
  place-content: center;
  justify-items: stretch;
  gap: clamp(18px,3.4vw,30px);
  padding: clamp(28px,6vw,72px) clamp(20px,5vw,56px);
  width: min(94vw,660px);
  margin-inline: auto;
}

.div-10__card {
  background: var(--div-10-acc);
  border: 4px solid var(--div-10-ink);
  box-shadow: 9px 9px 0 0 var(--div-10-ink);
  padding: clamp(22px,4vw,34px);
}

.div-10__eyebrow {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11.5px;
  letter-spacing: .2em;
  color: var(--div-10-acc2);
  font-weight: 700;
  margin-bottom: 10px;
}

.div-10__title {
  font-size: clamp(38px,9vw,86px);
  line-height: .9;
  letter-spacing: -.045em;
  font-weight: 900;
  text-transform: uppercase;
}

.div-10__slab {
  border: 0;
  height: 9px;
  background: var(--div-10-ink);
  box-shadow: 7px 7px 0 0 var(--div-10-acc2);
}

.div-10__slab--thin {
  height: 4px;
  box-shadow: 5px 5px 0 0 var(--div-10-ink);
}

.div-10__hazard {
  position: relative;
  height: clamp(46px,7vw,62px);
  border: 4px solid var(--div-10-ink);
  background: repeating-linear-gradient(45deg,var(--div-10-ink) 0 calc(var(--div-10-tile)/2),var(--div-10-acc) calc(var(--div-10-tile)/2) var(--div-10-tile));
  animation: div-10-march 1.15s linear infinite;
  display: grid;
  place-items: center;
  box-shadow: 9px 9px 0 0 var(--div-10-ink);
}

@keyframes div-10-march {
  to {
    background-position: calc(var(--div-10-tile) * 1.414) 0;
  }
}

.div-10__stamp {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: clamp(13px,2.2vw,17px);
  font-weight: 800;
  letter-spacing: .24em;
  background: var(--div-10-bg);
  border: 3px solid var(--div-10-ink);
  padding: 7px 16px;
  color: var(--div-10-ink);
}

.div-10__note {
  font-size: clamp(14px,2vw,17px);
  font-weight: 700;
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: .01em;
}

.div-10__chip {
  justify-self: start;
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11px;
  padding: 8px 14px;
  border: 2.5px solid var(--div-10-ink);
  background: var(--div-10-acc);
  max-width: 100%;
  overflow-wrap: anywhere;
}

@media (prefers-reduced-motion: reduce) {
  .div-10__hazard {
    animation: none;
  }
}
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 Divider 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: Neo-Brutalist Heavy Border Divider CSS
Source: https://codefronts.com/snippets/css-dividers/brutalist-dividers/

Brutalism's whole grammar in one divider: a 6px black slab, a hard unblurred offset shadow, zero border-radius, and a marching hazard-stripe rule built from a single repeating-linear-gradient. The trick that makes stripes scroll seamlessly is animating background-position by exactly one tile — get that number wrong and the pattern visibly stutters every loop.
## HTML
```html
<section class="div-10" aria-label="Neo-brutalist heavy border divider demo">
  <div class="div-10__stage">
    <div class="div-10__card">
      <p class="div-10__eyebrow">SECTION 01 / SPECS</p>
      <h2 class="div-10__title">HEAVY<br>BORDERS</h2>
    </div>
    <hr class="div-10__slab">
    <div class="div-10__hazard" role="separator" aria-label="Hazard divider">
      <span class="div-10__stamp">DIVIDER</span>
    </div>
    <hr class="div-10__slab div-10__slab--thin">
    <p class="div-10__note">Unblurred offset shadows. Zero radius. √2 stripe travel.</p>
    <p class="div-10__chip">repeating-linear-gradient(45deg) · background-position × 1.414</p>
  </div>
</section>
```
## CSS
```css
.div-10 {
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  background: var(--div-10-bg);
  --div-10-bg: oklch(0.93 0.13 105);
  --div-10-ink: oklch(0.18 0.012 265);
  --div-10-acc: oklch(0.99 0 0);
  --div-10-acc2: oklch(0.68 0.21 355);
  --div-10-tile: 30px;
  font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
  color: var(--div-10-ink);
}

.div-10 *,
.div-10 *::before,
.div-10 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.div-10__stage {
  min-height: 100svh;
  display: grid;
  place-content: center;
  justify-items: stretch;
  gap: clamp(18px,3.4vw,30px);
  padding: clamp(28px,6vw,72px) clamp(20px,5vw,56px);
  width: min(94vw,660px);
  margin-inline: auto;
}

.div-10__card {
  background: var(--div-10-acc);
  border: 4px solid var(--div-10-ink);
  box-shadow: 9px 9px 0 0 var(--div-10-ink);
  padding: clamp(22px,4vw,34px);
}

.div-10__eyebrow {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11.5px;
  letter-spacing: .2em;
  color: var(--div-10-acc2);
  font-weight: 700;
  margin-bottom: 10px;
}

.div-10__title {
  font-size: clamp(38px,9vw,86px);
  line-height: .9;
  letter-spacing: -.045em;
  font-weight: 900;
  text-transform: uppercase;
}

.div-10__slab {
  border: 0;
  height: 9px;
  background: var(--div-10-ink);
  box-shadow: 7px 7px 0 0 var(--div-10-acc2);
}

.div-10__slab--thin {
  height: 4px;
  box-shadow: 5px 5px 0 0 var(--div-10-ink);
}

.div-10__hazard {
  position: relative;
  height: clamp(46px,7vw,62px);
  border: 4px solid var(--div-10-ink);
  background: repeating-linear-gradient(45deg,var(--div-10-ink) 0 calc(var(--div-10-tile)/2),var(--div-10-acc) calc(var(--div-10-tile)/2) var(--div-10-tile));
  animation: div-10-march 1.15s linear infinite;
  display: grid;
  place-items: center;
  box-shadow: 9px 9px 0 0 var(--div-10-ink);
}

@keyframes div-10-march {
  to {
    background-position: calc(var(--div-10-tile) * 1.414) 0;
  }
}

.div-10__stamp {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: clamp(13px,2.2vw,17px);
  font-weight: 800;
  letter-spacing: .24em;
  background: var(--div-10-bg);
  border: 3px solid var(--div-10-ink);
  padding: 7px 16px;
  color: var(--div-10-ink);
}

.div-10__note {
  font-size: clamp(14px,2vw,17px);
  font-weight: 700;
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: .01em;
}

.div-10__chip {
  justify-self: start;
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11px;
  padding: 8px 14px;
  border: 2.5px solid var(--div-10-ink);
  background: var(--div-10-acc);
  max-width: 100%;
  overflow-wrap: anywhere;
}

@media (prefers-reduced-motion: reduce) {
  .div-10__hazard {
    animation: none;
  }
}
```

How this works

Brutalist dividers are loud on purpose, and the loudness is three properties:

.slab{ height:8px; background:var(--ink);
       box-shadow:6px 6px 0 0 var(--acc); }   /* no blur, no spread */

An unblurred, un-spread box-shadow is the entire aesthetic. Real shadows have blur; brutalist ones don't, because they aren't pretending to be light — they're pretending to be misregistered print.

The hazard rule is a tiled diagonal gradient set in motion:

.hazard{ --tile:28px;
  background:repeating-linear-gradient(45deg,
    var(--ink) 0 calc(var(--tile)/2),
    var(--acc) calc(var(--tile)/2) var(--tile));
  animation:march 1.1s linear infinite; }
@keyframes march{ to{ background-position:calc(var(--tile)*1.414) 0 } }

That 1.414 is √2, and it is the whole reason the loop is seamless: a 45° repeating gradient has a horizontal period of tile ÷ sin45°, not tile. Animate by the raw tile size and the stripes jump a fraction every cycle. Reduce the angle to 0° and the multiplier becomes 1.

The stamped label sits on the rule with a solid background and a 3px border, punching a hole in the stripes exactly like the ornamental divider punches a hole in a hairline — the same technique, opposite personality.

Make it yours

  • Shadow direction: -6px 6px, 6px -6px and so on. Keeping every shadow on a page in the same direction is what makes brutalism look designed rather than broken.
  • Colour: the style survives any hue as long as the contrast is brutal. Try acid green oklch(0.85 0.22 130) or hot pink oklch(0.7 0.24 350) against pure black.
  • Stripe angle: 45° is hazard tape, 90° is a barcode, 0° is a caution bar. Remember to adjust the animation distance (√2 at 45°, 1 at 0°/90°).
  • Static version: drop the animation and add border:3px solid var(--ink) around the stripe block for a printed-warning feel.

Gotchas — read before shipping

  • Animating background-position runs on the main thread and repaints the element every frame. Keep the striped area small, or move the stripes to a pseudo-element with a transform animation instead.
  • Hard shadows are invisible if the divider sits on a same-coloured surface — brutalism needs the offset colour to differ from BOTH the slab and the page.
  • Pure #000 on pure #fff at large areas causes halation for some readers; oklch(0.18 0.01 260) reads as black and is measurably easier on the eye.
  • A striped, animated band can trigger discomfort — always calm it under prefers-reduced-motion, and never run stripes faster than ~1 tile per second.

Browser support

ChromeSafariFirefoxEdge
111+16.4+113+111+

repeating-linear-gradient, box-shadow and background-position animation work back to IE10. Only the oklch() tokens set the modern floor.

Search CodeFronts

Loading…