28 / 34
All 34 in 34 CSS Floating Buttons
- 01Material Design 3 Floating Action Button (FAB)
- 02iOS-Style Compose Floating Button
- 03WhatsApp Floating Message Button CSS
- 04Intercom / Drift Chat Bubble Floating Button
- 05Accessible WAI-ARIA Floating Action Button (WCAG 2.2)
- 06Extended FAB with Icon and Label (Material Design 3)
- 07Speed Dial Radial Menu FAB with Backdrop
- 08Pure CSS FAB Speed Dial (No JavaScript)
- 09Material Gradient Floating Action Button CSS
- 10Vertical and Horizontal Speed Dial FAB Menu CSS
- 11Morphing FAB Button That Expands to Pill CSS
- 12Scroll-to-Top Floating Button with SVG Progress Ring
- 13Floating Chat Widget FAB with Notification Panel
- 14Fan and Arc Radial Spread FAB Menu CSS
- 15Apple Squircle Superellipse Floating Button CSS
- 16Social Share Floating Button Cluster CSS
- 17Glassmorphism Floating Action Button with Backdrop Blur
- 18Cyberpunk Neon Glow Floating Button CSS
- 19Floating Compose Button with Tooltip on Hover CSS
- 20Draggable Floating Action Button with Corner Snap CSS
- 21Notification Bell Floating Button with Badge Counter
- 22Floating Cart Button with Live Badge Counter CSS
- 23Magnetic Cursor Follower Floating Button CSS
- 24Dark Mode Theme Toggle Floating Button CSS
- 25Classic Gradient Circle Plus FAB CSS
- 26Pulse Ring Attention-Getter Floating Button CSS
- 27Pill-Shaped FAB with Icon and Text Label CSS
- 28Neo-Brutalist Hard Shadow Floating Button CSS
- 29Floating Button with Loading Spinner State CSS
- 30Draggable Floating Button with 6-Dot Grip Handle CSS
- 31Voice Recording Microphone Floating Button CSS
- 32Aurora Gradient Drift Premium Floating Button CSS
- 33Quick Emoji Reply Reaction Floating Button CSS
- 34Modern Squircle Rounded Square FAB CSS
Neo-Brutalist Hard Shadow Floating Button CSS
Neo-brutalism where the interaction, not just the look, is physical: a zero-blur offset shadow acting as a solid slab, and a press that translates the button exactly onto its own shadow so the slab collapses to nothing. Get that arithmetic right and the button feels like a real key being pushed flat against the page.
Nucleo: 44,000+ SVG icons in five families · All Icons Bundle $149
Nucleo · Affiliate link
The code
<section class="fb-28" aria-label="Neo brutalist hard shadow floating button demo">
<div class="fb-28__stage">
<p class="fb-28__eyebrow">zero blur · press lands on the slab</p>
<h2 class="fb-28__title">PUSH<br>IT<span>.</span></h2>
<p class="fb-28__sub">Translate equals shadow offset. Press it and the button lands exactly on its own shadow — the mass stays put, only the elevation goes.</p>
<div class="fb-28__row">
<button class="fb-28__fab" type="button" aria-label="Add">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 4v16M4 12h16" stroke="currentColor" stroke-width="3" stroke-linecap="square"/></svg>
</button>
<button class="fb-28__pill" type="button">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/></svg>
<span>Ship it</span>
</button>
<button class="fb-28__fab fb-28__fab--pop" type="button" aria-label="Favourite">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 4l2.5 5.6 6.1.6-4.6 4.1 1.3 6-5.3-3.2-5.3 3.2 1.3-6L3.4 10.2l6.1-.6z" fill="currentColor"/></svg>
</button>
<button class="fb-28__fab fb-28__fab--sticker" type="button" aria-label="Bookmark">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6 3h12v18l-6-4.6L6 21z" fill="currentColor"/></svg>
</button>
</div>
<p class="fb-28__chip">6px offset · 3px border · 100ms linear</p>
</div>
</section><section class="fb-28" aria-label="Neo brutalist hard shadow floating button demo">
<div class="fb-28__stage">
<p class="fb-28__eyebrow">zero blur · press lands on the slab</p>
<h2 class="fb-28__title">PUSH<br>IT<span>.</span></h2>
<p class="fb-28__sub">Translate equals shadow offset. Press it and the button lands exactly on its own shadow — the mass stays put, only the elevation goes.</p>
<div class="fb-28__row">
<button class="fb-28__fab" type="button" aria-label="Add">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 4v16M4 12h16" stroke="currentColor" stroke-width="3" stroke-linecap="square"/></svg>
</button>
<button class="fb-28__pill" type="button">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/></svg>
<span>Ship it</span>
</button>
<button class="fb-28__fab fb-28__fab--pop" type="button" aria-label="Favourite">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 4l2.5 5.6 6.1.6-4.6 4.1 1.3 6-5.3-3.2-5.3 3.2 1.3-6L3.4 10.2l6.1-.6z" fill="currentColor"/></svg>
</button>
<button class="fb-28__fab fb-28__fab--sticker" type="button" aria-label="Bookmark">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6 3h12v18l-6-4.6L6 21z" fill="currentColor"/></svg>
</button>
</div>
<p class="fb-28__chip">6px offset · 3px border · 100ms linear</p>
</div>
</section>.fb-28 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--fb-28-bg);
--fb-28-bg: oklch(0.93 0.13 100);
--fb-28-line: oklch(0.18 0.02 95);
--fb-28-fill: oklch(0.99 0.005 100);
--fb-28-pop: oklch(0.68 0.21 20);
--fb-28-cy: oklch(0.78 0.14 200);
font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
color: var(--fb-28-line);
display: grid;
place-items: center;
padding: clamp(20px,5vw,56px);
background-image: repeating-linear-gradient(45deg,oklch(0.18 0.02 95/.05) 0 2px,transparent 2px 12px);
}
.fb-28 *,
.fb-28 *::before,
.fb-28 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fb-28__stage {
width: min(100%,58ch);
display: grid;
gap: clamp(16px,3vw,26px);
justify-items: center;
text-align: center;
}
.fb-28__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
font-weight: 700;
letter-spacing: .18em;
text-transform: uppercase;
background: var(--fb-28-line);
color: var(--fb-28-bg);
padding: 6px 12px;
}
.fb-28__title {
font-size: clamp(44px,11vw,104px);
line-height: .86;
letter-spacing: -.05em;
font-weight: 900;
text-transform: uppercase;
-webkit-text-stroke: 2px var(--fb-28-line);
color: var(--fb-28-fill);
text-shadow: 7px 7px 0 var(--fb-28-line);
}
.fb-28__title span {
color: var(--fb-28-pop);
}
.fb-28__sub {
max-width: 46ch;
font-size: clamp(13.5px,1.7vw,16.5px);
line-height: 1.55;
font-weight: 560;
text-wrap: pretty;
}
.fb-28__row {
display: flex;
flex-wrap: wrap;
gap: clamp(18px,5vw,34px);
justify-content: center;
align-items: center;
padding: 12px 0 6px;
}
.fb-28__fab {
display: grid;
place-items: center;
inline-size: 68px;
block-size: 68px;
border: 3px solid var(--fb-28-line);
border-radius: 0;
cursor: pointer;
color: var(--fb-28-line);
background: var(--fb-28-fill);
box-shadow: 6px 6px 0 0 var(--fb-28-line);
transition: translate .1s linear,box-shadow .1s linear,background .1s linear;
}
.fb-28__fab svg {
width: 28px;
height: 28px;
}
.fb-28__fab:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line);
background: var(--fb-28-cy);
}
.fb-28__fab:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line);
}
.fb-28__fab:focus-visible {
outline: 3px dashed var(--fb-28-line);
outline-offset: 5px;
}
.fb-28__fab--pop {
background: var(--fb-28-pop);
color: var(--fb-28-fill);
}
.fb-28__fab--pop:hover {
background: oklch(0.75 0.2 22);
}
.fb-28__fab--sticker {
rotate: -4deg;
background: var(--fb-28-cy);
box-shadow: 6px 6px 0 0 var(--fb-28-line),12px 12px 0 0 var(--fb-28-pop);
}
.fb-28__fab--sticker:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line),15px 15px 0 0 var(--fb-28-pop);
background: oklch(0.85 0.14 195);
}
.fb-28__fab--sticker:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line),6px 6px 0 0 var(--fb-28-pop);
}
.fb-28__pill {
display: inline-flex;
align-items: center;
gap: 11px;
block-size: 68px;
padding-inline: 22px 26px;
border: 3px solid var(--fb-28-line);
cursor: pointer;
color: var(--fb-28-line);
background: var(--fb-28-fill);
font-family: inherit;
font-size: 19px;
font-weight: 800;
letter-spacing: -.02em;
text-transform: uppercase;
box-shadow: 6px 6px 0 0 var(--fb-28-line);
transition: translate .1s linear,box-shadow .1s linear,background .1s linear;
}
.fb-28__pill svg {
width: 26px;
height: 26px;
}
.fb-28__pill:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line);
background: var(--fb-28-pop);
color: var(--fb-28-fill);
}
.fb-28__pill:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line);
}
.fb-28__pill:focus-visible {
outline: 3px dashed var(--fb-28-line);
outline-offset: 5px;
}
.fb-28__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
font-weight: 600;
padding: 8px 14px;
border: 2px solid var(--fb-28-line);
background: var(--fb-28-fill);
}
@media (prefers-reduced-motion: reduce) {
.fb-28 * {
transition: none !important;
}
}.fb-28 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--fb-28-bg);
--fb-28-bg: oklch(0.93 0.13 100);
--fb-28-line: oklch(0.18 0.02 95);
--fb-28-fill: oklch(0.99 0.005 100);
--fb-28-pop: oklch(0.68 0.21 20);
--fb-28-cy: oklch(0.78 0.14 200);
font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
color: var(--fb-28-line);
display: grid;
place-items: center;
padding: clamp(20px,5vw,56px);
background-image: repeating-linear-gradient(45deg,oklch(0.18 0.02 95/.05) 0 2px,transparent 2px 12px);
}
.fb-28 *,
.fb-28 *::before,
.fb-28 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fb-28__stage {
width: min(100%,58ch);
display: grid;
gap: clamp(16px,3vw,26px);
justify-items: center;
text-align: center;
}
.fb-28__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
font-weight: 700;
letter-spacing: .18em;
text-transform: uppercase;
background: var(--fb-28-line);
color: var(--fb-28-bg);
padding: 6px 12px;
}
.fb-28__title {
font-size: clamp(44px,11vw,104px);
line-height: .86;
letter-spacing: -.05em;
font-weight: 900;
text-transform: uppercase;
-webkit-text-stroke: 2px var(--fb-28-line);
color: var(--fb-28-fill);
text-shadow: 7px 7px 0 var(--fb-28-line);
}
.fb-28__title span {
color: var(--fb-28-pop);
}
.fb-28__sub {
max-width: 46ch;
font-size: clamp(13.5px,1.7vw,16.5px);
line-height: 1.55;
font-weight: 560;
text-wrap: pretty;
}
.fb-28__row {
display: flex;
flex-wrap: wrap;
gap: clamp(18px,5vw,34px);
justify-content: center;
align-items: center;
padding: 12px 0 6px;
}
.fb-28__fab {
display: grid;
place-items: center;
inline-size: 68px;
block-size: 68px;
border: 3px solid var(--fb-28-line);
border-radius: 0;
cursor: pointer;
color: var(--fb-28-line);
background: var(--fb-28-fill);
box-shadow: 6px 6px 0 0 var(--fb-28-line);
transition: translate .1s linear,box-shadow .1s linear,background .1s linear;
}
.fb-28__fab svg {
width: 28px;
height: 28px;
}
.fb-28__fab:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line);
background: var(--fb-28-cy);
}
.fb-28__fab:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line);
}
.fb-28__fab:focus-visible {
outline: 3px dashed var(--fb-28-line);
outline-offset: 5px;
}
.fb-28__fab--pop {
background: var(--fb-28-pop);
color: var(--fb-28-fill);
}
.fb-28__fab--pop:hover {
background: oklch(0.75 0.2 22);
}
.fb-28__fab--sticker {
rotate: -4deg;
background: var(--fb-28-cy);
box-shadow: 6px 6px 0 0 var(--fb-28-line),12px 12px 0 0 var(--fb-28-pop);
}
.fb-28__fab--sticker:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line),15px 15px 0 0 var(--fb-28-pop);
background: oklch(0.85 0.14 195);
}
.fb-28__fab--sticker:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line),6px 6px 0 0 var(--fb-28-pop);
}
.fb-28__pill {
display: inline-flex;
align-items: center;
gap: 11px;
block-size: 68px;
padding-inline: 22px 26px;
border: 3px solid var(--fb-28-line);
cursor: pointer;
color: var(--fb-28-line);
background: var(--fb-28-fill);
font-family: inherit;
font-size: 19px;
font-weight: 800;
letter-spacing: -.02em;
text-transform: uppercase;
box-shadow: 6px 6px 0 0 var(--fb-28-line);
transition: translate .1s linear,box-shadow .1s linear,background .1s linear;
}
.fb-28__pill svg {
width: 26px;
height: 26px;
}
.fb-28__pill:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line);
background: var(--fb-28-pop);
color: var(--fb-28-fill);
}
.fb-28__pill:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line);
}
.fb-28__pill:focus-visible {
outline: 3px dashed var(--fb-28-line);
outline-offset: 5px;
}
.fb-28__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
font-weight: 600;
padding: 8px 14px;
border: 2px solid var(--fb-28-line);
background: var(--fb-28-fill);
}
@media (prefers-reduced-motion: reduce) {
.fb-28 * {
transition: none !important;
}
}Here's a working CSS Floating Button 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 Hard Shadow Floating Button CSS
Source: https://codefronts.com/components/css-floating-buttons/fb09/
Neo-brutalism where the interaction, not just the look, is physical: a zero-blur offset shadow acting as a solid slab, and a press that translates the button exactly onto its own shadow so the slab collapses to nothing. Get that arithmetic right and the button feels like a real key being pushed flat against the page.
## HTML
```html
<section class="fb-28" aria-label="Neo brutalist hard shadow floating button demo">
<div class="fb-28__stage">
<p class="fb-28__eyebrow">zero blur · press lands on the slab</p>
<h2 class="fb-28__title">PUSH<br>IT<span>.</span></h2>
<p class="fb-28__sub">Translate equals shadow offset. Press it and the button lands exactly on its own shadow — the mass stays put, only the elevation goes.</p>
<div class="fb-28__row">
<button class="fb-28__fab" type="button" aria-label="Add">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 4v16M4 12h16" stroke="currentColor" stroke-width="3" stroke-linecap="square"/></svg>
</button>
<button class="fb-28__pill" type="button">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/></svg>
<span>Ship it</span>
</button>
<button class="fb-28__fab fb-28__fab--pop" type="button" aria-label="Favourite">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 4l2.5 5.6 6.1.6-4.6 4.1 1.3 6-5.3-3.2-5.3 3.2 1.3-6L3.4 10.2l6.1-.6z" fill="currentColor"/></svg>
</button>
<button class="fb-28__fab fb-28__fab--sticker" type="button" aria-label="Bookmark">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6 3h12v18l-6-4.6L6 21z" fill="currentColor"/></svg>
</button>
</div>
<p class="fb-28__chip">6px offset · 3px border · 100ms linear</p>
</div>
</section>
```
## CSS
```css
.fb-28 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--fb-28-bg);
--fb-28-bg: oklch(0.93 0.13 100);
--fb-28-line: oklch(0.18 0.02 95);
--fb-28-fill: oklch(0.99 0.005 100);
--fb-28-pop: oklch(0.68 0.21 20);
--fb-28-cy: oklch(0.78 0.14 200);
font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
color: var(--fb-28-line);
display: grid;
place-items: center;
padding: clamp(20px,5vw,56px);
background-image: repeating-linear-gradient(45deg,oklch(0.18 0.02 95/.05) 0 2px,transparent 2px 12px);
}
.fb-28 *,
.fb-28 *::before,
.fb-28 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fb-28__stage {
width: min(100%,58ch);
display: grid;
gap: clamp(16px,3vw,26px);
justify-items: center;
text-align: center;
}
.fb-28__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
font-weight: 700;
letter-spacing: .18em;
text-transform: uppercase;
background: var(--fb-28-line);
color: var(--fb-28-bg);
padding: 6px 12px;
}
.fb-28__title {
font-size: clamp(44px,11vw,104px);
line-height: .86;
letter-spacing: -.05em;
font-weight: 900;
text-transform: uppercase;
-webkit-text-stroke: 2px var(--fb-28-line);
color: var(--fb-28-fill);
text-shadow: 7px 7px 0 var(--fb-28-line);
}
.fb-28__title span {
color: var(--fb-28-pop);
}
.fb-28__sub {
max-width: 46ch;
font-size: clamp(13.5px,1.7vw,16.5px);
line-height: 1.55;
font-weight: 560;
text-wrap: pretty;
}
.fb-28__row {
display: flex;
flex-wrap: wrap;
gap: clamp(18px,5vw,34px);
justify-content: center;
align-items: center;
padding: 12px 0 6px;
}
.fb-28__fab {
display: grid;
place-items: center;
inline-size: 68px;
block-size: 68px;
border: 3px solid var(--fb-28-line);
border-radius: 0;
cursor: pointer;
color: var(--fb-28-line);
background: var(--fb-28-fill);
box-shadow: 6px 6px 0 0 var(--fb-28-line);
transition: translate .1s linear,box-shadow .1s linear,background .1s linear;
}
.fb-28__fab svg {
width: 28px;
height: 28px;
}
.fb-28__fab:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line);
background: var(--fb-28-cy);
}
.fb-28__fab:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line);
}
.fb-28__fab:focus-visible {
outline: 3px dashed var(--fb-28-line);
outline-offset: 5px;
}
.fb-28__fab--pop {
background: var(--fb-28-pop);
color: var(--fb-28-fill);
}
.fb-28__fab--pop:hover {
background: oklch(0.75 0.2 22);
}
.fb-28__fab--sticker {
rotate: -4deg;
background: var(--fb-28-cy);
box-shadow: 6px 6px 0 0 var(--fb-28-line),12px 12px 0 0 var(--fb-28-pop);
}
.fb-28__fab--sticker:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line),15px 15px 0 0 var(--fb-28-pop);
background: oklch(0.85 0.14 195);
}
.fb-28__fab--sticker:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line),6px 6px 0 0 var(--fb-28-pop);
}
.fb-28__pill {
display: inline-flex;
align-items: center;
gap: 11px;
block-size: 68px;
padding-inline: 22px 26px;
border: 3px solid var(--fb-28-line);
cursor: pointer;
color: var(--fb-28-line);
background: var(--fb-28-fill);
font-family: inherit;
font-size: 19px;
font-weight: 800;
letter-spacing: -.02em;
text-transform: uppercase;
box-shadow: 6px 6px 0 0 var(--fb-28-line);
transition: translate .1s linear,box-shadow .1s linear,background .1s linear;
}
.fb-28__pill svg {
width: 26px;
height: 26px;
}
.fb-28__pill:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line);
background: var(--fb-28-pop);
color: var(--fb-28-fill);
}
.fb-28__pill:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line);
}
.fb-28__pill:focus-visible {
outline: 3px dashed var(--fb-28-line);
outline-offset: 5px;
}
.fb-28__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
font-weight: 600;
padding: 8px 14px;
border: 2px solid var(--fb-28-line);
background: var(--fb-28-fill);
}
@media (prefers-reduced-motion: reduce) {
.fb-28 * {
transition: none !important;
}
}
```Here's a working CSS Floating Button 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 Hard Shadow Floating Button CSS
Source: https://codefronts.com/components/css-floating-buttons/fb09/
Neo-brutalism where the interaction, not just the look, is physical: a zero-blur offset shadow acting as a solid slab, and a press that translates the button exactly onto its own shadow so the slab collapses to nothing. Get that arithmetic right and the button feels like a real key being pushed flat against the page.
## HTML
```html
<section class="fb-28" aria-label="Neo brutalist hard shadow floating button demo">
<div class="fb-28__stage">
<p class="fb-28__eyebrow">zero blur · press lands on the slab</p>
<h2 class="fb-28__title">PUSH<br>IT<span>.</span></h2>
<p class="fb-28__sub">Translate equals shadow offset. Press it and the button lands exactly on its own shadow — the mass stays put, only the elevation goes.</p>
<div class="fb-28__row">
<button class="fb-28__fab" type="button" aria-label="Add">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 4v16M4 12h16" stroke="currentColor" stroke-width="3" stroke-linecap="square"/></svg>
</button>
<button class="fb-28__pill" type="button">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M5 12h14M13 6l6 6-6 6" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="square"/></svg>
<span>Ship it</span>
</button>
<button class="fb-28__fab fb-28__fab--pop" type="button" aria-label="Favourite">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 4l2.5 5.6 6.1.6-4.6 4.1 1.3 6-5.3-3.2-5.3 3.2 1.3-6L3.4 10.2l6.1-.6z" fill="currentColor"/></svg>
</button>
<button class="fb-28__fab fb-28__fab--sticker" type="button" aria-label="Bookmark">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6 3h12v18l-6-4.6L6 21z" fill="currentColor"/></svg>
</button>
</div>
<p class="fb-28__chip">6px offset · 3px border · 100ms linear</p>
</div>
</section>
```
## CSS
```css
.fb-28 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--fb-28-bg);
--fb-28-bg: oklch(0.93 0.13 100);
--fb-28-line: oklch(0.18 0.02 95);
--fb-28-fill: oklch(0.99 0.005 100);
--fb-28-pop: oklch(0.68 0.21 20);
--fb-28-cy: oklch(0.78 0.14 200);
font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
color: var(--fb-28-line);
display: grid;
place-items: center;
padding: clamp(20px,5vw,56px);
background-image: repeating-linear-gradient(45deg,oklch(0.18 0.02 95/.05) 0 2px,transparent 2px 12px);
}
.fb-28 *,
.fb-28 *::before,
.fb-28 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fb-28__stage {
width: min(100%,58ch);
display: grid;
gap: clamp(16px,3vw,26px);
justify-items: center;
text-align: center;
}
.fb-28__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
font-weight: 700;
letter-spacing: .18em;
text-transform: uppercase;
background: var(--fb-28-line);
color: var(--fb-28-bg);
padding: 6px 12px;
}
.fb-28__title {
font-size: clamp(44px,11vw,104px);
line-height: .86;
letter-spacing: -.05em;
font-weight: 900;
text-transform: uppercase;
-webkit-text-stroke: 2px var(--fb-28-line);
color: var(--fb-28-fill);
text-shadow: 7px 7px 0 var(--fb-28-line);
}
.fb-28__title span {
color: var(--fb-28-pop);
}
.fb-28__sub {
max-width: 46ch;
font-size: clamp(13.5px,1.7vw,16.5px);
line-height: 1.55;
font-weight: 560;
text-wrap: pretty;
}
.fb-28__row {
display: flex;
flex-wrap: wrap;
gap: clamp(18px,5vw,34px);
justify-content: center;
align-items: center;
padding: 12px 0 6px;
}
.fb-28__fab {
display: grid;
place-items: center;
inline-size: 68px;
block-size: 68px;
border: 3px solid var(--fb-28-line);
border-radius: 0;
cursor: pointer;
color: var(--fb-28-line);
background: var(--fb-28-fill);
box-shadow: 6px 6px 0 0 var(--fb-28-line);
transition: translate .1s linear,box-shadow .1s linear,background .1s linear;
}
.fb-28__fab svg {
width: 28px;
height: 28px;
}
.fb-28__fab:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line);
background: var(--fb-28-cy);
}
.fb-28__fab:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line);
}
.fb-28__fab:focus-visible {
outline: 3px dashed var(--fb-28-line);
outline-offset: 5px;
}
.fb-28__fab--pop {
background: var(--fb-28-pop);
color: var(--fb-28-fill);
}
.fb-28__fab--pop:hover {
background: oklch(0.75 0.2 22);
}
.fb-28__fab--sticker {
rotate: -4deg;
background: var(--fb-28-cy);
box-shadow: 6px 6px 0 0 var(--fb-28-line),12px 12px 0 0 var(--fb-28-pop);
}
.fb-28__fab--sticker:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line),15px 15px 0 0 var(--fb-28-pop);
background: oklch(0.85 0.14 195);
}
.fb-28__fab--sticker:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line),6px 6px 0 0 var(--fb-28-pop);
}
.fb-28__pill {
display: inline-flex;
align-items: center;
gap: 11px;
block-size: 68px;
padding-inline: 22px 26px;
border: 3px solid var(--fb-28-line);
cursor: pointer;
color: var(--fb-28-line);
background: var(--fb-28-fill);
font-family: inherit;
font-size: 19px;
font-weight: 800;
letter-spacing: -.02em;
text-transform: uppercase;
box-shadow: 6px 6px 0 0 var(--fb-28-line);
transition: translate .1s linear,box-shadow .1s linear,background .1s linear;
}
.fb-28__pill svg {
width: 26px;
height: 26px;
}
.fb-28__pill:hover {
translate: -2px -2px;
box-shadow: 8px 8px 0 0 var(--fb-28-line);
background: var(--fb-28-pop);
color: var(--fb-28-fill);
}
.fb-28__pill:active {
translate: 6px 6px;
box-shadow: 0 0 0 0 var(--fb-28-line);
}
.fb-28__pill:focus-visible {
outline: 3px dashed var(--fb-28-line);
outline-offset: 5px;
}
.fb-28__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
font-weight: 600;
padding: 8px 14px;
border: 2px solid var(--fb-28-line);
background: var(--fb-28-fill);
}
@media (prefers-reduced-motion: reduce) {
.fb-28 * {
transition: none !important;
}
}
```How this works
The entire effect is one identity — translate distance equals shadow offset:
.brut{ border:3px solid #111; box-shadow:6px 6px 0 0 #111;
transition:translate .1s, box-shadow .1s }
.brut:hover { translate:-2px -2px; box-shadow:8px 8px 0 0 #111 }
.brut:active{ translate: 6px 6px; box-shadow:0 0 0 0 #111 } /* lands flat */On press the button moves down-right by exactly the shadow's offset while the shadow shrinks to zero — so the visual mass stays in the same place on screen and only the elevation disappears. Any mismatch between the two numbers and the button appears to slide sideways instead of being pressed.
Timing is deliberately short and linear (100ms, no easing). Brutalism has no springs; a bouncy neo-brutalist button is a contradiction and reads as a mistake.
The rest is discipline: a single flat fill, a 3px border in near-black rather than pure black, no gradient, no blur anywhere in the file, and a display face with real weight. The style survives or dies on whether you resist adding one soft shadow.
Make it yours
- Offset scale: 4px for compact controls, 6px standard, 10px for hero buttons. Border weight scales with it (2 / 3 / 4px).
- Colour shadow: an accent-coloured slab instead of black reads as pop-art; keep the border black so the shape stays legible.
- Sticker variant: add a slight
rotate(-2deg)and a second offset shadow in a contrasting hue for a layered print look. - Halftone fill: a repeating-radial-gradient dot pattern at 8% opacity gives the fill a risograph texture without a single image.
Gotchas — read before shipping
- Do not blur the shadow "just a little". The whole aesthetic depends on a hard edge; 1px of blur reads as a rendering bug.
- Pure black borders on saturated fills vibrate optically. Use oklch(0.18 …) with a hint of the fill's hue instead.
- Brutalist palettes are usually high-chroma; check text contrast properly, because bright yellow with white text fails badly.
- Offset shadows expand the visual footprint but not the layout box. Reserve margin equal to the offset or neighbouring elements overlap it.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 114+ | 17.5+ | 121+ | 114+ |
Floor set by oklch(), text-wrap as this demo is written. The core technique itself goes back further — Chrome 111+.
box-shadow with zero blur and the translate property are supported everywhere modern (translate: Chrome 104+, Safari 14.1+, Firefox 72+). Use transform:translate() for older engines.