FAB

화면 한쪽 구석에 떠서, 그 화면에서 가장 중요한 동작 하나를 즉시 실행하는 원형 버튼.

다른 이름: Floating action buttonSpeed dial
···
html
<div class="fabw">
  <div class="app-bg"><div class="bar" style="width:65%"></div><div class="bar" style="width:40%"></div></div>
  <div class="mini m1" aria-hidden="true">📷</div>
  <div class="mini m2" aria-hidden="true">📝</div>
  <div class="mini m3" aria-hidden="true">🎙️</div>
  <button class="fab" id="fabbtn" aria-label="새로 만들기" aria-haspopup="true" aria-expanded="false">+</button>
</div>
css
.fabw{position:absolute;inset:0}
.app-bg{position:absolute;inset:0;padding:16px;display:grid;gap:10px;align-content:start}
.bar{height:9px;border-radius:5px;background:var(--line)}
.fab{position:absolute;right:16px;bottom:16px;width:46px;height:46px;border-radius:50%;border:0;background:var(--accent);color:#fff;
  font-size:22px;line-height:1;cursor:pointer;box-shadow:0 10px 24px rgba(0,0,0,.25);transition:transform .25s}
.fab[aria-expanded=true]{transform:rotate(45deg)}
.mini{position:absolute;right:22px;bottom:22px;width:34px;height:34px;border-radius:50%;background:var(--surface);border:1px solid var(--line);
  display:grid;place-items:center;font-size:14px;opacity:0;transform:scale(.4);transition:transform .28s cubic-bezier(.3,1.3,.5,1),opacity .2s}
.fabw[data-open] .m1{transform:translate(-4px,-64px) scale(1);opacity:1}
.fabw[data-open] .m2{transform:translate(-46px,-42px) scale(1);opacity:1}
.fabw[data-open] .m3{transform:translate(-58px,4px) scale(1);opacity:1}
js
const wrap = document.querySelector('.fabw'), fab = document.getElementById('fabbtn');
function open(v) { wrap.toggleAttribute('data-open', v); fab.setAttribute('aria-expanded', String(v)); }
let auto = true;
fab.addEventListener('click', () => { auto = false; open(!wrap.hasAttribute('data-open')); });
function loop() { if (!auto) return; open(true); setTimeout(() => { if (auto) { open(false); setTimeout(loop, 900); } }, 1800); }
setTimeout(loop, 600);

아이콘만 있는 버튼이라면 반드시 aria-label로 "새 글 작성" 같은 텍스트를 줘야 합니다 — "+" 아이콘만으론 스크린리더에 아무 의미가 없습니다. 스크롤과 무관하게 항상 같은 자리에 떠 있어야 하므로 position: fixed(또는 뷰포트 기준 absolute)를 씁니다.

누르면 관련된 여러 동작이 부채꼴로 펼쳐지는 변형을 "스피드 다이얼"이라고 부르며, 이땐 트리거에 aria-haspopup과 aria-expanded를 추가로 붙여 메뉴 버튼처럼 다룹니다.

일반 버튼과 다른 점은 위계입니다 — 화면 안의 여러 버튼 중 하나가 아니라 화면당 보통 단 하나만 두고, 그 화면의 "기본 동작"이라는 의미를 담습니다. 두 개 이상의 FAB를 한 화면에 두면 이 위계가 무너집니다.