왜 pointer-events를 제대로 알아야 할까요?

모달 오버레이를 띄웠는데 뒤에 있는 버튼이 안 눌린다? 서브메뉴가 opacity: 0인데도 호버가 걸린다? 실무에서 자주 만나는 이런 버그의 8할은 pointer-events를 '이벤트 끄는 스위치' 정도로만 이해하고 있어서 생겨요.

이 속성의 진짜 동작은 이거예요.

"브라우저가 히트테스트(hit-testing)할 때, 이 요소를 이벤트 타겟 후보에서 제외할지 말지"

브라우저는 포인터 이벤트를 발생시키기 전에 항상 가장 위에 있는 요소부터 확인해요. 그 요소가 pointer-events: none이면, 브라우저는 그 요소를 건너뛰고 아래에 있는 다음 요소를 찾아요. 즉, 이벤트를 '비활성화'하는 게 아니라 타겟 선정 자체를 바꾸는 거예요. 이 관점 하나만 잡으면 나머지 동작은 거의 다 설명됩니다.

이 글은 CSS-Tricks의 pointer-events 레퍼런스를 바탕으로, 실무에서 자주 밟는 함정 위주로 재구성했어요.

Developer inspecting CSS pointer-events property in browser DevTools while debugging click-through behavior Developer Related Image

기본 문법과 값 11개 한눈에 보기

/* HTML + SVG 공통 */
pointer-events: auto;   /* 기본값. 정상적으로 이벤트를 받음 (SVG에서는 visiblePainted와 동일) */
pointer-events: none;   /* 이 요소는 이벤트 타겟이 되지 않음. 아래 요소가 대신 받음 */

/* SVG 전용 값 */
pointer-events: visiblePainted; /* 보이는 상태 + fill 또는 stroke 위일 때만 */
pointer-events: visibleFill;    /* 보이는 상태 + fill 위일 때만 (fill:none이어도 OK) */
pointer-events: visibleStroke;  /* 보이는 상태 + stroke 위일 때만 */
pointer-events: visible;        /* 보이는 상태 + fill 또는 stroke 위일 때만 */
pointer-events: painted;        /* visibility 무관, fill 또는 stroke 위일 때만 */
pointer-events: fill;           /* visibility 무관, fill 위일 때만 */
pointer-events: stroke;         /* visibility 무관, stroke 위일 때만 */
pointer-events: bounding-box;   /* 도형 모양 무관, 바운딩 박스 안이면 전부 */
pointer-events: all;            /* fill/stroke/visibility 무관, 전부 */

/* 전역 값 */
pointer-events: inherit;
pointer-events: initial;
pointer-events: revert;
pointer-events: unset;

실무에서 실제로 쓰는 값은 딱 3개

솔직히 말하면, 일반적인 웹앱 개발에서 매일 쓰는 건 auto, none, 그리고 가끔 bounding-box 정도예요. 나머지 SVG 값들은 아이콘/차트/지도 같은 그래픽 인터랙션을 만들 때만 등장합니다.

가장 흔한 패턴: 모달 오버레이 클릭 통과

<div class="overlay">
  <div class="modal">...</div>
</div>
/* 전체 화면을 덮는 컨테이너는 클릭을 통과시킨다 */
.overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none; /* ⚠️ 상속됨! */
}

/* 모달 본체는 다시 클릭을 받도록 복구 */
.modal {
  pointer-events: auto;
}

여기서 가장 많이 하는 실수가 바로 아래에서 설명할 '상속' 이슈예요.

Frontend engineer testing modal overlay with pointer-events none letting background buttons receive clicks

반드시 알아야 할 4가지 함정

1. pointer-events는 상속된다

pointer-events는 inherited: yes 속성이에요. 부모에 none을 걸면 자식도 전부 none이 돼요. 그래서 모달 패턴에서 .modal { pointer-events: auto; }로 되돌려주는 코드가 반드시 필요합니다.

.parent { pointer-events: none; }
.child  { pointer-events: auto; } /* 선택적으로 되살리기 */

2. 이벤트 전파(bubbling)는 여전히 동작한다

pointer-events: none인 부모 안에 pointer-events: auto인 자식이 있으면:

  • 자식이 event.target이 되고
  • 이벤트는 정상적으로 캡처 → 타겟 → 버블 단계를 거쳐요
  • 부모에 걸린 click, pointerenter, pointerleave 리스너도 정상 실행됩니다

즉, pointer-events는 타겟 선정만 바꾸지, 이벤트 전파는 건드리지 않아요. 이걸 모르면 "부모에 none 걸었는데 왜 이벤트가 올라오지?" 하고 삽질하게 됩니다.

3. 이건 '비활성화'가 아니다

  • 키보드 포커스는 여전히 가능해요. Tab으로 포커스가 잡히고, 폼 조작도 됩니다.
  • 진짜로 비활성화하려면:
    • 폼 컨트롤 → disabled 속성
    • 영역 전체를 포인터/키보드/접근성 트리에서 제거 → inert 속성

4. 텍스트 선택은 막지 못한다

pointer-events: none이어도 Ctrl/Cmd + A로 텍스트 드래그 선택이 가능해요. 텍스트 선택을 막으려면 별도로:

.no-select {
  user-select: none;
}

자주 쓰는 실전 패턴: 보이지 않는 서브메뉴

.menu-item .submenu {
  opacity: 0;
  pointer-events: none; /* opacity:0만 걸면 보이지 않아도 클릭됨 */
  transition: opacity .2s ease;
}

.menu-item:hover .submenu {
  opacity: 1;
  pointer-events: auto;
}

opacity: 0만 걸면 눈에 안 보여도 클릭은 됩니다. 이게 실제 사용자 입장에서는 "안 보이는 요소가 클릭을 가로챈다"는 최악의 UX 버그로 이어져요. 반드시 pointer-events를 같이 토글하세요.

SVG 값들은 언제 쓰나?

  • visiblePainted: 기본 SVG 동작. 안 보이거나 투명한 영역은 이벤트 무시.
  • bounding-box: 아이콘의 빈 모서리 영역까지 클릭 영역으로 만들고 싶을 때.
  • all: fill:none인 외곽선 아이콘도 전체 영역에서 클릭 받게 하고 싶을 때.

지도/차트에서 SVG 패스의 히트 영역을 정교하게 다듬을 때 유용합니다.

Web developer writing pointer-events CSS rules on laptop for interactive UI components

정리 및 다음 단계

핵심만 다시 짚으면:

목적올바른 도구
클릭 통과 / 이벤트 타겟 제외pointer-events: none
폼 컨트롤 비활성화disabled
영역 전체 비활성화(접근성 포함)inert
텍스트 선택 방지user-select: none

한국 개발 생태계 관점에서 한마디. 국내 SI/외주 프로젝트에서는 "모달 뒤 배경 클릭 막기"를 z-index만으로 해결하려다가 접근성 문제를 만드는 경우가 많아요. pointer-events: none + pointer-events: auto 조합으로 오버레이를 처리하고, 동시에 inert를 배경 컨테이너에 걸어주는 게 요즘 브라우저 기준으로는 가장 깔끔합니다. 특히 관리자 페이지에서 키보드 접근성 QA가 들어오면 pointer-events만으로는 부족하다는 걸 바로 체감하게 될 거예요.

한계와 주의사항. pointer-events는 어디까지나 포인터 이벤트 타겟 선정만 다뤄요. 스크린 리더, 키보드 내비게이션, 포커스 트랩 같은 접근성 문제는 전혀 해결해주지 않습니다. 또한 SVG 값들은 브라우저별 미세한 차이가 있을 수 있으니, 프로덕션에 넣기 전에 Safari/Firefox에서 반드시 확인하세요.

다음 단계 학습 방향. 이 속성을 이해했다면 자연스럽게 이어지는 주제는 (1) inert 속성과 포커스 트랩, (2) 이벤트 위임과 event.target vs event.currentTarget 구분, (3) 접근성 트리와 aria-hidden의 관계예요. 특히 (3)은 모달 구현할 때 pointer-events와 세트로 등장합니다.

함께 보면 좋은 글

본 콘텐츠는 신뢰할 수 있는 출처를 바탕으로 AI 도구를 활용하여 초안이 작성되었으며, 편집자의 검토를 거쳐 발행되었습니다. 전문가의 조언을 대체하지 않습니다.