Cessna 172 · flaps 10°Descent −500 ft/min
Beveled Control Panel
Three 130 × 80 px instrument panels with 12 px cut corners — a clip-path: polygon() in pixels, so the same 45° bevel whatever the size —, cyan and pink neon monospace figures, a veil and glow on hover: the console look, in plain CSS.
Updated
This effect is free — the Glassmorphism category contains 47 effects total, including 6 free. Effect.Labs has 840 vanilla effects. Explore the category →
Usage examples
Tank 3 — Autumn amber
Fermentation day 6 of 10 · last reading 2:10 pm
PIXEL BAZARRETRO GAMES · BUY · SELL · TRADE
Shelf C · consoles 1988-1996All tested in store
How it works
Each .bevel-panel (130 × 80 px, 145° gradient from #1a1a3e to #0f0f2a) is cut by clip-path: var(--bvp-bevel), an eight-point polygon() written with calc(): 0 12px, 12px 0, calc(100% - 12px) 0, 100% 12px…. The cut always measures 12 px on each axis, at 45°, on a 130 × 80 panel as on a 150 × 96 px one (measured in the scenes) — a percentage shape would give a flattened bevel on a wide panel. The four corners remove 2.8% of the area; measured in Chromium 151, Firefox 153 and WebKit 26, the point 2 px from the corner does not get the click.
The text is 'Courier New', monospace, uppercase with 1 px letter spacing: the value .bp-val at 22.4 px, the label .bp-label at 8.8 px and 70% opacity. The first and third panels are cyan #00ffcc, the second pink #ff6b9d (:nth-child(2)). On hover, over 0.3 s: the text brightens and gains a glow (text-shadow: 0 0 8px of the same hue at 80%), and a ::before veil, cut by the same variable, goes from opacity 0 to 1 with a gradient from the color at 15% to transparent. No JavaScript.
The bevel is a CSS variable set on the panel, --bvp-bevel, not an SVG <clipPath>: with no SVG and no id, several copies pasted into one page cannot conflict, and the shape depends on no outside element (a url(#bevel) with no SVG on the page would leave rectangles, see Squircle Cards). Its points are in pixels (calc(100% - 12px)): the cut corners keep 12 px whatever the panel's size.
Accessibility
- Contrast: the cyan value
#00ffccon#1a1a3emeasures 12.8:1, the pink#ff6b9d6.2:1 — comfortable. The label, at 70% opacity, drops to 6.8:1 in cyan but to 3.7:1 in pink, under the 4.5:1 threshold, and it is only 8.8 px: raise.bp-labelto0.65remandopacity: .85at least. - Color alone: the pink panel does not say why it is pink. If the color signals an alert (threshold exceeded), say it in the label or an
aria-labeltoo (“Core temperature: 42 °C, high”). - Keyboard:
divs withcursor: pointer, no role and notabindex— Tab never stops on them (measured), the glow only exists with a mouse. For display panels, removecursor: pointer; for clickable panels, use<button>s and repeat the glow on:focus-visible(the default focus ring is clipped byclip-path). Noprefers-reduced-motion: only a 0.3 s color transition, no movement.
Browser compatibility
CSS only: clip-path: polygon() with calc(), the --bvp-bevel custom property, gradients, text-shadow, a ::before pseudo-element. Zero JavaScript, zero SVG. Measured pasted into a blank page: identical bevel in Chromium 151, Firefox 153 and WebKit 26.
Without clip-path (Firefox before 54, Safari before 13.1 without prefix), the panels stay rectangular and readable. Add -webkit-clip-path: var(--bvp-bevel) on .bevel-panel and its ::before for Safari 9 to 13.
The code
Copy the three blocks into your page. No dependencies.
<div class="bevel-panel-wrap">
<div class="bevel-panel">
<span class="bp-val">87%</span>
<span class="bp-label">CPU Load</span>
</div>
<div class="bevel-panel">
<span class="bp-val">42°C</span>
<span class="bp-label">Core Temp</span>
</div>
<div class="bevel-panel">
<span class="bp-val">3.2G</span>
<span class="bp-label">Memory</span>
</div>
</div>
/* Formes en clip-path: polygon(), sans SVG ni id : Pans coupés de 12 px à 45°, quelle que soit la taille du panneau. */
.bevel-panel {
--bvp-bevel: polygon(0 12px, 12px 0, calc(100% - 12px) 0, 100% 12px, 100% calc(100% - 12px), calc(100% - 12px) 100%, 12px 100%, 0 calc(100% - 12px));
}
.bevel-panel-wrap {
display: flex;
gap: 12px;
align-items: center;
justify-content: center;
flex-wrap: wrap;
padding: 10px;
}
.bevel-panel {
clip-path: var(--bvp-bevel);
background: linear-gradient(145deg, #1a1a3e, #0f0f2a);
border: none;
color: #00ffcc;
width: 130px;
height: 80px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-family: 'Courier New', monospace;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 1px;
text-transform: uppercase;
cursor: pointer;
position: relative;
transition: all 0.3s ease;
}
.bevel-panel::before {
content: '';
position: absolute;
inset: 0;
clip-path: var(--bvp-bevel);
background: linear-gradient(145deg, rgba(0, 255, 204, 0.15), transparent);
opacity: 0;
transition: opacity 0.3s ease;
}
.bevel-panel:hover::before {
opacity: 1;
}
.bevel-panel:hover {
color: #00ffee;
text-shadow: 0 0 8px rgba(0, 255, 204, 0.8);
}
.bevel-panel .bp-val {
font-size: 1.4rem;
margin-bottom: 2px;
}
.bevel-panel .bp-label {
opacity: 0.7;
font-size: 0.55rem;
}
.bevel-panel:nth-child(2) {
color: #ff6b9d;
}
.bevel-panel:nth-child(2):hover {
color: #ff85b1;
text-shadow: 0 0 8px rgba(255, 107, 157, 0.8);
}
.bevel-panel:nth-child(2)::before {
background: linear-gradient(145deg, rgba(255, 107, 157, 0.15), transparent);
}
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Bevel size (CSS — --bvp-bevel on .bevel-panel) |
12 px at each corner | Replace the eight 12px in the polygon(): 8 px for a badge, 20 px for a large screen. To cut only two opposite corners (top left and bottom right): polygon(0 12px, 12px 0, 100% 0, 100% calc(100% - 12px), calc(100% - 12px) 100%, 0 100%). |
Colors (CSS — color of .bevel-panel and :nth-child(2)) |
cyan #00ffcc, pink #ff6b9d on the second |
The glow and the veil repeat the hue as hard-coded values (rgba(0,255,204,…)): change them with the color. An amber #fbbf24 gives an alert screen. |
Size (CSS — width / height of .bevel-panel) |
130 × 80 px | The bevel stays at 12 px. Enlarge .bp-val with the panel: 25 px for 150 × 92. |
Hover glow (CSS — .bevel-panel:hover) |
text-shadow: 0 0 8px at 80%, 15% veil, 0.3 s |
0 0 14px for a stronger neon; add the same block on :focus-visible if the panels become buttons. |
FAQ
Why is the bevel in pixels rather than percentages?
Because the panel is not square. In percentages, 10% of a 130 × 80 panel would give a cut of 13 px horizontally and 8 px vertically: a flattened bevel, no longer at 45°. With calc(100% - 12px), each corner loses 12 px on each axis whatever the size — measured identical on the 130 × 80 and 152 × 96 px panels of this page.
How do I flag a value that crosses a threshold?
In the code, the pink panel is picked by its position (.bevel-panel:nth-child(2), in three rules: color, hover, glow), not by its state. For a real threshold, replace :nth-child(2) with a state class, for example .bevel-panel--alert, in those three rules, and set it from JavaScript when the value crosses the limit (panel.classList.toggle('bevel-panel--alert', value > 40)). Color is not enough: say it in words too, in the label or an aria-label (“Core temperature: 42 °C, high”), and in an aria-live="polite" region if the alert should be announced as it happens.
What about the corner-shape: bevel property?
corner-shape (with border-radius) describes exactly this bevel and keeps borders and shadows on the shape, which clip-path does not. But it only exists in recent Chrome and Edge — measured: CSS.supports('corner-shape', 'bevel') is true in Chromium 151, false in Firefox 153 and WebKit 26 — and the latter two would show rounded corners. clip-path: polygon() has worked everywhere since 2020: it is the sold code's choice.