34 CSS Floating Buttons34 / 34
Modern Squircle Rounded Square FAB CSS
The rounded-square FAB that replaced the circle in most 2025-onward interfaces, with the one rule that makes it work: radius is a constant fraction of size, not a fixed pixel value. 0.29 is the sweet spot — the same ratio app icons use. Includes a live comparison of five ratios and a hover that morphs radius rather than colour.
Published Updated
The code
<section class="fb-34" aria-label="Modern squircle rounded square floating action button demo">
<div class="fb-34__stage">
<p class="fb-34__eyebrow">radius = size × ratio</p>
<h2 class="fb-34__title">One ratio, every size</h2>
<p class="fb-34__sub">Fixed pixel radii drift as buttons scale. Anchor the radius to a fraction of the size and a 40px control and a 96px hero read as the same shape.</p>
<div class="fb-34__ladder">
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.5" type="button" aria-label="Ratio 0.5"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.50<i>circle</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab fb-34__fab--hero" style="--fb-34-ratio:.29" type="button" aria-label="Ratio 0.29, recommended"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.29<i>squircle</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.22" type="button" aria-label="Ratio 0.22"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.22<i>card</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.12" type="button" aria-label="Ratio 0.12"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.12<i>chip</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:0" type="button" aria-label="Ratio zero"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.00<i>square</i></span></div>
</div>
<div class="fb-34__scale">
<button class="fb-34__fab" style="--fb-34-size:40px" type="button" aria-label="40 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:52px" type="button" aria-label="52 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:64px" type="button" aria-label="64 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:80px" type="button" aria-label="80 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.3" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:96px" type="button" aria-label="96 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
</div>
<p class="fb-34__caption">same 0.29 ratio · 40 → 96px · identical silhouette</p>
<p class="fb-34__chip">hover morphs the ratio toward 0.5 in 280ms</p>
</div>
</section><section class="fb-34" aria-label="Modern squircle rounded square floating action button demo">
<div class="fb-34__stage">
<p class="fb-34__eyebrow">radius = size × ratio</p>
<h2 class="fb-34__title">One ratio, every size</h2>
<p class="fb-34__sub">Fixed pixel radii drift as buttons scale. Anchor the radius to a fraction of the size and a 40px control and a 96px hero read as the same shape.</p>
<div class="fb-34__ladder">
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.5" type="button" aria-label="Ratio 0.5"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.50<i>circle</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab fb-34__fab--hero" style="--fb-34-ratio:.29" type="button" aria-label="Ratio 0.29, recommended"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.29<i>squircle</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.22" type="button" aria-label="Ratio 0.22"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.22<i>card</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.12" type="button" aria-label="Ratio 0.12"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.12<i>chip</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:0" type="button" aria-label="Ratio zero"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.00<i>square</i></span></div>
</div>
<div class="fb-34__scale">
<button class="fb-34__fab" style="--fb-34-size:40px" type="button" aria-label="40 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:52px" type="button" aria-label="52 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:64px" type="button" aria-label="64 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:80px" type="button" aria-label="80 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.3" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:96px" type="button" aria-label="96 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
</div>
<p class="fb-34__caption">same 0.29 ratio · 40 → 96px · identical silhouette</p>
<p class="fb-34__chip">hover morphs the ratio toward 0.5 in 280ms</p>
</div>
</section>.fb-34 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--fb-34-bg);
--fb-34-bg: oklch(0.96 0.012 210);
--fb-34-brand: oklch(0.52 0.13 215);
--fb-34-brandDeep: oklch(0.38 0.11 218);
--fb-34-ink: oklch(0.22 0.025 215);
--fb-34-mut: oklch(0.53 0.015 215);
--fb-34-size: 64px;
--fb-34-ratio: .29;
font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
color: var(--fb-34-ink);
display: grid;
place-items: center;
padding: clamp(20px,5vw,56px);
}
.fb-34 *,
.fb-34 *::before,
.fb-34 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fb-34__stage {
width: min(100%,62ch);
display: grid;
gap: clamp(16px,3vw,26px);
justify-items: center;
text-align: center;
}
.fb-34__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--fb-34-brand);
}
.fb-34__title {
font-size: clamp(26px,4.6vw,44px);
line-height: 1.05;
letter-spacing: -.03em;
font-weight: 700;
text-wrap: balance;
}
.fb-34__sub {
max-width: 52ch;
font-size: clamp(13.5px,1.7vw,16.5px);
line-height: 1.62;
color: var(--fb-34-mut);
text-wrap: pretty;
}
.fb-34__ladder {
display: flex;
flex-wrap: wrap;
gap: clamp(14px,4vw,30px);
justify-content: center;
align-items: flex-start;
padding: 6px 0;
}
.fb-34__cell {
display: grid;
gap: 10px;
justify-items: center;
}
.fb-34__cap {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 12px;
font-weight: 650;
display: grid;
gap: 2px;
}
.fb-34__cap i {
font-style: normal;
font-size: 10px;
font-weight: 400;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--fb-34-mut);
}
.fb-34__fab {
display: grid;
place-items: center;
inline-size: var(--fb-34-size);
block-size: var(--fb-34-size);
border: 0;
border-radius: calc(var(--fb-34-size) * var(--fb-34-ratio));
cursor: pointer;
color: oklch(0.99 0.01 215);
background: linear-gradient(155deg,oklch(0.62 0.13 205),var(--fb-34-brandDeep));
box-shadow: 0 12px 28px -12px oklch(0.38 0.11 218/.85),0 2px 5px oklch(0.28 0.05 218/.25);
transition: border-radius .28s cubic-bezier(.2,.9,.3,1),transform .28s cubic-bezier(.2,1.25,.4,1),box-shadow .28s ease;
}
.fb-34__fab svg {
width: calc(var(--fb-34-size) * .38);
height: calc(var(--fb-34-size) * .38);
}
.fb-34__fab:hover {
--fb-34-ratio: .5;
transform: translateY(-3px);
box-shadow: 0 18px 38px -12px oklch(0.38 0.11 218/.9);
}
.fb-34__fab:active {
transform: scale(.95);
--fb-34-ratio: .24;
}
.fb-34__fab:focus-visible {
outline: 3px solid var(--fb-34-brandDeep);
outline-offset: 4px;
}
.fb-34__fab--hero {
background: linear-gradient(155deg,oklch(0.74 0.16 155),oklch(0.5 0.14 168));
box-shadow: 0 14px 32px -12px oklch(0.5 0.14 168/.85),0 2px 5px oklch(0.28 0.05 168/.25);
color: oklch(0.16 0.04 168);
}
.fb-34__fab--hero:hover {
box-shadow: 0 20px 42px -12px oklch(0.5 0.14 168/.9);
}
@supports (corner-shape: squircle) {
.fb-34__fab {
corner-shape: squircle;
}
.fb-34__fab[style*=".5"] {
corner-shape: round;
}
}
.fb-34__scale {
display: flex;
flex-wrap: wrap;
gap: clamp(12px,3vw,22px);
justify-content: center;
align-items: center;
padding: 10px 16px;
border-radius: 24px;
background: oklch(1 0 0/.7);
border: 1px solid oklch(0.22 0.025 215/.08);
}
.fb-34__caption {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
color: var(--fb-34-mut);
}
.fb-34__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
color: var(--fb-34-mut);
padding: 8px 14px;
border: 1px solid oklch(0.22 0.025 215/.14);
border-radius: 99px;
}
@media (prefers-reduced-motion: reduce) {
.fb-34__fab {
transition: none;
}
}.fb-34 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--fb-34-bg);
--fb-34-bg: oklch(0.96 0.012 210);
--fb-34-brand: oklch(0.52 0.13 215);
--fb-34-brandDeep: oklch(0.38 0.11 218);
--fb-34-ink: oklch(0.22 0.025 215);
--fb-34-mut: oklch(0.53 0.015 215);
--fb-34-size: 64px;
--fb-34-ratio: .29;
font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
color: var(--fb-34-ink);
display: grid;
place-items: center;
padding: clamp(20px,5vw,56px);
}
.fb-34 *,
.fb-34 *::before,
.fb-34 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fb-34__stage {
width: min(100%,62ch);
display: grid;
gap: clamp(16px,3vw,26px);
justify-items: center;
text-align: center;
}
.fb-34__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--fb-34-brand);
}
.fb-34__title {
font-size: clamp(26px,4.6vw,44px);
line-height: 1.05;
letter-spacing: -.03em;
font-weight: 700;
text-wrap: balance;
}
.fb-34__sub {
max-width: 52ch;
font-size: clamp(13.5px,1.7vw,16.5px);
line-height: 1.62;
color: var(--fb-34-mut);
text-wrap: pretty;
}
.fb-34__ladder {
display: flex;
flex-wrap: wrap;
gap: clamp(14px,4vw,30px);
justify-content: center;
align-items: flex-start;
padding: 6px 0;
}
.fb-34__cell {
display: grid;
gap: 10px;
justify-items: center;
}
.fb-34__cap {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 12px;
font-weight: 650;
display: grid;
gap: 2px;
}
.fb-34__cap i {
font-style: normal;
font-size: 10px;
font-weight: 400;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--fb-34-mut);
}
.fb-34__fab {
display: grid;
place-items: center;
inline-size: var(--fb-34-size);
block-size: var(--fb-34-size);
border: 0;
border-radius: calc(var(--fb-34-size) * var(--fb-34-ratio));
cursor: pointer;
color: oklch(0.99 0.01 215);
background: linear-gradient(155deg,oklch(0.62 0.13 205),var(--fb-34-brandDeep));
box-shadow: 0 12px 28px -12px oklch(0.38 0.11 218/.85),0 2px 5px oklch(0.28 0.05 218/.25);
transition: border-radius .28s cubic-bezier(.2,.9,.3,1),transform .28s cubic-bezier(.2,1.25,.4,1),box-shadow .28s ease;
}
.fb-34__fab svg {
width: calc(var(--fb-34-size) * .38);
height: calc(var(--fb-34-size) * .38);
}
.fb-34__fab:hover {
--fb-34-ratio: .5;
transform: translateY(-3px);
box-shadow: 0 18px 38px -12px oklch(0.38 0.11 218/.9);
}
.fb-34__fab:active {
transform: scale(.95);
--fb-34-ratio: .24;
}
.fb-34__fab:focus-visible {
outline: 3px solid var(--fb-34-brandDeep);
outline-offset: 4px;
}
.fb-34__fab--hero {
background: linear-gradient(155deg,oklch(0.74 0.16 155),oklch(0.5 0.14 168));
box-shadow: 0 14px 32px -12px oklch(0.5 0.14 168/.85),0 2px 5px oklch(0.28 0.05 168/.25);
color: oklch(0.16 0.04 168);
}
.fb-34__fab--hero:hover {
box-shadow: 0 20px 42px -12px oklch(0.5 0.14 168/.9);
}
@supports (corner-shape: squircle) {
.fb-34__fab {
corner-shape: squircle;
}
.fb-34__fab[style*=".5"] {
corner-shape: round;
}
}
.fb-34__scale {
display: flex;
flex-wrap: wrap;
gap: clamp(12px,3vw,22px);
justify-content: center;
align-items: center;
padding: 10px 16px;
border-radius: 24px;
background: oklch(1 0 0/.7);
border: 1px solid oklch(0.22 0.025 215/.08);
}
.fb-34__caption {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
color: var(--fb-34-mut);
}
.fb-34__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
color: var(--fb-34-mut);
padding: 8px 14px;
border: 1px solid oklch(0.22 0.025 215/.14);
border-radius: 99px;
}
@media (prefers-reduced-motion: reduce) {
.fb-34__fab {
transition: none;
}
}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: Modern Squircle Rounded Square FAB CSS
Source: https://codefronts.com/components/css-floating-buttons/fb16/
The rounded-square FAB that replaced the circle in most 2025-onward interfaces, with the one rule that makes it work: radius is a constant fraction of size, not a fixed pixel value. 0.29 is the sweet spot — the same ratio app icons use. Includes a live comparison of five ratios and a hover that morphs radius rather than colour.
## HTML
```html
<section class="fb-34" aria-label="Modern squircle rounded square floating action button demo">
<div class="fb-34__stage">
<p class="fb-34__eyebrow">radius = size × ratio</p>
<h2 class="fb-34__title">One ratio, every size</h2>
<p class="fb-34__sub">Fixed pixel radii drift as buttons scale. Anchor the radius to a fraction of the size and a 40px control and a 96px hero read as the same shape.</p>
<div class="fb-34__ladder">
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.5" type="button" aria-label="Ratio 0.5"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.50<i>circle</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab fb-34__fab--hero" style="--fb-34-ratio:.29" type="button" aria-label="Ratio 0.29, recommended"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.29<i>squircle</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.22" type="button" aria-label="Ratio 0.22"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.22<i>card</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.12" type="button" aria-label="Ratio 0.12"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.12<i>chip</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:0" type="button" aria-label="Ratio zero"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.00<i>square</i></span></div>
</div>
<div class="fb-34__scale">
<button class="fb-34__fab" style="--fb-34-size:40px" type="button" aria-label="40 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:52px" type="button" aria-label="52 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:64px" type="button" aria-label="64 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:80px" type="button" aria-label="80 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.3" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:96px" type="button" aria-label="96 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
</div>
<p class="fb-34__caption">same 0.29 ratio · 40 → 96px · identical silhouette</p>
<p class="fb-34__chip">hover morphs the ratio toward 0.5 in 280ms</p>
</div>
</section>
```
## CSS
```css
.fb-34 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--fb-34-bg);
--fb-34-bg: oklch(0.96 0.012 210);
--fb-34-brand: oklch(0.52 0.13 215);
--fb-34-brandDeep: oklch(0.38 0.11 218);
--fb-34-ink: oklch(0.22 0.025 215);
--fb-34-mut: oklch(0.53 0.015 215);
--fb-34-size: 64px;
--fb-34-ratio: .29;
font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
color: var(--fb-34-ink);
display: grid;
place-items: center;
padding: clamp(20px,5vw,56px);
}
.fb-34 *,
.fb-34 *::before,
.fb-34 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fb-34__stage {
width: min(100%,62ch);
display: grid;
gap: clamp(16px,3vw,26px);
justify-items: center;
text-align: center;
}
.fb-34__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--fb-34-brand);
}
.fb-34__title {
font-size: clamp(26px,4.6vw,44px);
line-height: 1.05;
letter-spacing: -.03em;
font-weight: 700;
text-wrap: balance;
}
.fb-34__sub {
max-width: 52ch;
font-size: clamp(13.5px,1.7vw,16.5px);
line-height: 1.62;
color: var(--fb-34-mut);
text-wrap: pretty;
}
.fb-34__ladder {
display: flex;
flex-wrap: wrap;
gap: clamp(14px,4vw,30px);
justify-content: center;
align-items: flex-start;
padding: 6px 0;
}
.fb-34__cell {
display: grid;
gap: 10px;
justify-items: center;
}
.fb-34__cap {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 12px;
font-weight: 650;
display: grid;
gap: 2px;
}
.fb-34__cap i {
font-style: normal;
font-size: 10px;
font-weight: 400;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--fb-34-mut);
}
.fb-34__fab {
display: grid;
place-items: center;
inline-size: var(--fb-34-size);
block-size: var(--fb-34-size);
border: 0;
border-radius: calc(var(--fb-34-size) * var(--fb-34-ratio));
cursor: pointer;
color: oklch(0.99 0.01 215);
background: linear-gradient(155deg,oklch(0.62 0.13 205),var(--fb-34-brandDeep));
box-shadow: 0 12px 28px -12px oklch(0.38 0.11 218/.85),0 2px 5px oklch(0.28 0.05 218/.25);
transition: border-radius .28s cubic-bezier(.2,.9,.3,1),transform .28s cubic-bezier(.2,1.25,.4,1),box-shadow .28s ease;
}
.fb-34__fab svg {
width: calc(var(--fb-34-size) * .38);
height: calc(var(--fb-34-size) * .38);
}
.fb-34__fab:hover {
--fb-34-ratio: .5;
transform: translateY(-3px);
box-shadow: 0 18px 38px -12px oklch(0.38 0.11 218/.9);
}
.fb-34__fab:active {
transform: scale(.95);
--fb-34-ratio: .24;
}
.fb-34__fab:focus-visible {
outline: 3px solid var(--fb-34-brandDeep);
outline-offset: 4px;
}
.fb-34__fab--hero {
background: linear-gradient(155deg,oklch(0.74 0.16 155),oklch(0.5 0.14 168));
box-shadow: 0 14px 32px -12px oklch(0.5 0.14 168/.85),0 2px 5px oklch(0.28 0.05 168/.25);
color: oklch(0.16 0.04 168);
}
.fb-34__fab--hero:hover {
box-shadow: 0 20px 42px -12px oklch(0.5 0.14 168/.9);
}
@supports (corner-shape: squircle) {
.fb-34__fab {
corner-shape: squircle;
}
.fb-34__fab[style*=".5"] {
corner-shape: round;
}
}
.fb-34__scale {
display: flex;
flex-wrap: wrap;
gap: clamp(12px,3vw,22px);
justify-content: center;
align-items: center;
padding: 10px 16px;
border-radius: 24px;
background: oklch(1 0 0/.7);
border: 1px solid oklch(0.22 0.025 215/.08);
}
.fb-34__caption {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
color: var(--fb-34-mut);
}
.fb-34__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
color: var(--fb-34-mut);
padding: 8px 14px;
border: 1px solid oklch(0.22 0.025 215/.14);
border-radius: 99px;
}
@media (prefers-reduced-motion: reduce) {
.fb-34__fab {
transition: none;
}
}
```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: Modern Squircle Rounded Square FAB CSS
Source: https://codefronts.com/components/css-floating-buttons/fb16/
The rounded-square FAB that replaced the circle in most 2025-onward interfaces, with the one rule that makes it work: radius is a constant fraction of size, not a fixed pixel value. 0.29 is the sweet spot — the same ratio app icons use. Includes a live comparison of five ratios and a hover that morphs radius rather than colour.
## HTML
```html
<section class="fb-34" aria-label="Modern squircle rounded square floating action button demo">
<div class="fb-34__stage">
<p class="fb-34__eyebrow">radius = size × ratio</p>
<h2 class="fb-34__title">One ratio, every size</h2>
<p class="fb-34__sub">Fixed pixel radii drift as buttons scale. Anchor the radius to a fraction of the size and a 40px control and a 96px hero read as the same shape.</p>
<div class="fb-34__ladder">
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.5" type="button" aria-label="Ratio 0.5"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.50<i>circle</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab fb-34__fab--hero" style="--fb-34-ratio:.29" type="button" aria-label="Ratio 0.29, recommended"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.29<i>squircle</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.22" type="button" aria-label="Ratio 0.22"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.22<i>card</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:.12" type="button" aria-label="Ratio 0.12"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.12<i>chip</i></span></div>
<div class="fb-34__cell"><button class="fb-34__fab" style="--fb-34-ratio:0" type="button" aria-label="Ratio zero"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button><span class="fb-34__cap">.00<i>square</i></span></div>
</div>
<div class="fb-34__scale">
<button class="fb-34__fab" style="--fb-34-size:40px" type="button" aria-label="40 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.6" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:52px" type="button" aria-label="52 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:64px" type="button" aria-label="64 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.4" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:80px" type="button" aria-label="80 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.3" stroke-linecap="round"/></svg></button>
<button class="fb-34__fab" style="--fb-34-size:96px" type="button" aria-label="96 pixel"><svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/></svg></button>
</div>
<p class="fb-34__caption">same 0.29 ratio · 40 → 96px · identical silhouette</p>
<p class="fb-34__chip">hover morphs the ratio toward 0.5 in 280ms</p>
</div>
</section>
```
## CSS
```css
.fb-34 {
width: 100%;
min-height: 100vh;
min-height: 100svh;
display: block;
background: var(--fb-34-bg);
--fb-34-bg: oklch(0.96 0.012 210);
--fb-34-brand: oklch(0.52 0.13 215);
--fb-34-brandDeep: oklch(0.38 0.11 218);
--fb-34-ink: oklch(0.22 0.025 215);
--fb-34-mut: oklch(0.53 0.015 215);
--fb-34-size: 64px;
--fb-34-ratio: .29;
font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
color: var(--fb-34-ink);
display: grid;
place-items: center;
padding: clamp(20px,5vw,56px);
}
.fb-34 *,
.fb-34 *::before,
.fb-34 *::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.fb-34__stage {
width: min(100%,62ch);
display: grid;
gap: clamp(16px,3vw,26px);
justify-items: center;
text-align: center;
}
.fb-34__eyebrow {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11.5px;
letter-spacing: .16em;
text-transform: uppercase;
color: var(--fb-34-brand);
}
.fb-34__title {
font-size: clamp(26px,4.6vw,44px);
line-height: 1.05;
letter-spacing: -.03em;
font-weight: 700;
text-wrap: balance;
}
.fb-34__sub {
max-width: 52ch;
font-size: clamp(13.5px,1.7vw,16.5px);
line-height: 1.62;
color: var(--fb-34-mut);
text-wrap: pretty;
}
.fb-34__ladder {
display: flex;
flex-wrap: wrap;
gap: clamp(14px,4vw,30px);
justify-content: center;
align-items: flex-start;
padding: 6px 0;
}
.fb-34__cell {
display: grid;
gap: 10px;
justify-items: center;
}
.fb-34__cap {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 12px;
font-weight: 650;
display: grid;
gap: 2px;
}
.fb-34__cap i {
font-style: normal;
font-size: 10px;
font-weight: 400;
letter-spacing: .06em;
text-transform: uppercase;
color: var(--fb-34-mut);
}
.fb-34__fab {
display: grid;
place-items: center;
inline-size: var(--fb-34-size);
block-size: var(--fb-34-size);
border: 0;
border-radius: calc(var(--fb-34-size) * var(--fb-34-ratio));
cursor: pointer;
color: oklch(0.99 0.01 215);
background: linear-gradient(155deg,oklch(0.62 0.13 205),var(--fb-34-brandDeep));
box-shadow: 0 12px 28px -12px oklch(0.38 0.11 218/.85),0 2px 5px oklch(0.28 0.05 218/.25);
transition: border-radius .28s cubic-bezier(.2,.9,.3,1),transform .28s cubic-bezier(.2,1.25,.4,1),box-shadow .28s ease;
}
.fb-34__fab svg {
width: calc(var(--fb-34-size) * .38);
height: calc(var(--fb-34-size) * .38);
}
.fb-34__fab:hover {
--fb-34-ratio: .5;
transform: translateY(-3px);
box-shadow: 0 18px 38px -12px oklch(0.38 0.11 218/.9);
}
.fb-34__fab:active {
transform: scale(.95);
--fb-34-ratio: .24;
}
.fb-34__fab:focus-visible {
outline: 3px solid var(--fb-34-brandDeep);
outline-offset: 4px;
}
.fb-34__fab--hero {
background: linear-gradient(155deg,oklch(0.74 0.16 155),oklch(0.5 0.14 168));
box-shadow: 0 14px 32px -12px oklch(0.5 0.14 168/.85),0 2px 5px oklch(0.28 0.05 168/.25);
color: oklch(0.16 0.04 168);
}
.fb-34__fab--hero:hover {
box-shadow: 0 20px 42px -12px oklch(0.5 0.14 168/.9);
}
@supports (corner-shape: squircle) {
.fb-34__fab {
corner-shape: squircle;
}
.fb-34__fab[style*=".5"] {
corner-shape: round;
}
}
.fb-34__scale {
display: flex;
flex-wrap: wrap;
gap: clamp(12px,3vw,22px);
justify-content: center;
align-items: center;
padding: 10px 16px;
border-radius: 24px;
background: oklch(1 0 0/.7);
border: 1px solid oklch(0.22 0.025 215/.08);
}
.fb-34__caption {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
color: var(--fb-34-mut);
}
.fb-34__chip {
font-family: ui-monospace,Menlo,Consolas,monospace;
font-size: 11px;
color: var(--fb-34-mut);
padding: 8px 14px;
border: 1px solid oklch(0.22 0.025 215/.14);
border-radius: 99px;
}
@media (prefers-reduced-motion: reduce) {
.fb-34__fab {
transition: none;
}
}
```How this works
The whole system is one ratio token:
.fab{ --size:64px; --ratio:.29;
inline-size:var(--size); block-size:var(--size);
border-radius:calc(var(--size) * var(--ratio)); }Fixed pixel radii break at scale: 16px on a 40px button is a soft square, on a 96px button it is nearly sharp. Anchoring to a ratio keeps the silhouette identical at every size, which is what lets a 40px toolbar button and a 96px hero FAB read as the same component.
The ratios worth knowing: 0.5 is a circle, 0.29 is the app-icon squircle, 0.22 reads as a card, 0.12 as a chip, 0 as brutalist. Below about 0.1 the corner stops doing any work.
Because the radius is a calc from a custom property, it interpolates — hovering morphs from squircle toward circle in 280ms, and the transition is smooth rather than stepped. Pair it with corner-shape:squircle where supported for a truly continuous curve.
Make it yours
- Design-system token: expose the ratio as a global (--radius-ratio) and every rounded element in the product stays in family.
- Directional radius: a larger radius on the corner nearest the screen edge makes a docked button feel attached to it.
- Press morph: shrink the ratio slightly on :active so the button squares up as it is pressed — subtle, physical.
- Nested radius: an inner element's radius should be the parent's minus the padding, or the curves will not sit concentric.
Gotchas — read before shipping
- Never mix fixed and ratio radii in one component set; the mismatch is subtle at one size and obvious across three.
- border-radius percentages behave differently from calc ratios — 29% of a non-square box gives an ellipse, not a squircle.
- Nested rounded elements need computed inner radii. An inner radius equal to the outer one looks visibly wrong at the corners.
- At very small sizes, ratio radii round down to sub-pixel values and the corners look inconsistent between browsers. Below 32px, set a floor.
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+.
calc() with custom properties in border-radius works everywhere modern. The optional corner-shape:squircle enhancement is Chrome 139+ and Safari 26+, wrapped in @supports.