28 CSS Close Buttons07 / 28

Pure CSSMIT licensed

Neumorphic Soft Shadow Close Button

A tactile soft-UI dismiss: the button appears extruded from a putty-coloured surface by dual opposing box-shadows (light from the top-left, dark to the bottom-right), then visibly presses IN when clicked by swapping to inset shadows — a physical push-button without a single layout shift.

Published

Live Demo
Try it

The code

<section class="ccb-07" aria-label="Neumorphic close button demo">
  <div class="ccb-07__panel">
    <button class="ccb-07__close" type="button" aria-label="Close"></button>
    <span class="ccb-07__hint">press me</span>
  </div>
</section>
.ccb-07,
.ccb-07 *,
.ccb-07 *::before,
.ccb-07 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.ccb-07 {
  --surface: oklch(0.9 0.015 260);
  --lite: color-mix(in oklab,var(--surface) 30%,white);
  --dark: color-mix(in oklab,var(--surface) 88%,black);
  --ink: oklch(0.45 0.04 265);
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 48px 24px;
  background: var(--surface);
}

.ccb-07 .ccb-07__panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.ccb-07 .ccb-07__close {
  position: relative;
  width: 64px;
  height: 64px;
  border: none;
  border-radius: 50%;
  background: var(--surface);
  cursor: pointer;
  box-shadow: -6px -6px 14px var(--lite),6px 6px 14px var(--dark);
  transition: box-shadow .09s ease;
}

.ccb-07 .ccb-07__close::before,
.ccb-07 .ccb-07__close::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 2.5px;
  border-radius: 2px;
  background: var(--ink);
  transition: opacity .09s ease;
}

.ccb-07 .ccb-07__close::before {
  transform: translate(-50%,-50%) rotate(45deg);
}

.ccb-07 .ccb-07__close::after {
  transform: translate(-50%,-50%) rotate(-45deg);
}

.ccb-07 .ccb-07__close:hover {
  box-shadow: -8px -8px 18px var(--lite),8px 8px 18px var(--dark);
}

.ccb-07 .ccb-07__close:active {
  box-shadow: inset -5px -5px 12px var(--lite),inset 5px 5px 12px var(--dark);
}

.ccb-07 .ccb-07__close:active::before,
.ccb-07 .ccb-07__close:active::after {
  opacity: .65;
}

.ccb-07 .ccb-07__close:focus-visible {
  outline: 3px solid oklch(0.5 0.18 265);
  outline-offset: 3px;
}

.ccb-07 .ccb-07__hint {
  font-size: 12px;
  letter-spacing: .05em;
  color: color-mix(in oklab,var(--ink) 60%,transparent);
}

@media (prefers-reduced-motion: reduce) {
  .ccb-07 .ccb-07__close,
    .ccb-07 .ccb-07__close::before,
    .ccb-07 .ccb-07__close::after {
    transition: none;
  }
}
/* No JavaScript — dual opposing box-shadows extrude the button; :active swaps them to inset for a physical press, zero layout shift. */
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 Close 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: Neumorphic Soft Shadow Close Button
Source: https://codefronts.com/components/css-close-buttons/neumorphic-soft-shadow-close-button/

A tactile soft-UI dismiss: the button appears extruded from a putty-coloured surface by dual opposing box-shadows (light from the top-left, dark to the bottom-right), then visibly presses IN when clicked by swapping to inset shadows — a physical push-button without a single layout shift.
## HTML
```html
<section class="ccb-07" aria-label="Neumorphic close button demo">
  <div class="ccb-07__panel">
    <button class="ccb-07__close" type="button" aria-label="Close"></button>
    <span class="ccb-07__hint">press me</span>
  </div>
</section>
```
## CSS
```css
.ccb-07,
.ccb-07 *,
.ccb-07 *::before,
.ccb-07 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.ccb-07 {
  --surface: oklch(0.9 0.015 260);
  --lite: color-mix(in oklab,var(--surface) 30%,white);
  --dark: color-mix(in oklab,var(--surface) 88%,black);
  --ink: oklch(0.45 0.04 265);
  font-family: 'Segoe UI',system-ui,sans-serif;
  width: 100%;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 48px 24px;
  background: var(--surface);
}

.ccb-07 .ccb-07__panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.ccb-07 .ccb-07__close {
  position: relative;
  width: 64px;
  height: 64px;
  border: none;
  border-radius: 50%;
  background: var(--surface);
  cursor: pointer;
  box-shadow: -6px -6px 14px var(--lite),6px 6px 14px var(--dark);
  transition: box-shadow .09s ease;
}

.ccb-07 .ccb-07__close::before,
.ccb-07 .ccb-07__close::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 20px;
  height: 2.5px;
  border-radius: 2px;
  background: var(--ink);
  transition: opacity .09s ease;
}

.ccb-07 .ccb-07__close::before {
  transform: translate(-50%,-50%) rotate(45deg);
}

.ccb-07 .ccb-07__close::after {
  transform: translate(-50%,-50%) rotate(-45deg);
}

.ccb-07 .ccb-07__close:hover {
  box-shadow: -8px -8px 18px var(--lite),8px 8px 18px var(--dark);
}

.ccb-07 .ccb-07__close:active {
  box-shadow: inset -5px -5px 12px var(--lite),inset 5px 5px 12px var(--dark);
}

.ccb-07 .ccb-07__close:active::before,
.ccb-07 .ccb-07__close:active::after {
  opacity: .65;
}

.ccb-07 .ccb-07__close:focus-visible {
  outline: 3px solid oklch(0.5 0.18 265);
  outline-offset: 3px;
}

.ccb-07 .ccb-07__hint {
  font-size: 12px;
  letter-spacing: .05em;
  color: color-mix(in oklab,var(--ink) 60%,transparent);
}

@media (prefers-reduced-motion: reduce) {
  .ccb-07 .ccb-07__close,
    .ccb-07 .ccb-07__close::before,
    .ccb-07 .ccb-07__close::after {
    transition: none;
  }
}
```

## JavaScript
```js
/* No JavaScript — dual opposing box-shadows extrude the button; :active swaps them to inset for a physical press, zero layout shift. */
```

How this works

Neumorphism is two shadows: box-shadow: -6px -6px 14px light, 6px 6px 14px dark raises the element; the :active state swaps to the same pair with inset, sinking it. Because only shadows change — never size or position — the press causes zero reflow and the × stays optically stable.

Both shadow colors derive from ONE surface color via color-mix: light = surface mixed 70% toward white, dark = 12% toward black. Change --surface and the entire material re-lights itself. The × bars dim slightly on press, selling the "pushed below the light source" read. Focus gets a high-contrast ring because low-contrast soft UI is exactly where keyboard users get lost.

Make it yours

  • Re-material everything by changing --surface alone — both shadows recompute.
  • Deepen extrusion with larger blur/offset pairs (10px/24px reads chunky and playful).
  • Square the button (border-radius:18px) for keypad-style panels.
  • Add a subtle transition on box-shadow (kept at 90ms here) — slower reads mushy.

Gotchas — read before shipping

  • Neumorphism lives or dies by ONE consistent light source — if other elements light from top-left, this button must too.
  • Never place it on a different-coloured card than --surface; the illusion requires button and background to share material.
  • The style's inherently low contrast fails WCAG for the glyph if you dim it too far — keep the × at ≥4.5:1 against the surface.

Browser support

ChromeSafariFirefoxEdge
111+16.4+113+111+

color-mix computes the material; box-shadow pairs work everywhere.

Techniques used in this demo

Search CodeFronts

Loading…