inert 속성

inert Attribute

요소와 그 자손 전체를 포커스·클릭·스크린리더에서 한 번에 제외시키는 HTML 속성. 모달 뒤 배경을 잠글 때 씁니다.

다른 이름: inert
···
html
<div class="wrap">
  <div class="badge" id="badge"><svg viewBox="0 0 10 10"><path id="bpath" d="M1.5 5.2l2.6 2.6L8.5 2.4" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"/></svg><span id="btext">확인 중</span></div>
  <div class="bg" id="bg">
    <button class="bgbtn">배경 버튼 A</button>
    <button class="bgbtn">배경 버튼 B</button>
  </div>
  <div class="modal" id="modal">모달 열림 — 배경 비활성</div>
</div>
css
.wrap{position:relative;width:min(260px,92%);height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px}
.bg{display:grid;gap:8px;transition:opacity .3s}
.bg[inert],.bg.fallback-inert{opacity:.35}
.bgbtn{padding:8px 14px;border-radius:8px;border:1px solid var(--line);background:var(--surface);color:var(--fg);font-size:11px}
.modal{padding:8px 12px;border-radius:8px;background:var(--accent);color:#fff;font-size:10px;font-weight:700;
  opacity:0;visibility:hidden;transition:opacity .3s}
.modal.show{opacity:1;visibility:visible}
.badge{position:absolute;top:10px;right:10px;display:flex;align-items:center;gap:5px;padding:4px 9px;border-radius:999px;font-size:10px;font-weight:700;background:var(--bg);border:1px solid var(--line);color:var(--accent-3);z-index:2}
.badge.no{color:var(--accent-2)}
.badge svg{width:9px;height:9px}
js
const ok = 'inert' in HTMLElement.prototype;
const b=document.getElementById('badge'),p=document.getElementById('bpath'),t=document.getElementById('btext');
b.classList.toggle('no', !ok);
p.setAttribute('d', ok ? 'M1.5 5.2l2.6 2.6L8.5 2.4' : 'M2 2l6 6M8 2l-6 6');
t.textContent = ok ? 'inert 지원됨' : '미지원 · tabindex 폴백';
const bg = document.getElementById('bg'), modal = document.getElementById('modal'), buttons = [...bg.querySelectorAll('.bgbtn')];
function lock(on){
  if (ok) { on ? bg.setAttribute('inert','') : bg.removeAttribute('inert'); }
  else {
    bg.classList.toggle('fallback-inert', on);
    buttons.forEach((btn) => { on ? btn.setAttribute('tabindex','-1') : btn.removeAttribute('tabindex'); btn.style.pointerEvents = on ? 'none' : ''; });
  }
  modal.classList.toggle('show', on);
}
let on = false;
setInterval(() => { on = !on; lock(on); }, 1800);

모달이 열려 있는데 Tab을 누르면 포커스가 배경 콘텐츠로 새어나가는 건 흔한 접근성 버그입니다. 막으려면 배경의 모든 버튼·링크·입력에 `tabindex="-1"`을 일일이 달고, `aria-hidden="true"`도 얹고, `pointer-events:none`까지 CSS로 줘야 했습니다 — 그것도 배경 안에 포커스 가능한 요소가 새로 추가될 때마다 다시 챙겨야 하는 코드였습니다.

`inert` 속성 하나를 부모에 달면 그 서브트리 전체가 포커스·클릭·텍스트 선택·스크린리더 접근에서 제외됩니다. 자손 하나하나를 챙길 필요 없이 "이 영역 전체를 죽은 상태로 만들어라"를 선언적으로 표현합니다. `<dialog>.showModal()`은 내부적으로 배경을 이 방식으로 처리합니다.

기본 지원은 caniuse/MDN baseline을 확인하세요. 미지원 브라우저에서는 배경의 포커스 가능한 요소마다 `tabindex="-1"`·`aria-hidden`을 직접 토글하고 `pointer-events:none`을 CSS로 주는 수동 처리가 필요합니다.

언제 쓰나

모달이 열려 있는 동안 배경 콘텐츠를 포커스·클릭에서 완전히 제외하고 싶을 때.