26 CSS Link Effects24 / 26

Pure CSSMIT licensed

CSS Brutalist Block Shadow Hover Effect

Neo-brutalism's whole physics engine is one equation: translate the box toward or away from its hard shadow. Hover lifts the card off the page (shadow grows), :active slams it flat (shadow zero) — a click you can feel. Three builds: the standard lift, the inverted press-in, and a rotated double-shadow stack that swaps colors mid-hover.

Published Updated

Live Demo
Try it

The code

<section class="cle-24" aria-label="Brutalist shadow hover demo">
  <div class="cle-24__stage">
    <div class="cle-24__var"><a href="#a" class="cle-24__lift">READ THE ZINE</a><small class="cle-24__cap">A · lift, then slam (:active)</small></div>
    <div class="cle-24__var"><a href="#b" class="cle-24__press">RSVP → ISSUE 07</a><small class="cle-24__cap">B · press-in</small></div>
    <div class="cle-24__var"><a href="#c" class="cle-24__stack">SHOP PRINTS</a><small class="cle-24__cap">C · double stack + tilt</small></div>
  </div>
</section>
.cle-24,
.cle-24 *,
.cle-24 *::before,
.cle-24 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cle-24 {
  width: 100%;
  min-height: 100vh;
  --blk: oklch(0.22 0.01 90);
  --yel: oklch(0.86 0.16 95);
  --pnk: oklch(0.78 0.15 5);
  --blu: oklch(0.75 0.11 230);
  font-family: ui-monospace,'Cascadia Code',Menlo,Consolas,monospace;
}

.cle-24__stage {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 48px 56px;
  border: 1px solid oklch(0.88 0.03 90);
  background: oklch(0.955 0.02 90);
  background-image: radial-gradient(oklch(0.85 0.03 90) 1px,transparent 1px);
  background-size: 22px 22px;
  padding: 44px 36px;
}

.cle-24__var {
  display: grid;
  gap: 16px;
  justify-items: center;
}

.cle-24__cap {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: oklch(0.48 0.03 90);
  font-family: 'Segoe UI',system-ui,sans-serif;
}

.cle-24 a {
  display: inline-block;
  padding: 16px 26px;
  border: 3px solid var(--blk);
  color: var(--blk);
  text-decoration: none;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .04em;
}

.cle-24 a:focus-visible {
  outline: 3px dashed var(--blk);
  outline-offset: 4px;
}

.cle-24__lift {
  background: var(--yel);
  box-shadow: 5px 5px 0 var(--blk);
  transition: translate .15s ease-out,box-shadow .15s ease-out;
}

.cle-24__lift:hover,
.cle-24__lift:focus-visible {
  translate: -3px -3px;
  box-shadow: 8px 8px 0 var(--blk);
}

.cle-24__lift:active {
  translate: 2px 2px;
  box-shadow: 0 0 0 var(--blk);
}

.cle-24__press {
  background: var(--blu);
  box-shadow: 6px 6px 0 var(--blk);
  transition: translate .15s ease-out,box-shadow .15s ease-out;
}

.cle-24__press:hover,
.cle-24__press:focus-visible {
  translate: 4px 4px;
  box-shadow: 2px 2px 0 var(--blk);
}

.cle-24__press:active {
  translate: 6px 6px;
  box-shadow: 0 0 0 var(--blk);
}

.cle-24__stack {
  background: oklch(0.97 0.01 90);
  box-shadow: 5px 5px 0 var(--pnk),10px 10px 0 var(--blk);
  transition: translate .15s ease-out,box-shadow .15s ease-out,rotate .15s ease-out,background-color .15s;
}

.cle-24__stack:hover,
.cle-24__stack:focus-visible {
  translate: -3px -3px;
  rotate: -1.2deg;
  background: var(--pnk);
  box-shadow: 7px 7px 0 var(--yel),14px 14px 0 var(--blk);
}

.cle-24__stack:active {
  translate: 4px 4px;
  rotate: 0deg;
  box-shadow: 0 0 0 var(--yel),0 0 0 var(--blk);
}

@media (prefers-reduced-motion: reduce) {
  .cle-24 * {
    transition-duration: .01s !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 Link Effect 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: CSS Brutalist Block Shadow Hover Effect
Source: https://codefronts.com/motion/css-link-effects/brutalist-block/

Neo-brutalism's whole physics engine is one equation: translate the box toward or away from its hard shadow. Hover lifts the card off the page (shadow grows), :active slams it flat (shadow zero) — a click you can feel. Three builds: the standard lift, the inverted press-in, and a rotated double-shadow stack that swaps colors mid-hover.
## HTML
```html
<section class="cle-24" aria-label="Brutalist shadow hover demo">
  <div class="cle-24__stage">
    <div class="cle-24__var"><a href="#a" class="cle-24__lift">READ THE ZINE</a><small class="cle-24__cap">A · lift, then slam (:active)</small></div>
    <div class="cle-24__var"><a href="#b" class="cle-24__press">RSVP → ISSUE 07</a><small class="cle-24__cap">B · press-in</small></div>
    <div class="cle-24__var"><a href="#c" class="cle-24__stack">SHOP PRINTS</a><small class="cle-24__cap">C · double stack + tilt</small></div>
  </div>
</section>
```
## CSS
```css
.cle-24,
.cle-24 *,
.cle-24 *::before,
.cle-24 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cle-24 {
  width: 100%;
  min-height: 100vh;
  --blk: oklch(0.22 0.01 90);
  --yel: oklch(0.86 0.16 95);
  --pnk: oklch(0.78 0.15 5);
  --blu: oklch(0.75 0.11 230);
  font-family: ui-monospace,'Cascadia Code',Menlo,Consolas,monospace;
}

.cle-24__stage {
  width: 100%;
  height: 100vh;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 48px 56px;
  border: 1px solid oklch(0.88 0.03 90);
  background: oklch(0.955 0.02 90);
  background-image: radial-gradient(oklch(0.85 0.03 90) 1px,transparent 1px);
  background-size: 22px 22px;
  padding: 44px 36px;
}

.cle-24__var {
  display: grid;
  gap: 16px;
  justify-items: center;
}

.cle-24__cap {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: oklch(0.48 0.03 90);
  font-family: 'Segoe UI',system-ui,sans-serif;
}

.cle-24 a {
  display: inline-block;
  padding: 16px 26px;
  border: 3px solid var(--blk);
  color: var(--blk);
  text-decoration: none;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .04em;
}

.cle-24 a:focus-visible {
  outline: 3px dashed var(--blk);
  outline-offset: 4px;
}

.cle-24__lift {
  background: var(--yel);
  box-shadow: 5px 5px 0 var(--blk);
  transition: translate .15s ease-out,box-shadow .15s ease-out;
}

.cle-24__lift:hover,
.cle-24__lift:focus-visible {
  translate: -3px -3px;
  box-shadow: 8px 8px 0 var(--blk);
}

.cle-24__lift:active {
  translate: 2px 2px;
  box-shadow: 0 0 0 var(--blk);
}

.cle-24__press {
  background: var(--blu);
  box-shadow: 6px 6px 0 var(--blk);
  transition: translate .15s ease-out,box-shadow .15s ease-out;
}

.cle-24__press:hover,
.cle-24__press:focus-visible {
  translate: 4px 4px;
  box-shadow: 2px 2px 0 var(--blk);
}

.cle-24__press:active {
  translate: 6px 6px;
  box-shadow: 0 0 0 var(--blk);
}

.cle-24__stack {
  background: oklch(0.97 0.01 90);
  box-shadow: 5px 5px 0 var(--pnk),10px 10px 0 var(--blk);
  transition: translate .15s ease-out,box-shadow .15s ease-out,rotate .15s ease-out,background-color .15s;
}

.cle-24__stack:hover,
.cle-24__stack:focus-visible {
  translate: -3px -3px;
  rotate: -1.2deg;
  background: var(--pnk);
  box-shadow: 7px 7px 0 var(--yel),14px 14px 0 var(--blk);
}

.cle-24__stack:active {
  translate: 4px 4px;
  rotate: 0deg;
  box-shadow: 0 0 0 var(--yel),0 0 0 var(--blk);
}

@media (prefers-reduced-motion: reduce) {
  .cle-24 * {
    transition-duration: .01s !important;
  }
}
```

How this works

A zero-blur box-shadow reads as a solid block glued to the page. Because the shadow doesn't move with transforms, translating the element relative to it creates depth:

.lift{ border:3px solid var(--blk); box-shadow: 5px 5px 0 var(--blk);
       transition: translate .15s ease-out, box-shadow .15s ease-out; }
.lift:hover { translate: -3px -3px; box-shadow: 8px 8px 0 var(--blk); }
.lift:active{ translate:  2px  2px; box-shadow: 0 0 0 var(--blk); }

Hover moves the box up-left while the shadow grows by the same delta — the box rises. :active reverses both to zero — the box lands flat with a thunk. Keeping translate and shadow deltas equal is what sells the physicality; mismatch them and the shadow looks painted on.

B inverts the contract (hover = press toward the page, shadow shrinking to 2px), useful for toggle-like links. C stacks two shadows — accent at 5px, black at 10px — and adds a −1.2° rotation on hover plus a background flip, the maximal zine energy. All transitions are a snappy .15s: brutalism doesn't ease, it clunks.

Make it yours

  • Depth: the shadow offset pair; keep translate delta = shadow delta for honest physics.
  • Palette: brutalism wants 2–3 flat, loud tokens — the demo uses yellow/pink/blue on cream with near-black ink.
  • C's tilt: the -1.2deg rotate; anything past ±3° starts fighting readability.
  • Round nothing: border-radius 0 is the aesthetic. If you must, 4px max and equal shadow offsets.

Gotchas — read before shipping

  • Always pair the hover lift with an :active press — brutalist buttons that don't physically depress feel broken mid-click.
  • Use translate, not margin/position nudges: margins reflow neighboring layout every frame.
  • The hard shadow is decorative; contrast lives in the border and text — the 3px near-black border is what keeps these AA-legible on cream.

Browser support

ChromeSafariFirefoxEdge
111+16.2+113+111+

box-shadow + individual translate/rotate properties (Chrome 104, Safari 14.1, Firefox 72). oklch sets the stated floor; this pattern otherwise runs on anything.

Search CodeFronts

Loading…