34 CSS Floating Buttons34 / 34

Pure CSSMIT licensed

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

Live Demo
Try it

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>
.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;
  }
}
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 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

ChromeSafariFirefoxEdge
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.

Search CodeFronts

Loading…