28 CSS Close Buttons16 / 28
Glitch Cross Close Button
A cyberpunk dismiss for dark dashboards and game UI: on hover the × splits into cyan and magenta ghosts that jitter on opposite X offsets while clip-path slices strobe horizontal tears across the glyph — the full RGB-split glitch, built from two pseudo-element copies and two keyframe tracks.
Published Updated
The code
<section class="ccb-16" aria-label="Glitch close button demo">
<button class="ccb-16__close" type="button" aria-label="Close">
<span class="ccb-16__x" aria-hidden="true"></span>
</button>
</section><section class="ccb-16" aria-label="Glitch close button demo">
<button class="ccb-16__close" type="button" aria-label="Close">
<span class="ccb-16__x" aria-hidden="true"></span>
</button>
</section>.ccb-16,
.ccb-16 *,
.ccb-16 *::before,
.ccb-16 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ccb-16 {
--c1: oklch(0.85 0.15 195);
--c2: oklch(0.65 0.26 345);
font-family: ui-monospace,'Cascadia Code',Menlo,monospace;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: radial-gradient(100% 110% at 50% 0%,oklch(0.22 0.03 280 / .9),transparent 60%),oklch(0.13 0.015 280);
}
.ccb-16 .ccb-16__close {
display: grid;
place-items: center;
width: 72px;
height: 72px;
border: 1px solid oklch(0.85 0.15 195 / .35);
border-radius: 12px;
background: oklch(0.17 0.02 280);
cursor: pointer;
isolation: isolate;
box-shadow: 0 0 0 1px rgba(0,0,0,.6),0 18px 40px -20px rgba(0,0,0,.9);
transition: border-color .2s ease;
}
.ccb-16 .ccb-16__x {
position: relative;
width: 26px;
height: 26px;
--bars: linear-gradient(45deg,transparent calc(50% - 1.25px),currentColor calc(50% - 1.25px) calc(50% + 1.25px),transparent calc(50% + 1.25px)),linear-gradient(-45deg,transparent calc(50% - 1.25px),currentColor calc(50% - 1.25px) calc(50% + 1.25px),transparent calc(50% + 1.25px));
background: var(--bars);
color: #fff;
}
.ccb-16 .ccb-16__x::before,
.ccb-16 .ccb-16__x::after {
content: "";
position: absolute;
inset: 0;
background: var(--bars);
mix-blend-mode: screen;
opacity: 0;
}
.ccb-16 .ccb-16__x::before {
color: var(--c1);
}
.ccb-16 .ccb-16__x::after {
color: var(--c2);
}
.ccb-16 .ccb-16__close:hover .ccb-16__x::before {
opacity: 1;
animation: ccb-16-g1 .32s steps(2,jump-none) infinite;
}
.ccb-16 .ccb-16__close:hover .ccb-16__x::after {
opacity: 1;
animation: ccb-16-g2 .44s steps(2,jump-none) infinite;
}
.ccb-16 .ccb-16__close:hover {
border-color: var(--c1);
}
@keyframes ccb-16-g1 {
0% {
transform: translateX(-3px);
clip-path: inset(0 0 62% 0);
}
23% {
transform: translateX(2px);
clip-path: inset(38% 0 21% 0);
}
41% {
transform: translateX(-2px);
clip-path: inset(71% 0 0 0);
}
67% {
transform: translateX(3px);
clip-path: inset(12% 0 55% 0);
}
100% {
transform: translateX(-1px);
clip-path: inset(45% 0 32% 0);
}
}
@keyframes ccb-16-g2 {
0% {
transform: translateX(3px);
clip-path: inset(58% 0 8% 0);
}
19% {
transform: translateX(-2px);
clip-path: inset(9% 0 70% 0);
}
47% {
transform: translateX(2px);
clip-path: inset(33% 0 40% 0);
}
73% {
transform: translateX(-3px);
clip-path: inset(80% 0 2% 0);
}
100% {
transform: translateX(1px);
clip-path: inset(21% 0 48% 0);
}
}
.ccb-16 .ccb-16__close:active {
transform: scale(.93);
}
.ccb-16 .ccb-16__close:focus-visible {
outline: 2.5px solid var(--c1);
outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
.ccb-16 .ccb-16__close:hover .ccb-16__x::before,
.ccb-16 .ccb-16__close:hover .ccb-16__x::after {
animation: none;
opacity: 0;
}
}.ccb-16,
.ccb-16 *,
.ccb-16 *::before,
.ccb-16 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ccb-16 {
--c1: oklch(0.85 0.15 195);
--c2: oklch(0.65 0.26 345);
font-family: ui-monospace,'Cascadia Code',Menlo,monospace;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: radial-gradient(100% 110% at 50% 0%,oklch(0.22 0.03 280 / .9),transparent 60%),oklch(0.13 0.015 280);
}
.ccb-16 .ccb-16__close {
display: grid;
place-items: center;
width: 72px;
height: 72px;
border: 1px solid oklch(0.85 0.15 195 / .35);
border-radius: 12px;
background: oklch(0.17 0.02 280);
cursor: pointer;
isolation: isolate;
box-shadow: 0 0 0 1px rgba(0,0,0,.6),0 18px 40px -20px rgba(0,0,0,.9);
transition: border-color .2s ease;
}
.ccb-16 .ccb-16__x {
position: relative;
width: 26px;
height: 26px;
--bars: linear-gradient(45deg,transparent calc(50% - 1.25px),currentColor calc(50% - 1.25px) calc(50% + 1.25px),transparent calc(50% + 1.25px)),linear-gradient(-45deg,transparent calc(50% - 1.25px),currentColor calc(50% - 1.25px) calc(50% + 1.25px),transparent calc(50% + 1.25px));
background: var(--bars);
color: #fff;
}
.ccb-16 .ccb-16__x::before,
.ccb-16 .ccb-16__x::after {
content: "";
position: absolute;
inset: 0;
background: var(--bars);
mix-blend-mode: screen;
opacity: 0;
}
.ccb-16 .ccb-16__x::before {
color: var(--c1);
}
.ccb-16 .ccb-16__x::after {
color: var(--c2);
}
.ccb-16 .ccb-16__close:hover .ccb-16__x::before {
opacity: 1;
animation: ccb-16-g1 .32s steps(2,jump-none) infinite;
}
.ccb-16 .ccb-16__close:hover .ccb-16__x::after {
opacity: 1;
animation: ccb-16-g2 .44s steps(2,jump-none) infinite;
}
.ccb-16 .ccb-16__close:hover {
border-color: var(--c1);
}
@keyframes ccb-16-g1 {
0% {
transform: translateX(-3px);
clip-path: inset(0 0 62% 0);
}
23% {
transform: translateX(2px);
clip-path: inset(38% 0 21% 0);
}
41% {
transform: translateX(-2px);
clip-path: inset(71% 0 0 0);
}
67% {
transform: translateX(3px);
clip-path: inset(12% 0 55% 0);
}
100% {
transform: translateX(-1px);
clip-path: inset(45% 0 32% 0);
}
}
@keyframes ccb-16-g2 {
0% {
transform: translateX(3px);
clip-path: inset(58% 0 8% 0);
}
19% {
transform: translateX(-2px);
clip-path: inset(9% 0 70% 0);
}
47% {
transform: translateX(2px);
clip-path: inset(33% 0 40% 0);
}
73% {
transform: translateX(-3px);
clip-path: inset(80% 0 2% 0);
}
100% {
transform: translateX(1px);
clip-path: inset(21% 0 48% 0);
}
}
.ccb-16 .ccb-16__close:active {
transform: scale(.93);
}
.ccb-16 .ccb-16__close:focus-visible {
outline: 2.5px solid var(--c1);
outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
.ccb-16 .ccb-16__close:hover .ccb-16__x::before,
.ccb-16 .ccb-16__close:hover .ccb-16__x::after {
animation: none;
opacity: 0;
}
}/* No JavaScript — two gradient-drawn ghost copies jitter on desynced steps() tracks; clip-path:inset() strobes the scanline tears. */
/* No JavaScript — two gradient-drawn ghost copies jitter on desynced steps() tracks; clip-path:inset() strobes the scanline tears. */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: Glitch Cross Close Button
Source: https://codefronts.com/components/css-close-buttons/glitch-cross/
A cyberpunk dismiss for dark dashboards and game UI: on hover the × splits into cyan and magenta ghosts that jitter on opposite X offsets while clip-path slices strobe horizontal tears across the glyph — the full RGB-split glitch, built from two pseudo-element copies and two keyframe tracks.
## HTML
```html
<section class="ccb-16" aria-label="Glitch close button demo">
<button class="ccb-16__close" type="button" aria-label="Close">
<span class="ccb-16__x" aria-hidden="true"></span>
</button>
</section>
```
## CSS
```css
.ccb-16,
.ccb-16 *,
.ccb-16 *::before,
.ccb-16 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ccb-16 {
--c1: oklch(0.85 0.15 195);
--c2: oklch(0.65 0.26 345);
font-family: ui-monospace,'Cascadia Code',Menlo,monospace;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: radial-gradient(100% 110% at 50% 0%,oklch(0.22 0.03 280 / .9),transparent 60%),oklch(0.13 0.015 280);
}
.ccb-16 .ccb-16__close {
display: grid;
place-items: center;
width: 72px;
height: 72px;
border: 1px solid oklch(0.85 0.15 195 / .35);
border-radius: 12px;
background: oklch(0.17 0.02 280);
cursor: pointer;
isolation: isolate;
box-shadow: 0 0 0 1px rgba(0,0,0,.6),0 18px 40px -20px rgba(0,0,0,.9);
transition: border-color .2s ease;
}
.ccb-16 .ccb-16__x {
position: relative;
width: 26px;
height: 26px;
--bars: linear-gradient(45deg,transparent calc(50% - 1.25px),currentColor calc(50% - 1.25px) calc(50% + 1.25px),transparent calc(50% + 1.25px)),linear-gradient(-45deg,transparent calc(50% - 1.25px),currentColor calc(50% - 1.25px) calc(50% + 1.25px),transparent calc(50% + 1.25px));
background: var(--bars);
color: #fff;
}
.ccb-16 .ccb-16__x::before,
.ccb-16 .ccb-16__x::after {
content: "";
position: absolute;
inset: 0;
background: var(--bars);
mix-blend-mode: screen;
opacity: 0;
}
.ccb-16 .ccb-16__x::before {
color: var(--c1);
}
.ccb-16 .ccb-16__x::after {
color: var(--c2);
}
.ccb-16 .ccb-16__close:hover .ccb-16__x::before {
opacity: 1;
animation: ccb-16-g1 .32s steps(2,jump-none) infinite;
}
.ccb-16 .ccb-16__close:hover .ccb-16__x::after {
opacity: 1;
animation: ccb-16-g2 .44s steps(2,jump-none) infinite;
}
.ccb-16 .ccb-16__close:hover {
border-color: var(--c1);
}
@keyframes ccb-16-g1 {
0% {
transform: translateX(-3px);
clip-path: inset(0 0 62% 0);
}
23% {
transform: translateX(2px);
clip-path: inset(38% 0 21% 0);
}
41% {
transform: translateX(-2px);
clip-path: inset(71% 0 0 0);
}
67% {
transform: translateX(3px);
clip-path: inset(12% 0 55% 0);
}
100% {
transform: translateX(-1px);
clip-path: inset(45% 0 32% 0);
}
}
@keyframes ccb-16-g2 {
0% {
transform: translateX(3px);
clip-path: inset(58% 0 8% 0);
}
19% {
transform: translateX(-2px);
clip-path: inset(9% 0 70% 0);
}
47% {
transform: translateX(2px);
clip-path: inset(33% 0 40% 0);
}
73% {
transform: translateX(-3px);
clip-path: inset(80% 0 2% 0);
}
100% {
transform: translateX(1px);
clip-path: inset(21% 0 48% 0);
}
}
.ccb-16 .ccb-16__close:active {
transform: scale(.93);
}
.ccb-16 .ccb-16__close:focus-visible {
outline: 2.5px solid var(--c1);
outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
.ccb-16 .ccb-16__close:hover .ccb-16__x::before,
.ccb-16 .ccb-16__close:hover .ccb-16__x::after {
animation: none;
opacity: 0;
}
}
```
## JavaScript
```js
/* No JavaScript — two gradient-drawn ghost copies jitter on desynced steps() tracks; clip-path:inset() strobes the scanline tears. */
```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: Glitch Cross Close Button
Source: https://codefronts.com/components/css-close-buttons/glitch-cross/
A cyberpunk dismiss for dark dashboards and game UI: on hover the × splits into cyan and magenta ghosts that jitter on opposite X offsets while clip-path slices strobe horizontal tears across the glyph — the full RGB-split glitch, built from two pseudo-element copies and two keyframe tracks.
## HTML
```html
<section class="ccb-16" aria-label="Glitch close button demo">
<button class="ccb-16__close" type="button" aria-label="Close">
<span class="ccb-16__x" aria-hidden="true"></span>
</button>
</section>
```
## CSS
```css
.ccb-16,
.ccb-16 *,
.ccb-16 *::before,
.ccb-16 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.ccb-16 {
--c1: oklch(0.85 0.15 195);
--c2: oklch(0.65 0.26 345);
font-family: ui-monospace,'Cascadia Code',Menlo,monospace;
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
padding: 48px 24px;
background: radial-gradient(100% 110% at 50% 0%,oklch(0.22 0.03 280 / .9),transparent 60%),oklch(0.13 0.015 280);
}
.ccb-16 .ccb-16__close {
display: grid;
place-items: center;
width: 72px;
height: 72px;
border: 1px solid oklch(0.85 0.15 195 / .35);
border-radius: 12px;
background: oklch(0.17 0.02 280);
cursor: pointer;
isolation: isolate;
box-shadow: 0 0 0 1px rgba(0,0,0,.6),0 18px 40px -20px rgba(0,0,0,.9);
transition: border-color .2s ease;
}
.ccb-16 .ccb-16__x {
position: relative;
width: 26px;
height: 26px;
--bars: linear-gradient(45deg,transparent calc(50% - 1.25px),currentColor calc(50% - 1.25px) calc(50% + 1.25px),transparent calc(50% + 1.25px)),linear-gradient(-45deg,transparent calc(50% - 1.25px),currentColor calc(50% - 1.25px) calc(50% + 1.25px),transparent calc(50% + 1.25px));
background: var(--bars);
color: #fff;
}
.ccb-16 .ccb-16__x::before,
.ccb-16 .ccb-16__x::after {
content: "";
position: absolute;
inset: 0;
background: var(--bars);
mix-blend-mode: screen;
opacity: 0;
}
.ccb-16 .ccb-16__x::before {
color: var(--c1);
}
.ccb-16 .ccb-16__x::after {
color: var(--c2);
}
.ccb-16 .ccb-16__close:hover .ccb-16__x::before {
opacity: 1;
animation: ccb-16-g1 .32s steps(2,jump-none) infinite;
}
.ccb-16 .ccb-16__close:hover .ccb-16__x::after {
opacity: 1;
animation: ccb-16-g2 .44s steps(2,jump-none) infinite;
}
.ccb-16 .ccb-16__close:hover {
border-color: var(--c1);
}
@keyframes ccb-16-g1 {
0% {
transform: translateX(-3px);
clip-path: inset(0 0 62% 0);
}
23% {
transform: translateX(2px);
clip-path: inset(38% 0 21% 0);
}
41% {
transform: translateX(-2px);
clip-path: inset(71% 0 0 0);
}
67% {
transform: translateX(3px);
clip-path: inset(12% 0 55% 0);
}
100% {
transform: translateX(-1px);
clip-path: inset(45% 0 32% 0);
}
}
@keyframes ccb-16-g2 {
0% {
transform: translateX(3px);
clip-path: inset(58% 0 8% 0);
}
19% {
transform: translateX(-2px);
clip-path: inset(9% 0 70% 0);
}
47% {
transform: translateX(2px);
clip-path: inset(33% 0 40% 0);
}
73% {
transform: translateX(-3px);
clip-path: inset(80% 0 2% 0);
}
100% {
transform: translateX(1px);
clip-path: inset(21% 0 48% 0);
}
}
.ccb-16 .ccb-16__close:active {
transform: scale(.93);
}
.ccb-16 .ccb-16__close:focus-visible {
outline: 2.5px solid var(--c1);
outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
.ccb-16 .ccb-16__close:hover .ccb-16__x::before,
.ccb-16 .ccb-16__close:hover .ccb-16__x::after {
animation: none;
opacity: 0;
}
}
```
## JavaScript
```js
/* No JavaScript — two gradient-drawn ghost copies jitter on desynced steps() tracks; clip-path:inset() strobes the scanline tears. */
```How this works
The glyph element carries the white ×; its ::before and ::after are full-size copies drawn with the same CSS gradients, one tinted cyan and one magenta, stacked underneath with mix-blend-mode:screen. On hover each copy runs its own steps-y keyframe: opposite translateX jitters plus a strobing clip-path:inset() that shows different horizontal slivers each frame — the classic scanline tear.
Randomness is faked with prime-numbered percentage stops (7%, 23%, 41%…) so the two tracks never sync visibly. The × itself is drawn with two hard-stop linear-gradient backgrounds instead of pseudo-elements — this demo's pseudos are budgeted for the ghosts, a useful trick when you run out of ::before/::after.
Make it yours
- Swap ghost hues via
--c1/--c2(cyan/magenta is CRT canon; red/blue reads anaglyph). - Increase jitter amplitude (±3px → ±6px) for violent glitches.
- Run the animation continuously (not just hover) for an "unstable system" alert close.
- Add a third steps() track on the parent's opacity for flicker.
Gotchas — read before shipping
- Both ghost tracks must use different durations (here .32s/.44s) — equal durations sync into a boring wobble.
- mix-blend-mode:screen needs a dark backdrop; on white the ghosts vanish (isolation:isolate keeps the blend scoped).
- Keep the resting state perfectly clean — glitch effects lose all impact if the idle glyph already shimmers.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 113+ | 111+ |
clip-path:inset() + mix-blend-mode — both universal since 2020.