32 CSS Floating Action Button Designs 06 / 32
Fan Arc FAB Menu
Fan and arc style FAB menu with radial spread using JS angle math, available in two demo layouts.
The code
<div class="fb06">
<h1>Fan Arc FAB Menu</h1>
<p class="fb06-sub">Radial floating action button menu — actions spread in a configurable arc on click. CSS transitions + a tiny 15-line JS layout engine.</p>
<div class="fb06-demos">
<!-- Demo 1: Upward fan (90°) -->
<div class="fb06-well" id="fb06-well1">
<span class="fb06-well-tag">Upward 90° arc · 5 items</span>
<div class="fb06-fan-fab" id="fb06-fan1" data-arc="90" data-start="135" data-radius="88">
<div class="fb06-fan-item fb06-closed" data-index="0">
<button class="fb06-fan-btn fb06-fan-btn--a" aria-label="Share">
<svg viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11A3 3 0 0021 5a3 3 0 00-3-3 3 3 0 00-3 3c0 .24.04.47.09.7L8.04 9.81A3 3 0 005 9a3 3 0 00-3 3 3 3 0 003 3 3 3 0 003.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92S19.61 16.08 18 16.08z"/></svg>
</button>
<span class="fb06-fan-lbl">Share</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="1">
<button class="fb06-fan-btn fb06-fan-btn--b" aria-label="Camera">
<svg viewBox="0 0 24 24"><path d="M12 15.2A3.2 3.2 0 018.8 12 3.2 3.2 0 0112 8.8a3.2 3.2 0 013.2 3.2A3.2 3.2 0 0112 15.2M12 7a5 5 0 00-5 5 5 5 0 005 5 5 5 0 005-5 5 5 0 00-5-5m6.5-1H5.5A2.5 2.5 0 003 8.5V19a2.5 2.5 0 002.5 2.5h13A2.5 2.5 0 0021 19V8.5A2.5 2.5 0 0018.5 6zM9 4l.83-1H14.2L15 4H9z"/></svg>
</button>
<span class="fb06-fan-lbl">Camera</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="2">
<button class="fb06-fan-btn fb06-fan-btn--c" aria-label="Bookmark">
<svg viewBox="0 0 24 24"><path d="M17 3H7a2 2 0 00-2 2v16l7-3 7 3V5a2 2 0 00-2-2z"/></svg>
</button>
<span class="fb06-fan-lbl">Bookmark</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="3">
<button class="fb06-fan-btn fb06-fan-btn--d" aria-label="Favorite">
<svg viewBox="0 0 24 24"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5A5.5 5.5 0 0112 5.09 5.5 5.5 0 0122 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
</button>
<span class="fb06-fan-lbl">Like</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="4">
<button class="fb06-fan-btn fb06-fan-btn--e" aria-label="More">
<svg viewBox="0 0 24 24"><path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></svg>
</button>
<span class="fb06-fan-lbl">More</span>
</div>
<button class="fb06-fan-trigger" aria-label="Toggle actions" aria-expanded="false">
<svg viewBox="0 0 24 24"><path d="M19 11h-6V5h-2v6H5v2h6v6h2v-6h6z"/></svg>
</button>
</div>
</div>
<!-- Demo 2: Corner fan (positioned like a real FAB) -->
<div class="fb06-well fb06-corner-well" id="fb06-well2">
<span class="fb06-well-tag">Corner placement · 4 items · 120° arc</span>
<div class="fb06-fan-fab fb06-fan-fab--corner" id="fb06-fan2" data-arc="120" data-start="180" data-radius="90">
<div class="fb06-fan-item fb06-closed" data-index="0">
<button class="fb06-fan-btn fb06-fan-btn--a" aria-label="New post">
<svg viewBox="0 0 24 24"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 000-1.41l-2.34-2.34a1 1 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg>
</button>
<span class="fb06-fan-lbl">Edit</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="1">
<button class="fb06-fan-btn fb06-fan-btn--c" aria-label="Attach">
<svg viewBox="0 0 24 24"><path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5a2.5 2.5 0 015 0v10.5c0 .83-.67 1.5-1.5 1.5s-1.5-.67-1.5-1.5V6H9v9.5a3.5 3.5 0 007 0V5c0-2.76-2.24-5-5-5S6 2.24 6 5v12.5c0 3.87 3.13 7 7 7s7-3.13 7-7V6h-3.5z"/></svg>
</button>
<span class="fb06-fan-lbl">Attach</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="2">
<button class="fb06-fan-btn fb06-fan-btn--b" aria-label="Gallery">
<svg viewBox="0 0 24 24"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>
</button>
<span class="fb06-fan-lbl">Gallery</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="3">
<button class="fb06-fan-btn fb06-fan-btn--e" aria-label="Location">
<svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5a2.5 2.5 0 010-5 2.5 2.5 0 010 5z"/></svg>
</button>
<span class="fb06-fan-lbl">Location</span>
</div>
<button class="fb06-fan-trigger" style="background:linear-gradient(135deg,#8b5cf6,#d946ef);box-shadow:0 6px 22px rgba(139,92,246,.45),inset 0 1px 0 rgba(255,255,255,.18)" aria-label="Toggle actions" aria-expanded="false">
<svg viewBox="0 0 24 24"><path d="M19 11h-6V5h-2v6H5v2h6v6h2v-6h6z"/></svg>
</button>
</div>
</div>
</div>
</div> <div class="fb06">
<h1>Fan Arc FAB Menu</h1>
<p class="fb06-sub">Radial floating action button menu — actions spread in a configurable arc on click. CSS transitions + a tiny 15-line JS layout engine.</p>
<div class="fb06-demos">
<!-- Demo 1: Upward fan (90°) -->
<div class="fb06-well" id="fb06-well1">
<span class="fb06-well-tag">Upward 90° arc · 5 items</span>
<div class="fb06-fan-fab" id="fb06-fan1" data-arc="90" data-start="135" data-radius="88">
<div class="fb06-fan-item fb06-closed" data-index="0">
<button class="fb06-fan-btn fb06-fan-btn--a" aria-label="Share">
<svg viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11A3 3 0 0021 5a3 3 0 00-3-3 3 3 0 00-3 3c0 .24.04.47.09.7L8.04 9.81A3 3 0 005 9a3 3 0 00-3 3 3 3 0 003 3 3 3 0 003.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92S19.61 16.08 18 16.08z"/></svg>
</button>
<span class="fb06-fan-lbl">Share</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="1">
<button class="fb06-fan-btn fb06-fan-btn--b" aria-label="Camera">
<svg viewBox="0 0 24 24"><path d="M12 15.2A3.2 3.2 0 018.8 12 3.2 3.2 0 0112 8.8a3.2 3.2 0 013.2 3.2A3.2 3.2 0 0112 15.2M12 7a5 5 0 00-5 5 5 5 0 005 5 5 5 0 005-5 5 5 0 00-5-5m6.5-1H5.5A2.5 2.5 0 003 8.5V19a2.5 2.5 0 002.5 2.5h13A2.5 2.5 0 0021 19V8.5A2.5 2.5 0 0018.5 6zM9 4l.83-1H14.2L15 4H9z"/></svg>
</button>
<span class="fb06-fan-lbl">Camera</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="2">
<button class="fb06-fan-btn fb06-fan-btn--c" aria-label="Bookmark">
<svg viewBox="0 0 24 24"><path d="M17 3H7a2 2 0 00-2 2v16l7-3 7 3V5a2 2 0 00-2-2z"/></svg>
</button>
<span class="fb06-fan-lbl">Bookmark</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="3">
<button class="fb06-fan-btn fb06-fan-btn--d" aria-label="Favorite">
<svg viewBox="0 0 24 24"><path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5A5.5 5.5 0 0112 5.09 5.5 5.5 0 0122 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/></svg>
</button>
<span class="fb06-fan-lbl">Like</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="4">
<button class="fb06-fan-btn fb06-fan-btn--e" aria-label="More">
<svg viewBox="0 0 24 24"><path d="M6 10c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm12 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm-6 0c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></svg>
</button>
<span class="fb06-fan-lbl">More</span>
</div>
<button class="fb06-fan-trigger" aria-label="Toggle actions" aria-expanded="false">
<svg viewBox="0 0 24 24"><path d="M19 11h-6V5h-2v6H5v2h6v6h2v-6h6z"/></svg>
</button>
</div>
</div>
<!-- Demo 2: Corner fan (positioned like a real FAB) -->
<div class="fb06-well fb06-corner-well" id="fb06-well2">
<span class="fb06-well-tag">Corner placement · 4 items · 120° arc</span>
<div class="fb06-fan-fab fb06-fan-fab--corner" id="fb06-fan2" data-arc="120" data-start="180" data-radius="90">
<div class="fb06-fan-item fb06-closed" data-index="0">
<button class="fb06-fan-btn fb06-fan-btn--a" aria-label="New post">
<svg viewBox="0 0 24 24"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04a1 1 0 000-1.41l-2.34-2.34a1 1 0 00-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/></svg>
</button>
<span class="fb06-fan-lbl">Edit</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="1">
<button class="fb06-fan-btn fb06-fan-btn--c" aria-label="Attach">
<svg viewBox="0 0 24 24"><path d="M16.5 6v11.5c0 2.21-1.79 4-4 4s-4-1.79-4-4V5a2.5 2.5 0 015 0v10.5c0 .83-.67 1.5-1.5 1.5s-1.5-.67-1.5-1.5V6H9v9.5a3.5 3.5 0 007 0V5c0-2.76-2.24-5-5-5S6 2.24 6 5v12.5c0 3.87 3.13 7 7 7s7-3.13 7-7V6h-3.5z"/></svg>
</button>
<span class="fb06-fan-lbl">Attach</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="2">
<button class="fb06-fan-btn fb06-fan-btn--b" aria-label="Gallery">
<svg viewBox="0 0 24 24"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>
</button>
<span class="fb06-fan-lbl">Gallery</span>
</div>
<div class="fb06-fan-item fb06-closed" data-index="3">
<button class="fb06-fan-btn fb06-fan-btn--e" aria-label="Location">
<svg viewBox="0 0 24 24"><path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5a2.5 2.5 0 010-5 2.5 2.5 0 010 5z"/></svg>
</button>
<span class="fb06-fan-lbl">Location</span>
</div>
<button class="fb06-fan-trigger" style="background:linear-gradient(135deg,#8b5cf6,#d946ef);box-shadow:0 6px 22px rgba(139,92,246,.45),inset 0 1px 0 rgba(255,255,255,.18)" aria-label="Toggle actions" aria-expanded="false">
<svg viewBox="0 0 24 24"><path d="M19 11h-6V5h-2v6H5v2h6v6h2v-6h6z"/></svg>
</button>
</div>
</div>
</div>
</div>.fb06, .fb06 *, .fb06 *::before, .fb06 *::after { box-sizing: border-box; margin: 0; padding: 0; }
.fb06 {
font-family: 'Plus Jakarta Sans', sans-serif;
background: #0c0c10;
min-height: 100vh;
display: grid;
place-items: center;
padding: 40px 20px;
color: #e4e4e7;
}
h1 {
font-size: clamp(1.6rem, 5vw, 2.4rem);
font-weight: 700;
text-align: center;
letter-spacing: -.022em;
margin-bottom: 8px;
}
p.fb06-sub {
text-align: center;
color: #52525b;
font-size: .9rem;
max-width: 42ch;
margin: 0 auto 60px;
line-height: 1.6;
}
.fb06-demos {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 24px;
width: min(880px, 100%);
}
.fb06-well {
background: #141418;
border: 1px solid #27272a;
border-radius: 22px;
height: 400px;
position: relative;
overflow: hidden;
display: flex;
align-items: flex-end;
justify-content: center;
padding: 40px;
}
.fb06-well-tag {
position: absolute;
top: 16px;
left: 18px;
font-size: .68rem;
font-weight: 600;
letter-spacing: .08em;
text-transform: uppercase;
color: #3f3f46;
}
/* ══ FAN FAB ══ */
.fb06-fan-fab {
position: relative;
width: 62px;
height: 62px;
}
/* main trigger */
.fb06-fan-trigger {
position: relative;
z-index: 10;
width: 62px;
height: 62px;
border-radius: 50%;
border: none;
cursor: pointer;
background: linear-gradient(135deg, #f97316, #ea580c);
box-shadow: 0 6px 22px rgba(249,115,22,.45), inset 0 1px 0 rgba(255,255,255,.18);
display: grid;
place-items: center;
transition: transform .25s cubic-bezier(.34,1.56,.64,1), box-shadow .2s;
}
.fb06-fan-trigger:hover { box-shadow: 0 10px 30px rgba(249,115,22,.6), inset 0 1px 0 rgba(255,255,255,.18); }
.fb06-fan-trigger.fb06-open { transform: rotate(45deg); }
.fb06-fan-trigger svg { width: 26px; height: 26px; fill: #fff; pointer-events: none; }
/* action items */
.fb06-fan-item {
position: absolute;
bottom: 0;
left: 50%;
transform-origin: center 31px; /* half of 62px = pivot at btn center */
transition:
transform .3s cubic-bezier(.34,1.56,.64,1),
opacity .22s ease;
opacity: 0;
}
/* closed: all stacked under trigger */
.fb06-fan-item.fb06-closed { transform: translateX(-50%) translateY(0) scale(.5); }
/* open: spread via CSS custom properties set by JS */
.fb06-fan-item.fb06-open {
opacity: 1;
}
.fb06-fan-btn {
width: 50px;
height: 50px;
border-radius: 50%;
border: none;
cursor: pointer;
display: grid;
place-items: center;
box-shadow: 0 4px 14px rgba(0,0,0,.5);
transition: transform .15s ease;
position: relative;
transform: translateX(-50%);
}
.fb06-fan-btn:hover { transform: translateX(-50%) scale(1.15); }
.fb06-fan-btn svg { width: 20px; height: 20px; fill: #fff; }
/* label tooltip */
.fb06-fan-lbl {
position: absolute;
right: calc(100% + 10px);
top: 50%;
transform: translateY(-50%);
background: #1f1f24;
border: 1px solid #3f3f46;
color: #a1a1aa;
font-size: .72rem;
font-weight: 600;
padding: 4px 10px;
border-radius: 6px;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity .15s ease;
}
.fb06-fan-btn:hover + .fb06-fan-lbl,
.fb06-fan-btn:focus + .fb06-fan-lbl { opacity: 1; }
/* color variants */
.fb06-fan-btn--a { background: linear-gradient(135deg, #6366f1, #8b5cf6); box-shadow: 0 4px 14px rgba(99,102,241,.5); }
.fb06-fan-btn--b { background: linear-gradient(135deg, #06b6d4, #0ea5e9); box-shadow: 0 4px 14px rgba(6,182,212,.5); }
.fb06-fan-btn--c { background: linear-gradient(135deg, #10b981, #059669); box-shadow: 0 4px 14px rgba(16,185,129,.5); }
.fb06-fan-btn--d { background: linear-gradient(135deg, #f43f5e, #e11d48); box-shadow: 0 4px 14px rgba(244,63,94,.5); }
.fb06-fan-btn--e { background: linear-gradient(135deg, #f59e0b, #d97706); box-shadow: 0 4px 14px rgba(245,158,11,.5); }
/* ── Grid of demo variants ── */
.fb06-corner-well {
position: relative;
overflow: hidden;
}
.fb06-fan-fab--corner {
position: absolute;
bottom: 28px;
right: 28px;
}
@media (prefers-reduced-motion: reduce) {
.fb06-fan-item, .fb06-fan-trigger { transition: none; }
} .fb06, .fb06 *, .fb06 *::before, .fb06 *::after { box-sizing: border-box; margin: 0; padding: 0; }
.fb06 {
font-family: 'Plus Jakarta Sans', sans-serif;
background: #0c0c10;
min-height: 100vh;
display: grid;
place-items: center;
padding: 40px 20px;
color: #e4e4e7;
}
h1 {
font-size: clamp(1.6rem, 5vw, 2.4rem);
font-weight: 700;
text-align: center;
letter-spacing: -.022em;
margin-bottom: 8px;
}
p.fb06-sub {
text-align: center;
color: #52525b;
font-size: .9rem;
max-width: 42ch;
margin: 0 auto 60px;
line-height: 1.6;
}
.fb06-demos {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
gap: 24px;
width: min(880px, 100%);
}
.fb06-well {
background: #141418;
border: 1px solid #27272a;
border-radius: 22px;
height: 400px;
position: relative;
overflow: hidden;
display: flex;
align-items: flex-end;
justify-content: center;
padding: 40px;
}
.fb06-well-tag {
position: absolute;
top: 16px;
left: 18px;
font-size: .68rem;
font-weight: 600;
letter-spacing: .08em;
text-transform: uppercase;
color: #3f3f46;
}
/* ══ FAN FAB ══ */
.fb06-fan-fab {
position: relative;
width: 62px;
height: 62px;
}
/* main trigger */
.fb06-fan-trigger {
position: relative;
z-index: 10;
width: 62px;
height: 62px;
border-radius: 50%;
border: none;
cursor: pointer;
background: linear-gradient(135deg, #f97316, #ea580c);
box-shadow: 0 6px 22px rgba(249,115,22,.45), inset 0 1px 0 rgba(255,255,255,.18);
display: grid;
place-items: center;
transition: transform .25s cubic-bezier(.34,1.56,.64,1), box-shadow .2s;
}
.fb06-fan-trigger:hover { box-shadow: 0 10px 30px rgba(249,115,22,.6), inset 0 1px 0 rgba(255,255,255,.18); }
.fb06-fan-trigger.fb06-open { transform: rotate(45deg); }
.fb06-fan-trigger svg { width: 26px; height: 26px; fill: #fff; pointer-events: none; }
/* action items */
.fb06-fan-item {
position: absolute;
bottom: 0;
left: 50%;
transform-origin: center 31px; /* half of 62px = pivot at btn center */
transition:
transform .3s cubic-bezier(.34,1.56,.64,1),
opacity .22s ease;
opacity: 0;
}
/* closed: all stacked under trigger */
.fb06-fan-item.fb06-closed { transform: translateX(-50%) translateY(0) scale(.5); }
/* open: spread via CSS custom properties set by JS */
.fb06-fan-item.fb06-open {
opacity: 1;
}
.fb06-fan-btn {
width: 50px;
height: 50px;
border-radius: 50%;
border: none;
cursor: pointer;
display: grid;
place-items: center;
box-shadow: 0 4px 14px rgba(0,0,0,.5);
transition: transform .15s ease;
position: relative;
transform: translateX(-50%);
}
.fb06-fan-btn:hover { transform: translateX(-50%) scale(1.15); }
.fb06-fan-btn svg { width: 20px; height: 20px; fill: #fff; }
/* label tooltip */
.fb06-fan-lbl {
position: absolute;
right: calc(100% + 10px);
top: 50%;
transform: translateY(-50%);
background: #1f1f24;
border: 1px solid #3f3f46;
color: #a1a1aa;
font-size: .72rem;
font-weight: 600;
padding: 4px 10px;
border-radius: 6px;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity .15s ease;
}
.fb06-fan-btn:hover + .fb06-fan-lbl,
.fb06-fan-btn:focus + .fb06-fan-lbl { opacity: 1; }
/* color variants */
.fb06-fan-btn--a { background: linear-gradient(135deg, #6366f1, #8b5cf6); box-shadow: 0 4px 14px rgba(99,102,241,.5); }
.fb06-fan-btn--b { background: linear-gradient(135deg, #06b6d4, #0ea5e9); box-shadow: 0 4px 14px rgba(6,182,212,.5); }
.fb06-fan-btn--c { background: linear-gradient(135deg, #10b981, #059669); box-shadow: 0 4px 14px rgba(16,185,129,.5); }
.fb06-fan-btn--d { background: linear-gradient(135deg, #f43f5e, #e11d48); box-shadow: 0 4px 14px rgba(244,63,94,.5); }
.fb06-fan-btn--e { background: linear-gradient(135deg, #f59e0b, #d97706); box-shadow: 0 4px 14px rgba(245,158,11,.5); }
/* ── Grid of demo variants ── */
.fb06-corner-well {
position: relative;
overflow: hidden;
}
.fb06-fan-fab--corner {
position: absolute;
bottom: 28px;
right: 28px;
}
@media (prefers-reduced-motion: reduce) {
.fb06-fan-item, .fb06-fan-trigger { transition: none; }
}document.querySelectorAll('.fb06-fan-fab').forEach(fab => {
const arc = parseFloat(fab.dataset.arc); // total degrees
const start = parseFloat(fab.dataset.start); // starting angle (deg)
const radius = parseFloat(fab.dataset.radius);
const items = Array.from(fab.querySelectorAll('.fb06-fan-item'));
const trigger = fab.querySelector('.fb06-fan-trigger');
let isOpen = false;
const count = items.length;
function openFan() {
items.forEach((item, i) => {
const angleDeg = count > 1
? start - (arc / (count - 1)) * i
: start;
const rad = angleDeg * Math.PI / 180;
const x = Math.cos(rad) * radius;
const y = Math.sin(rad) * radius;
item.classList.remove('fb06-closed');
item.classList.add('fb06-open');
item.style.transitionDelay = (i * 0.04) + 's';
item.style.transform = `translateX(calc(-50% + ${x}px)) translateY(${-y}px) scale(1)`;
});
}
function closeFan() {
items.forEach((item, i) => {
item.classList.remove('fb06-open');
item.classList.add('fb06-closed');
item.style.transitionDelay = ((count - 1 - i) * 0.03) + 's';
item.style.transform = '';
});
}
trigger.addEventListener('click', () => {
isOpen = !isOpen;
trigger.classList.toggle('fb06-open', isOpen);
trigger.setAttribute('aria-expanded', isOpen);
isOpen ? openFan() : closeFan();
});
}); document.querySelectorAll('.fb06-fan-fab').forEach(fab => {
const arc = parseFloat(fab.dataset.arc); // total degrees
const start = parseFloat(fab.dataset.start); // starting angle (deg)
const radius = parseFloat(fab.dataset.radius);
const items = Array.from(fab.querySelectorAll('.fb06-fan-item'));
const trigger = fab.querySelector('.fb06-fan-trigger');
let isOpen = false;
const count = items.length;
function openFan() {
items.forEach((item, i) => {
const angleDeg = count > 1
? start - (arc / (count - 1)) * i
: start;
const rad = angleDeg * Math.PI / 180;
const x = Math.cos(rad) * radius;
const y = Math.sin(rad) * radius;
item.classList.remove('fb06-closed');
item.classList.add('fb06-open');
item.style.transitionDelay = (i * 0.04) + 's';
item.style.transform = `translateX(calc(-50% + ${x}px)) translateY(${-y}px) scale(1)`;
});
}
function closeFan() {
items.forEach((item, i) => {
item.classList.remove('fb06-open');
item.classList.add('fb06-closed');
item.style.transitionDelay = ((count - 1 - i) * 0.03) + 's';
item.style.transform = '';
});
}
trigger.addEventListener('click', () => {
isOpen = !isOpen;
trigger.classList.toggle('fb06-open', isOpen);
trigger.setAttribute('aria-expanded', isOpen);
isOpen ? openFan() : closeFan();
});
});