28 CSS Hamburger Menus26 / 28
Neumorphic Hamburger Toggle Button HTML CSS
Soft-UI physics done by the rules: the burger is a clay button raised from the surface by the canonical dual shadow (light from the top-left, dark to the bottom-right), and pressing it doesn't move it — it inverts the shadows to inset, so the button visibly sinks INTO the surface while its lines fold to an X. The state is a real checkbox (a toggle IS a checkbox), the soft menu card floats up on the same material system, and the docs carry the honest accessibility warning neumorphism demands.
Published Updated
The code
<section class="chm-26" aria-label="Neumorphic hamburger toggle demo">
<div class="chm-26__stage">
<input type="checkbox" id="chm26-t" class="chm-26__state">
<div class="chm-26__plate">
<label for="chm26-t" class="chm-26__btn">
<span class="chm-26__ico" aria-hidden="true"><i></i><i></i><i></i></span>
</label>
<span class="chm-26__word" aria-hidden="true"><b class="chm-26__w1">rest</b><b class="chm-26__w2">pressed</b></span>
</div>
<nav class="chm-26__menu" aria-label="Menu">
<a href="#home" style="--i:0"><i class="chm-26__dot" aria-hidden="true"></i>Home</a>
<a href="#library" style="--i:1"><i class="chm-26__dot" aria-hidden="true"></i>Library</a>
<a href="#stats" style="--i:2"><i class="chm-26__dot" aria-hidden="true"></i>Statistics</a>
<a href="#settings" style="--i:3"><i class="chm-26__dot" aria-hidden="true"></i>Settings</a>
</nav>
<p class="chm-26__note" aria-hidden="true">same clay, two shadows — pressed = the pair goes <code>inset</code>. Note the focus ring stays loud on purpose.</p>
</div>
</section><section class="chm-26" aria-label="Neumorphic hamburger toggle demo">
<div class="chm-26__stage">
<input type="checkbox" id="chm26-t" class="chm-26__state">
<div class="chm-26__plate">
<label for="chm26-t" class="chm-26__btn">
<span class="chm-26__ico" aria-hidden="true"><i></i><i></i><i></i></span>
</label>
<span class="chm-26__word" aria-hidden="true"><b class="chm-26__w1">rest</b><b class="chm-26__w2">pressed</b></span>
</div>
<nav class="chm-26__menu" aria-label="Menu">
<a href="#home" style="--i:0"><i class="chm-26__dot" aria-hidden="true"></i>Home</a>
<a href="#library" style="--i:1"><i class="chm-26__dot" aria-hidden="true"></i>Library</a>
<a href="#stats" style="--i:2"><i class="chm-26__dot" aria-hidden="true"></i>Statistics</a>
<a href="#settings" style="--i:3"><i class="chm-26__dot" aria-hidden="true"></i>Settings</a>
</nav>
<p class="chm-26__note" aria-hidden="true">same clay, two shadows — pressed = the pair goes <code>inset</code>. Note the focus ring stays loud on purpose.</p>
</div>
</section>.chm-26,
.chm-26 *,
.chm-26 *::before,
.chm-26 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.chm-26 {
background: var(--bg);
width: 100%;
min-height: 100vh;
box-sizing: border-box;
--clay: oklch(0.92 0.012 260);
--lite: oklch(0.99 0.005 260);
--shade: oklch(0.78 0.02 260);
--ink: oklch(0.32 0.02 262);
--mut: oklch(0.52 0.018 262);
--acc: oklch(0.65 0.11 190);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.chm-26__stage {
position: relative;
min-height: 480px;
border-radius: 22px;
background: var(--clay);
padding: 34px 28px;
display: flex;
flex-direction: column;
align-items: center;
gap: 26px;
border: 1px solid oklch(0.87 0.014 260);
}
.chm-26__state {
position: absolute;
width: 1px;
height: 1px;
clip-path: inset(50%);
overflow: hidden;
white-space: nowrap;
}
.chm-26__plate {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
}
.chm-26__btn {
width: 74px;
height: 74px;
display: grid;
place-items: center;
border-radius: 22px;
background: var(--clay);
cursor: pointer;
box-shadow: -7px -7px 14px var(--lite),7px 7px 14px var(--shade);
transition: box-shadow .3s ease;
}
.chm-26__btn:hover {
box-shadow: -9px -9px 18px var(--lite),9px 9px 18px var(--shade);
}
.chm-26__state:focus-visible ~ .chm-26__plate .chm-26__btn {
outline: 3px solid var(--acc);
outline-offset: 3px;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__btn {
box-shadow: inset -5px -5px 10px var(--lite),inset 5px 5px 10px var(--shade);
}
.chm-26__ico {
position: relative;
width: 24px;
height: 16px;
display: block;
}
.chm-26__ico i {
position: absolute;
left: 0;
width: 24px;
height: 2.6px;
border-radius: 3px;
background: var(--ink);
transition: translate .3s cubic-bezier(.2,.7,.2,1),rotate .3s cubic-bezier(.2,.7,.2,1) .05s,opacity .2s,background .3s;
}
.chm-26__ico i:nth-child(1) {
top: 0;
}
.chm-26__ico i:nth-child(2) {
top: 6.7px;
}
.chm-26__ico i:nth-child(3) {
top: 13.4px;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i {
background: var(--acc);
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(1) {
translate: 0 6.7px;
rotate: 45deg;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(2) {
opacity: 0;
scale: .4 1;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(3) {
translate: 0 -6.7px;
rotate: -45deg;
}
.chm-26__word {
position: relative;
height: 16px;
overflow: hidden;
display: block;
font-size: 11px;
letter-spacing: .22em;
text-transform: uppercase;
color: var(--mut);
}
.chm-26__word b {
display: block;
height: 16px;
line-height: 16px;
font-weight: 700;
transition: translate .35s cubic-bezier(.2,.7,.2,1);
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__word b {
translate: 0 -16px;
}
.chm-26__menu {
width: min(280px,100%);
display: grid;
gap: 14px;
padding: 6px;
}
.chm-26__menu a {
display: flex;
align-items: center;
gap: 13px;
min-height: 52px;
padding: 0 20px;
border-radius: 16px;
background: var(--clay);
color: var(--ink);
font-size: 14px;
font-weight: 700;
text-decoration: none;
box-shadow: -6px -6px 12px var(--lite),6px 6px 12px var(--shade);
opacity: 0;
translate: 0 12px;
pointer-events: none;
transition: box-shadow .25s,opacity .3s,translate .35s cubic-bezier(.2,.7,.2,1),color .2s;
}
.chm-26__state:checked ~ .chm-26__menu a {
opacity: 1;
translate: 0 0;
pointer-events: auto;
transition-delay: 0s,calc(.08s + var(--i)*.05s),calc(.08s + var(--i)*.05s),0s;
}
.chm-26__menu a:hover {
color: var(--acc);
}
.chm-26__menu a:active {
box-shadow: inset -4px -4px 8px var(--lite),inset 4px 4px 8px var(--shade);
}
.chm-26__menu a:focus-visible {
outline: 3px solid var(--acc);
outline-offset: 2px;
}
.chm-26__dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--clay);
box-shadow: inset -2px -2px 4px var(--lite),inset 2px 2px 4px var(--shade);
transition: background .2s,box-shadow .2s;
}
.chm-26__menu a:hover .chm-26__dot,
.chm-26__menu a:focus-visible .chm-26__dot {
background: var(--acc);
box-shadow: none;
}
.chm-26__note {
margin-top: auto;
font-size: 12px;
line-height: 1.6;
color: var(--mut);
text-align: center;
max-width: 34ch;
text-wrap: pretty;
}
.chm-26__note code {
font: 11px ui-monospace,Menlo,Consolas,monospace;
background: oklch(0.88 0.014 260);
border-radius: 5px;
padding: 1.5px 6px;
}
@media (prefers-reduced-motion: reduce) {
.chm-26 * {
transition-duration: .01s !important;
transition-delay: 0s !important;
}
}.chm-26,
.chm-26 *,
.chm-26 *::before,
.chm-26 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.chm-26 {
background: var(--bg);
width: 100%;
min-height: 100vh;
box-sizing: border-box;
--clay: oklch(0.92 0.012 260);
--lite: oklch(0.99 0.005 260);
--shade: oklch(0.78 0.02 260);
--ink: oklch(0.32 0.02 262);
--mut: oklch(0.52 0.018 262);
--acc: oklch(0.65 0.11 190);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.chm-26__stage {
position: relative;
min-height: 480px;
border-radius: 22px;
background: var(--clay);
padding: 34px 28px;
display: flex;
flex-direction: column;
align-items: center;
gap: 26px;
border: 1px solid oklch(0.87 0.014 260);
}
.chm-26__state {
position: absolute;
width: 1px;
height: 1px;
clip-path: inset(50%);
overflow: hidden;
white-space: nowrap;
}
.chm-26__plate {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
}
.chm-26__btn {
width: 74px;
height: 74px;
display: grid;
place-items: center;
border-radius: 22px;
background: var(--clay);
cursor: pointer;
box-shadow: -7px -7px 14px var(--lite),7px 7px 14px var(--shade);
transition: box-shadow .3s ease;
}
.chm-26__btn:hover {
box-shadow: -9px -9px 18px var(--lite),9px 9px 18px var(--shade);
}
.chm-26__state:focus-visible ~ .chm-26__plate .chm-26__btn {
outline: 3px solid var(--acc);
outline-offset: 3px;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__btn {
box-shadow: inset -5px -5px 10px var(--lite),inset 5px 5px 10px var(--shade);
}
.chm-26__ico {
position: relative;
width: 24px;
height: 16px;
display: block;
}
.chm-26__ico i {
position: absolute;
left: 0;
width: 24px;
height: 2.6px;
border-radius: 3px;
background: var(--ink);
transition: translate .3s cubic-bezier(.2,.7,.2,1),rotate .3s cubic-bezier(.2,.7,.2,1) .05s,opacity .2s,background .3s;
}
.chm-26__ico i:nth-child(1) {
top: 0;
}
.chm-26__ico i:nth-child(2) {
top: 6.7px;
}
.chm-26__ico i:nth-child(3) {
top: 13.4px;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i {
background: var(--acc);
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(1) {
translate: 0 6.7px;
rotate: 45deg;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(2) {
opacity: 0;
scale: .4 1;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(3) {
translate: 0 -6.7px;
rotate: -45deg;
}
.chm-26__word {
position: relative;
height: 16px;
overflow: hidden;
display: block;
font-size: 11px;
letter-spacing: .22em;
text-transform: uppercase;
color: var(--mut);
}
.chm-26__word b {
display: block;
height: 16px;
line-height: 16px;
font-weight: 700;
transition: translate .35s cubic-bezier(.2,.7,.2,1);
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__word b {
translate: 0 -16px;
}
.chm-26__menu {
width: min(280px,100%);
display: grid;
gap: 14px;
padding: 6px;
}
.chm-26__menu a {
display: flex;
align-items: center;
gap: 13px;
min-height: 52px;
padding: 0 20px;
border-radius: 16px;
background: var(--clay);
color: var(--ink);
font-size: 14px;
font-weight: 700;
text-decoration: none;
box-shadow: -6px -6px 12px var(--lite),6px 6px 12px var(--shade);
opacity: 0;
translate: 0 12px;
pointer-events: none;
transition: box-shadow .25s,opacity .3s,translate .35s cubic-bezier(.2,.7,.2,1),color .2s;
}
.chm-26__state:checked ~ .chm-26__menu a {
opacity: 1;
translate: 0 0;
pointer-events: auto;
transition-delay: 0s,calc(.08s + var(--i)*.05s),calc(.08s + var(--i)*.05s),0s;
}
.chm-26__menu a:hover {
color: var(--acc);
}
.chm-26__menu a:active {
box-shadow: inset -4px -4px 8px var(--lite),inset 4px 4px 8px var(--shade);
}
.chm-26__menu a:focus-visible {
outline: 3px solid var(--acc);
outline-offset: 2px;
}
.chm-26__dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--clay);
box-shadow: inset -2px -2px 4px var(--lite),inset 2px 2px 4px var(--shade);
transition: background .2s,box-shadow .2s;
}
.chm-26__menu a:hover .chm-26__dot,
.chm-26__menu a:focus-visible .chm-26__dot {
background: var(--acc);
box-shadow: none;
}
.chm-26__note {
margin-top: auto;
font-size: 12px;
line-height: 1.6;
color: var(--mut);
text-align: center;
max-width: 34ch;
text-wrap: pretty;
}
.chm-26__note code {
font: 11px ui-monospace,Menlo,Consolas,monospace;
background: oklch(0.88 0.014 260);
border-radius: 5px;
padding: 1.5px 6px;
}
@media (prefers-reduced-motion: reduce) {
.chm-26 * {
transition-duration: .01s !important;
transition-delay: 0s !important;
}
}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: Neumorphic Hamburger Toggle Button HTML CSS
Source: https://codefronts.com/navigation/css-hamburger-menus/neumorphic-hamburger-menu-toggle-button/
Soft-UI physics done by the rules: the burger is a clay button raised from the surface by the canonical dual shadow (light from the top-left, dark to the bottom-right), and pressing it doesn't move it — it inverts the shadows to inset, so the button visibly sinks INTO the surface while its lines fold to an X. The state is a real checkbox (a toggle IS a checkbox), the soft menu card floats up on the same material system, and the docs carry the honest accessibility warning neumorphism demands.
## HTML
```html
<section class="chm-26" aria-label="Neumorphic hamburger toggle demo">
<div class="chm-26__stage">
<input type="checkbox" id="chm26-t" class="chm-26__state">
<div class="chm-26__plate">
<label for="chm26-t" class="chm-26__btn">
<span class="chm-26__ico" aria-hidden="true"><i></i><i></i><i></i></span>
</label>
<span class="chm-26__word" aria-hidden="true"><b class="chm-26__w1">rest</b><b class="chm-26__w2">pressed</b></span>
</div>
<nav class="chm-26__menu" aria-label="Menu">
<a href="#home" style="--i:0"><i class="chm-26__dot" aria-hidden="true"></i>Home</a>
<a href="#library" style="--i:1"><i class="chm-26__dot" aria-hidden="true"></i>Library</a>
<a href="#stats" style="--i:2"><i class="chm-26__dot" aria-hidden="true"></i>Statistics</a>
<a href="#settings" style="--i:3"><i class="chm-26__dot" aria-hidden="true"></i>Settings</a>
</nav>
<p class="chm-26__note" aria-hidden="true">same clay, two shadows — pressed = the pair goes <code>inset</code>. Note the focus ring stays loud on purpose.</p>
</div>
</section>
```
## CSS
```css
.chm-26,
.chm-26 *,
.chm-26 *::before,
.chm-26 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.chm-26 {
background: var(--bg);
width: 100%;
min-height: 100vh;
box-sizing: border-box;
--clay: oklch(0.92 0.012 260);
--lite: oklch(0.99 0.005 260);
--shade: oklch(0.78 0.02 260);
--ink: oklch(0.32 0.02 262);
--mut: oklch(0.52 0.018 262);
--acc: oklch(0.65 0.11 190);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.chm-26__stage {
position: relative;
min-height: 480px;
border-radius: 22px;
background: var(--clay);
padding: 34px 28px;
display: flex;
flex-direction: column;
align-items: center;
gap: 26px;
border: 1px solid oklch(0.87 0.014 260);
}
.chm-26__state {
position: absolute;
width: 1px;
height: 1px;
clip-path: inset(50%);
overflow: hidden;
white-space: nowrap;
}
.chm-26__plate {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
}
.chm-26__btn {
width: 74px;
height: 74px;
display: grid;
place-items: center;
border-radius: 22px;
background: var(--clay);
cursor: pointer;
box-shadow: -7px -7px 14px var(--lite),7px 7px 14px var(--shade);
transition: box-shadow .3s ease;
}
.chm-26__btn:hover {
box-shadow: -9px -9px 18px var(--lite),9px 9px 18px var(--shade);
}
.chm-26__state:focus-visible ~ .chm-26__plate .chm-26__btn {
outline: 3px solid var(--acc);
outline-offset: 3px;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__btn {
box-shadow: inset -5px -5px 10px var(--lite),inset 5px 5px 10px var(--shade);
}
.chm-26__ico {
position: relative;
width: 24px;
height: 16px;
display: block;
}
.chm-26__ico i {
position: absolute;
left: 0;
width: 24px;
height: 2.6px;
border-radius: 3px;
background: var(--ink);
transition: translate .3s cubic-bezier(.2,.7,.2,1),rotate .3s cubic-bezier(.2,.7,.2,1) .05s,opacity .2s,background .3s;
}
.chm-26__ico i:nth-child(1) {
top: 0;
}
.chm-26__ico i:nth-child(2) {
top: 6.7px;
}
.chm-26__ico i:nth-child(3) {
top: 13.4px;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i {
background: var(--acc);
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(1) {
translate: 0 6.7px;
rotate: 45deg;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(2) {
opacity: 0;
scale: .4 1;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(3) {
translate: 0 -6.7px;
rotate: -45deg;
}
.chm-26__word {
position: relative;
height: 16px;
overflow: hidden;
display: block;
font-size: 11px;
letter-spacing: .22em;
text-transform: uppercase;
color: var(--mut);
}
.chm-26__word b {
display: block;
height: 16px;
line-height: 16px;
font-weight: 700;
transition: translate .35s cubic-bezier(.2,.7,.2,1);
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__word b {
translate: 0 -16px;
}
.chm-26__menu {
width: min(280px,100%);
display: grid;
gap: 14px;
padding: 6px;
}
.chm-26__menu a {
display: flex;
align-items: center;
gap: 13px;
min-height: 52px;
padding: 0 20px;
border-radius: 16px;
background: var(--clay);
color: var(--ink);
font-size: 14px;
font-weight: 700;
text-decoration: none;
box-shadow: -6px -6px 12px var(--lite),6px 6px 12px var(--shade);
opacity: 0;
translate: 0 12px;
pointer-events: none;
transition: box-shadow .25s,opacity .3s,translate .35s cubic-bezier(.2,.7,.2,1),color .2s;
}
.chm-26__state:checked ~ .chm-26__menu a {
opacity: 1;
translate: 0 0;
pointer-events: auto;
transition-delay: 0s,calc(.08s + var(--i)*.05s),calc(.08s + var(--i)*.05s),0s;
}
.chm-26__menu a:hover {
color: var(--acc);
}
.chm-26__menu a:active {
box-shadow: inset -4px -4px 8px var(--lite),inset 4px 4px 8px var(--shade);
}
.chm-26__menu a:focus-visible {
outline: 3px solid var(--acc);
outline-offset: 2px;
}
.chm-26__dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--clay);
box-shadow: inset -2px -2px 4px var(--lite),inset 2px 2px 4px var(--shade);
transition: background .2s,box-shadow .2s;
}
.chm-26__menu a:hover .chm-26__dot,
.chm-26__menu a:focus-visible .chm-26__dot {
background: var(--acc);
box-shadow: none;
}
.chm-26__note {
margin-top: auto;
font-size: 12px;
line-height: 1.6;
color: var(--mut);
text-align: center;
max-width: 34ch;
text-wrap: pretty;
}
.chm-26__note code {
font: 11px ui-monospace,Menlo,Consolas,monospace;
background: oklch(0.88 0.014 260);
border-radius: 5px;
padding: 1.5px 6px;
}
@media (prefers-reduced-motion: reduce) {
.chm-26 * {
transition-duration: .01s !important;
transition-delay: 0s !important;
}
}
```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: Neumorphic Hamburger Toggle Button HTML CSS
Source: https://codefronts.com/navigation/css-hamburger-menus/neumorphic-hamburger-menu-toggle-button/
Soft-UI physics done by the rules: the burger is a clay button raised from the surface by the canonical dual shadow (light from the top-left, dark to the bottom-right), and pressing it doesn't move it — it inverts the shadows to inset, so the button visibly sinks INTO the surface while its lines fold to an X. The state is a real checkbox (a toggle IS a checkbox), the soft menu card floats up on the same material system, and the docs carry the honest accessibility warning neumorphism demands.
## HTML
```html
<section class="chm-26" aria-label="Neumorphic hamburger toggle demo">
<div class="chm-26__stage">
<input type="checkbox" id="chm26-t" class="chm-26__state">
<div class="chm-26__plate">
<label for="chm26-t" class="chm-26__btn">
<span class="chm-26__ico" aria-hidden="true"><i></i><i></i><i></i></span>
</label>
<span class="chm-26__word" aria-hidden="true"><b class="chm-26__w1">rest</b><b class="chm-26__w2">pressed</b></span>
</div>
<nav class="chm-26__menu" aria-label="Menu">
<a href="#home" style="--i:0"><i class="chm-26__dot" aria-hidden="true"></i>Home</a>
<a href="#library" style="--i:1"><i class="chm-26__dot" aria-hidden="true"></i>Library</a>
<a href="#stats" style="--i:2"><i class="chm-26__dot" aria-hidden="true"></i>Statistics</a>
<a href="#settings" style="--i:3"><i class="chm-26__dot" aria-hidden="true"></i>Settings</a>
</nav>
<p class="chm-26__note" aria-hidden="true">same clay, two shadows — pressed = the pair goes <code>inset</code>. Note the focus ring stays loud on purpose.</p>
</div>
</section>
```
## CSS
```css
.chm-26,
.chm-26 *,
.chm-26 *::before,
.chm-26 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.chm-26 {
background: var(--bg);
width: 100%;
min-height: 100vh;
box-sizing: border-box;
--clay: oklch(0.92 0.012 260);
--lite: oklch(0.99 0.005 260);
--shade: oklch(0.78 0.02 260);
--ink: oklch(0.32 0.02 262);
--mut: oklch(0.52 0.018 262);
--acc: oklch(0.65 0.11 190);
font-family: 'Segoe UI',system-ui,sans-serif;
color: var(--ink);
}
.chm-26__stage {
position: relative;
min-height: 480px;
border-radius: 22px;
background: var(--clay);
padding: 34px 28px;
display: flex;
flex-direction: column;
align-items: center;
gap: 26px;
border: 1px solid oklch(0.87 0.014 260);
}
.chm-26__state {
position: absolute;
width: 1px;
height: 1px;
clip-path: inset(50%);
overflow: hidden;
white-space: nowrap;
}
.chm-26__plate {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
}
.chm-26__btn {
width: 74px;
height: 74px;
display: grid;
place-items: center;
border-radius: 22px;
background: var(--clay);
cursor: pointer;
box-shadow: -7px -7px 14px var(--lite),7px 7px 14px var(--shade);
transition: box-shadow .3s ease;
}
.chm-26__btn:hover {
box-shadow: -9px -9px 18px var(--lite),9px 9px 18px var(--shade);
}
.chm-26__state:focus-visible ~ .chm-26__plate .chm-26__btn {
outline: 3px solid var(--acc);
outline-offset: 3px;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__btn {
box-shadow: inset -5px -5px 10px var(--lite),inset 5px 5px 10px var(--shade);
}
.chm-26__ico {
position: relative;
width: 24px;
height: 16px;
display: block;
}
.chm-26__ico i {
position: absolute;
left: 0;
width: 24px;
height: 2.6px;
border-radius: 3px;
background: var(--ink);
transition: translate .3s cubic-bezier(.2,.7,.2,1),rotate .3s cubic-bezier(.2,.7,.2,1) .05s,opacity .2s,background .3s;
}
.chm-26__ico i:nth-child(1) {
top: 0;
}
.chm-26__ico i:nth-child(2) {
top: 6.7px;
}
.chm-26__ico i:nth-child(3) {
top: 13.4px;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i {
background: var(--acc);
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(1) {
translate: 0 6.7px;
rotate: 45deg;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(2) {
opacity: 0;
scale: .4 1;
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__ico i:nth-child(3) {
translate: 0 -6.7px;
rotate: -45deg;
}
.chm-26__word {
position: relative;
height: 16px;
overflow: hidden;
display: block;
font-size: 11px;
letter-spacing: .22em;
text-transform: uppercase;
color: var(--mut);
}
.chm-26__word b {
display: block;
height: 16px;
line-height: 16px;
font-weight: 700;
transition: translate .35s cubic-bezier(.2,.7,.2,1);
}
.chm-26__state:checked ~ .chm-26__plate .chm-26__word b {
translate: 0 -16px;
}
.chm-26__menu {
width: min(280px,100%);
display: grid;
gap: 14px;
padding: 6px;
}
.chm-26__menu a {
display: flex;
align-items: center;
gap: 13px;
min-height: 52px;
padding: 0 20px;
border-radius: 16px;
background: var(--clay);
color: var(--ink);
font-size: 14px;
font-weight: 700;
text-decoration: none;
box-shadow: -6px -6px 12px var(--lite),6px 6px 12px var(--shade);
opacity: 0;
translate: 0 12px;
pointer-events: none;
transition: box-shadow .25s,opacity .3s,translate .35s cubic-bezier(.2,.7,.2,1),color .2s;
}
.chm-26__state:checked ~ .chm-26__menu a {
opacity: 1;
translate: 0 0;
pointer-events: auto;
transition-delay: 0s,calc(.08s + var(--i)*.05s),calc(.08s + var(--i)*.05s),0s;
}
.chm-26__menu a:hover {
color: var(--acc);
}
.chm-26__menu a:active {
box-shadow: inset -4px -4px 8px var(--lite),inset 4px 4px 8px var(--shade);
}
.chm-26__menu a:focus-visible {
outline: 3px solid var(--acc);
outline-offset: 2px;
}
.chm-26__dot {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--clay);
box-shadow: inset -2px -2px 4px var(--lite),inset 2px 2px 4px var(--shade);
transition: background .2s,box-shadow .2s;
}
.chm-26__menu a:hover .chm-26__dot,
.chm-26__menu a:focus-visible .chm-26__dot {
background: var(--acc);
box-shadow: none;
}
.chm-26__note {
margin-top: auto;
font-size: 12px;
line-height: 1.6;
color: var(--mut);
text-align: center;
max-width: 34ch;
text-wrap: pretty;
}
.chm-26__note code {
font: 11px ui-monospace,Menlo,Consolas,monospace;
background: oklch(0.88 0.014 260);
border-radius: 5px;
padding: 1.5px 6px;
}
@media (prefers-reduced-motion: reduce) {
.chm-26 * {
transition-duration: .01s !important;
transition-delay: 0s !important;
}
}
```How this works
Neumorphism is one material rule applied consistently: every element is the SAME color as the background, shaped purely by two opposing shadows from one imaginary light source:
.surface{ background:oklch(0.92 0.012 260); }
.btn{
background:inherit; /* same clay */
box-shadow: -7px -7px 14px oklch(0.99 0.005 260), /* light */
7px 7px 14px oklch(0.78 0.02 260); /* shade */
}
#chm26-t:checked ~ .btn{
box-shadow: inset -5px -5px 10px oklch(0.99 0.005 260),
inset 5px 5px 10px oklch(0.78 0.02 260);
}Raised = outset pair; pressed = the SAME pair inset. That inversion is the entire interaction language — no translate, no scale; the light does the talking. Keep the light source fixed forever: one element lit from elsewhere shatters the illusion (the #1 neumorphic bug — copy-pasted shadows with flipped signs).
Radii follow the material too: soft clay wants generous rounding (18px on a 64px button), and the menu card raises with a LARGER blur (safer read: farther from surface = softer, wider shadows). Transition the box-shadow (both states declare full shadow pairs, so the interpolation is smooth).
The a11y warning, printed in bold because this style is famous for failing audits: neumorphism is intrinsically low-contrast — the button's edge against the surface is often under 1.4:1, far below the 3:1 WCAG 1.4.11 requires for control boundaries. This build compensates where it counts: ink-dark lines (7.8:1), a real focus ring that ignores the soft aesthetic entirely, and the pressed state ALSO changes line color (never shadow-only state signaling). Treat soft-UI as a skin over compliant bones, not a substitute for them.
Make it yours
- The whole theme is three tokens: --clay (surface), --lite, --shade. Warm clay: hue 60; cool porcelain: hue 260 (as shipped). Keep lightness within ±0.10 of the surface or shadows go muddy.
- Depth: shadow offset 7px/blur 14px = standard; 4/8 = subtle plaque; 10/24 = pillow. Offsets and blur scale together, roughly 1:2.
- The menu card's items are raised pills that flatten (shadow:none) on press — the same inversion grammar; restyle only the shadow recipe to retheme everything.
- Add an accent (this demo's teal check-dot) sparingly — pure monochrome neumorphism reads as decoration, not UI; one saturated cue restores hierarchy.
Gotchas — read before shipping
- Neumorphism only exists on midtone surfaces — on white the light shadow vanishes, on near-black the dark one does. If your brand background is either, this is the wrong pattern (and this demo's docs say so out loud).
- background:inherit on the button assumes it sits DIRECTLY on the surface — inside a differently-colored card the inherit chain breaks; re-declare the clay explicitly.
- Soft shadows are paint-heavy; a page of 50 neumorphic elements measurably slows low-end scroll. It's a hero-element style, not a system.
- Never remove the focus outline because 'it ruins the softness' — that instinct is how neumorphic UIs fail WCAG 2.4.7. Ring it anyway (this demo's ring offsets 3px so the clay stays clean at rest).
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+.
Dual box-shadows and inset transitions run in every engine of the last decade — the floor is only the oklch() palette. This is also the easiest demo to port to hex for legacy.