34 CSS Floating Buttons
26 / 34

All 34 in 34 CSS Floating Buttons

  1. 01Material Design 3 Floating Action Button (FAB)
  2. 02iOS-Style Compose Floating Button
  3. 03WhatsApp Floating Message Button CSS
  4. 04Intercom / Drift Chat Bubble Floating Button
  5. 05Accessible WAI-ARIA Floating Action Button (WCAG 2.2)
  6. 06Extended FAB with Icon and Label (Material Design 3)
  7. 07Speed Dial Radial Menu FAB with Backdrop
  8. 08Pure CSS FAB Speed Dial (No JavaScript)
  9. 09Material Gradient Floating Action Button CSS
  10. 10Vertical and Horizontal Speed Dial FAB Menu CSS
  11. 11Morphing FAB Button That Expands to Pill CSS
  12. 12Scroll-to-Top Floating Button with SVG Progress Ring
  13. 13Floating Chat Widget FAB with Notification Panel
  14. 14Fan and Arc Radial Spread FAB Menu CSS
  15. 15Apple Squircle Superellipse Floating Button CSS
  16. 16Social Share Floating Button Cluster CSS
  17. 17Glassmorphism Floating Action Button with Backdrop Blur
  18. 18Cyberpunk Neon Glow Floating Button CSS
  19. 19Floating Compose Button with Tooltip on Hover CSS
  20. 20Draggable Floating Action Button with Corner Snap CSS
  21. 21Notification Bell Floating Button with Badge Counter
  22. 22Floating Cart Button with Live Badge Counter CSS
  23. 23Magnetic Cursor Follower Floating Button CSS
  24. 24Dark Mode Theme Toggle Floating Button CSS
  25. 25Classic Gradient Circle Plus FAB CSS
  26. 26Pulse Ring Attention-Getter Floating Button CSS
  27. 27Pill-Shaped FAB with Icon and Text Label CSS
  28. 28Neo-Brutalist Hard Shadow Floating Button CSS
  29. 29Floating Button with Loading Spinner State CSS
  30. 30Draggable Floating Button with 6-Dot Grip Handle CSS
  31. 31Voice Recording Microphone Floating Button CSS
  32. 32Aurora Gradient Drift Premium Floating Button CSS
  33. 33Quick Emoji Reply Reaction Floating Button CSS
  34. 34Modern Squircle Rounded Square FAB CSS
Pure CSSMIT licensed

Pulse Ring Attention-Getter Floating Button CSS

Three expanding rings on a stagger, the pattern used for call buttons, live indicators and onboarding spotlights. The important part is restraint: this demo shows the correct version (a short burst that stops), the radar variant, and a live-status dot — plus exactly why an infinite pulse on a persistent control is a mistake and when it is genuinely justified.

Live Demo
Try it

Nucleo: 44,000+ SVG icons in five families · All Icons Bundle $149

Nucleo · Affiliate link

Get the Nucleo bundle

The code

<section class="fb-26" aria-label="Pulse ring attention getter button demo">
  <div class="fb-26__stage">
    <p class="fb-26__eyebrow">staggered rings · opacity leads scale</p>
    <h2 class="fb-26__title">Pulse with a reason</h2>
    <p class="fb-26__sub">Three rings, each a third of a cycle behind the last. Fade to zero before the scale ends, or the ring pops instead of dissolving.</p>
    <div class="fb-26__row">
      <div class="fb-26__cell">
        <span class="fb-26__wrap">
          <i class="fb-26__ring" aria-hidden="true"></i><i class="fb-26__ring" aria-hidden="true"></i><i class="fb-26__ring" aria-hidden="true"></i>
          <button class="fb-26__fab" type="button" aria-label="Start a call">
            <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6.5 3.8l2.6 1 1 3.1-1.8 1.6a11 11 0 0 0 5.2 5.2l1.6-1.8 3.1 1 1 2.6-1.6 1.9c-.8.9-2.1 1-3.2.5A17.6 17.6 0 0 1 4.4 8.6c-.5-1.1-.4-2.4.5-3.2z" fill="currentColor"/></svg>
          </button>
        </span>
        <span class="fb-26__cap">live · infinite</span>
      </div>
      <div class="fb-26__cell">
        <button class="fb-26__fab fb-26__fab--shadow" type="button" aria-label="Highlighted action, three pulses">
          <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 3l2.4 6.2H21l-5.3 3.9 2 6.4-5.7-4-5.7 4 2-6.4L3 9.2h6.6z" fill="currentColor"/></svg>
        </button>
        <span class="fb-26__cap">onboarding · 3×</span>
      </div>
      <div class="fb-26__cell">
        <span class="fb-26__wrap">
          <i class="fb-26__radar" aria-hidden="true"></i>
          <button class="fb-26__fab fb-26__fab--radar" type="button" aria-label="Scanning for devices">
            <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="2.6" fill="currentColor"/><path d="M7.8 16.2a6 6 0 0 1 0-8.4M16.2 7.8a6 6 0 0 1 0 8.4M5 19a10 10 0 0 1 0-14M19 5a10 10 0 0 1 0 14" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
          </button>
        </span>
        <span class="fb-26__cap">radar sweep</span>
      </div>
    </div>
    <p class="fb-26__chip">2.4s cycle · delays 0 / .8 / 1.6s · stops under reduced motion</p>
  </div>
</section>
.fb-26 {
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  background: var(--fb-26-bg);
  --fb-26-bg: radial-gradient(100% 80% at 50% 0%,oklch(0.26 0.05 160),oklch(0.15 0.02 175) 70%);
  --fb-26-accent: oklch(0.78 0.17 155);
  --fb-26-ink: oklch(0.97 0.01 160);
  --fb-26-mut: oklch(0.76 0.02 160);
  font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
  color: var(--fb-26-ink);
  display: grid;
  place-items: center;
  padding: clamp(20px,5vw,56px);
}

.fb-26 *,
.fb-26 *::before,
.fb-26 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.fb-26__stage {
  width: min(100%,58ch);
  display: grid;
  gap: clamp(20px,3.4vw,32px);
  justify-items: center;
  text-align: center;
}

.fb-26__eyebrow {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fb-26-accent);
}

.fb-26__title {
  font-size: clamp(26px,4.6vw,44px);
  line-height: 1.05;
  letter-spacing: -.03em;
  font-weight: 700;
  text-wrap: balance;
}

.fb-26__sub {
  max-width: 50ch;
  font-size: clamp(13.5px,1.7vw,16.5px);
  line-height: 1.62;
  color: var(--fb-26-mut);
  text-wrap: pretty;
}

.fb-26__row {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(28px,8vw,72px);
  justify-content: center;
  padding: 18px 0;
}

.fb-26__cell {
  display: grid;
  gap: 16px;
  justify-items: center;
}

.fb-26__cap {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--fb-26-mut);
}

.fb-26__wrap {
  position: relative;
  display: grid;
  place-items: center;
}

.fb-26__ring {
  position: absolute;
  width: 66px;
  height: 66px;
  border-radius: 50%;
  border: 2px solid var(--fb-26-accent);
  pointer-events: none;
  opacity: 0;
  animation: fb-26-ping 2.4s cubic-bezier(0,.55,.45,1) infinite;
}

.fb-26__ring:nth-child(2) {
  animation-delay: .8s;
}

.fb-26__ring:nth-child(3) {
  animation-delay: 1.6s;
}

@keyframes fb-26-ping {
  0% {
    scale: .85;
    opacity: .7;
  }

  70% {
    opacity: 0;
  }

  100% {
    scale: 2.2;
    opacity: 0;
  }
}

.fb-26__fab {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 66px;
  block-size: 66px;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  color: oklch(0.15 0.04 160);
  background: radial-gradient(120% 120% at 32% 26%,oklch(0.92 0.15 150),var(--fb-26-accent));
  box-shadow: 0 16px 38px -14px oklch(0.78 0.17 155/.6),0 2px 6px oklch(0.08 0.01 175/.7);
  transition: transform .28s cubic-bezier(.2,1.3,.4,1),box-shadow .3s ease;
}

.fb-26__fab svg {
  width: 27px;
  height: 27px;
}

.fb-26__fab:hover {
  transform: translateY(-3px) scale(1.04);
}

.fb-26__fab:active {
  transform: scale(.93);
}

.fb-26__fab:focus-visible {
  outline: 3px solid oklch(0.98 0.01 160);
  outline-offset: 6px;
}

.fb-26__fab--shadow {
  background: radial-gradient(120% 120% at 32% 26%,oklch(0.9 0.14 95),oklch(0.78 0.16 78));
  color: oklch(0.2 0.05 78);
  animation: fb-26-shadow 2.2s cubic-bezier(0,.55,.45,1) 3;
}

@keyframes fb-26-shadow {
  0% {
    box-shadow: 0 0 0 0 oklch(0.78 0.16 78/.65),0 16px 38px -14px oklch(0.78 0.16 78/.6);
  }

  70%,
    100% {
    box-shadow: 0 0 0 22px oklch(0.78 0.16 78/0),0 16px 38px -14px oklch(0.78 0.16 78/.6);
  }
}

.fb-26__fab--radar {
  background: radial-gradient(120% 120% at 32% 26%,oklch(0.85 0.13 200),oklch(0.66 0.15 210));
  color: oklch(0.14 0.04 210);
}

.fb-26__radar {
  position: absolute;
  width: 132px;
  height: 132px;
  border-radius: 50%;
  pointer-events: none;
  background: conic-gradient(from 0deg,transparent 0deg,color-mix(in oklch,oklch(0.7 0.15 205) 55%,transparent) 42deg,transparent 60deg);
  -webkit-mask: radial-gradient(circle,transparent 32px,#000 33px,#000 66px,transparent 67px);
  mask: radial-gradient(circle,transparent 32px,#000 33px,#000 66px,transparent 67px);
  animation: fb-26-sweep 3.4s linear infinite;
}

@keyframes fb-26-sweep {
  to {
    rotate: 360deg;
  }
}

.fb-26__chip {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11px;
  color: var(--fb-26-mut);
  padding: 8px 14px;
  border: 1px solid oklch(1 0 0/.16);
  border-radius: 99px;
}

@media (prefers-reduced-motion: reduce) {
  .fb-26__ring,
    .fb-26__radar,
    .fb-26__fab--shadow {
    animation: none !important;
  }

  .fb-26__ring:first-of-type {
    opacity: .35;
    scale: 1.35;
  }
}
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: Pulse Ring Attention-Getter Floating Button CSS
Source: https://codefronts.com/components/css-floating-buttons/fb03/

Three expanding rings on a stagger, the pattern used for call buttons, live indicators and onboarding spotlights. The important part is restraint: this demo shows the correct version (a short burst that stops), the radar variant, and a live-status dot — plus exactly why an infinite pulse on a persistent control is a mistake and when it is genuinely justified.
## HTML
```html
<section class="fb-26" aria-label="Pulse ring attention getter button demo">
  <div class="fb-26__stage">
    <p class="fb-26__eyebrow">staggered rings · opacity leads scale</p>
    <h2 class="fb-26__title">Pulse with a reason</h2>
    <p class="fb-26__sub">Three rings, each a third of a cycle behind the last. Fade to zero before the scale ends, or the ring pops instead of dissolving.</p>
    <div class="fb-26__row">
      <div class="fb-26__cell">
        <span class="fb-26__wrap">
          <i class="fb-26__ring" aria-hidden="true"></i><i class="fb-26__ring" aria-hidden="true"></i><i class="fb-26__ring" aria-hidden="true"></i>
          <button class="fb-26__fab" type="button" aria-label="Start a call">
            <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M6.5 3.8l2.6 1 1 3.1-1.8 1.6a11 11 0 0 0 5.2 5.2l1.6-1.8 3.1 1 1 2.6-1.6 1.9c-.8.9-2.1 1-3.2.5A17.6 17.6 0 0 1 4.4 8.6c-.5-1.1-.4-2.4.5-3.2z" fill="currentColor"/></svg>
          </button>
        </span>
        <span class="fb-26__cap">live · infinite</span>
      </div>
      <div class="fb-26__cell">
        <button class="fb-26__fab fb-26__fab--shadow" type="button" aria-label="Highlighted action, three pulses">
          <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 3l2.4 6.2H21l-5.3 3.9 2 6.4-5.7-4-5.7 4 2-6.4L3 9.2h6.6z" fill="currentColor"/></svg>
        </button>
        <span class="fb-26__cap">onboarding · 3×</span>
      </div>
      <div class="fb-26__cell">
        <span class="fb-26__wrap">
          <i class="fb-26__radar" aria-hidden="true"></i>
          <button class="fb-26__fab fb-26__fab--radar" type="button" aria-label="Scanning for devices">
            <svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="2.6" fill="currentColor"/><path d="M7.8 16.2a6 6 0 0 1 0-8.4M16.2 7.8a6 6 0 0 1 0 8.4M5 19a10 10 0 0 1 0-14M19 5a10 10 0 0 1 0 14" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>
          </button>
        </span>
        <span class="fb-26__cap">radar sweep</span>
      </div>
    </div>
    <p class="fb-26__chip">2.4s cycle · delays 0 / .8 / 1.6s · stops under reduced motion</p>
  </div>
</section>
```
## CSS
```css
.fb-26 {
  width: 100%;
  min-height: 100vh;
  min-height: 100svh;
  display: block;
  background: var(--fb-26-bg);
  --fb-26-bg: radial-gradient(100% 80% at 50% 0%,oklch(0.26 0.05 160),oklch(0.15 0.02 175) 70%);
  --fb-26-accent: oklch(0.78 0.17 155);
  --fb-26-ink: oklch(0.97 0.01 160);
  --fb-26-mut: oklch(0.76 0.02 160);
  font-family: 'Segoe UI',system-ui,-apple-system,sans-serif;
  color: var(--fb-26-ink);
  display: grid;
  place-items: center;
  padding: clamp(20px,5vw,56px);
}

.fb-26 *,
.fb-26 *::before,
.fb-26 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.fb-26__stage {
  width: min(100%,58ch);
  display: grid;
  gap: clamp(20px,3.4vw,32px);
  justify-items: center;
  text-align: center;
}

.fb-26__eyebrow {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--fb-26-accent);
}

.fb-26__title {
  font-size: clamp(26px,4.6vw,44px);
  line-height: 1.05;
  letter-spacing: -.03em;
  font-weight: 700;
  text-wrap: balance;
}

.fb-26__sub {
  max-width: 50ch;
  font-size: clamp(13.5px,1.7vw,16.5px);
  line-height: 1.62;
  color: var(--fb-26-mut);
  text-wrap: pretty;
}

.fb-26__row {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(28px,8vw,72px);
  justify-content: center;
  padding: 18px 0;
}

.fb-26__cell {
  display: grid;
  gap: 16px;
  justify-items: center;
}

.fb-26__cap {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--fb-26-mut);
}

.fb-26__wrap {
  position: relative;
  display: grid;
  place-items: center;
}

.fb-26__ring {
  position: absolute;
  width: 66px;
  height: 66px;
  border-radius: 50%;
  border: 2px solid var(--fb-26-accent);
  pointer-events: none;
  opacity: 0;
  animation: fb-26-ping 2.4s cubic-bezier(0,.55,.45,1) infinite;
}

.fb-26__ring:nth-child(2) {
  animation-delay: .8s;
}

.fb-26__ring:nth-child(3) {
  animation-delay: 1.6s;
}

@keyframes fb-26-ping {
  0% {
    scale: .85;
    opacity: .7;
  }

  70% {
    opacity: 0;
  }

  100% {
    scale: 2.2;
    opacity: 0;
  }
}

.fb-26__fab {
  position: relative;
  display: grid;
  place-items: center;
  inline-size: 66px;
  block-size: 66px;
  border: 0;
  border-radius: 50%;
  cursor: pointer;
  color: oklch(0.15 0.04 160);
  background: radial-gradient(120% 120% at 32% 26%,oklch(0.92 0.15 150),var(--fb-26-accent));
  box-shadow: 0 16px 38px -14px oklch(0.78 0.17 155/.6),0 2px 6px oklch(0.08 0.01 175/.7);
  transition: transform .28s cubic-bezier(.2,1.3,.4,1),box-shadow .3s ease;
}

.fb-26__fab svg {
  width: 27px;
  height: 27px;
}

.fb-26__fab:hover {
  transform: translateY(-3px) scale(1.04);
}

.fb-26__fab:active {
  transform: scale(.93);
}

.fb-26__fab:focus-visible {
  outline: 3px solid oklch(0.98 0.01 160);
  outline-offset: 6px;
}

.fb-26__fab--shadow {
  background: radial-gradient(120% 120% at 32% 26%,oklch(0.9 0.14 95),oklch(0.78 0.16 78));
  color: oklch(0.2 0.05 78);
  animation: fb-26-shadow 2.2s cubic-bezier(0,.55,.45,1) 3;
}

@keyframes fb-26-shadow {
  0% {
    box-shadow: 0 0 0 0 oklch(0.78 0.16 78/.65),0 16px 38px -14px oklch(0.78 0.16 78/.6);
  }

  70%,
    100% {
    box-shadow: 0 0 0 22px oklch(0.78 0.16 78/0),0 16px 38px -14px oklch(0.78 0.16 78/.6);
  }
}

.fb-26__fab--radar {
  background: radial-gradient(120% 120% at 32% 26%,oklch(0.85 0.13 200),oklch(0.66 0.15 210));
  color: oklch(0.14 0.04 210);
}

.fb-26__radar {
  position: absolute;
  width: 132px;
  height: 132px;
  border-radius: 50%;
  pointer-events: none;
  background: conic-gradient(from 0deg,transparent 0deg,color-mix(in oklch,oklch(0.7 0.15 205) 55%,transparent) 42deg,transparent 60deg);
  -webkit-mask: radial-gradient(circle,transparent 32px,#000 33px,#000 66px,transparent 67px);
  mask: radial-gradient(circle,transparent 32px,#000 33px,#000 66px,transparent 67px);
  animation: fb-26-sweep 3.4s linear infinite;
}

@keyframes fb-26-sweep {
  to {
    rotate: 360deg;
  }
}

.fb-26__chip {
  font-family: ui-monospace,Menlo,Consolas,monospace;
  font-size: 11px;
  color: var(--fb-26-mut);
  padding: 8px 14px;
  border: 1px solid oklch(1 0 0/.16);
  border-radius: 99px;
}

@media (prefers-reduced-motion: reduce) {
  .fb-26__ring,
    .fb-26__radar,
    .fb-26__fab--shadow {
    animation: none !important;
  }

  .fb-26__ring:first-of-type {
    opacity: .35;
    scale: 1.35;
  }
}
```

How this works

Rings are pseudo-elements scaling out with a fading opacity, each offset by a third of the cycle:

@keyframes ping{ 0%{ scale:.85; opacity:.7 } 70%{ opacity:0 } 100%{ scale:2.1; opacity:0 } }
.ring   { animation:ping 2.4s cubic-bezier(0,.55,.45,1) infinite }
.ring:nth-child(2){ animation-delay:.8s }
.ring:nth-child(3){ animation-delay:1.6s }

Opacity must reach zero before the scale finishes (70% here), otherwise the ring pops out of existence at full size. That single offset is what makes the falloff read as a wave rather than a flicker.

Two cheaper variants are included. The box-shadow pulse animates a spread-only shadow from 0 to 18px — one element, no extra DOM, but it cannot fade independently of the button. The radar sweep is a conic-gradient rotating behind a masked circle, for "scanning" rather than "attention".

On restraint: an infinite pulse is defensible for a live state (recording, an active call, a device pairing) because the animation is the status. For a plain create button it is nagging — use three iterations on first render and stop.

Make it yours

  • Iteration count: animation-iteration-count:3 for onboarding, infinite only for genuine live status.
  • Ring count: two rings read calm, three read urgent, four read broken. Space delays evenly across the duration.
  • Colour fade: animate the border colour from the accent to transparent alongside opacity for a softer edge.
  • Speed: 2.4s is a heartbeat. Under 1.2s it reads as an alarm — appropriate for an emergency call button, wrong for anything else.

Gotchas — read before shipping

  • Rings must be pointer-events:none or the expanded ring intercepts clicks well outside the button's visual bounds.
  • Animating box-shadow spread repaints on every frame; animating scale on a pseudo-element stays on the compositor. Prefer the latter for persistent pulses.
  • Infinite motion near text is a known trigger for vestibular discomfort. Always provide the reduced-motion stop, and consider a static ring instead.
  • A pulse plus a badge plus a colour change is three attention signals fighting each other. Pick one.

Browser support

ChromeSafariFirefoxEdge
114+17.5+121+114+

Floor set by oklch(), color-mix(), text-wrap as this demo is written. The core technique itself goes back further — Chrome 111+.

Keyframes, scale and conic-gradient (Chrome 69+, Safari 12.1+, Firefox 83+) are all broadly supported. oklch() tokens are the only modern floor.

Search CodeFronts

Loading…