대니
danny's blog@dannywon_dev
발행 60 · 대기 84

1인 개발자. 클로드 코드를 팀처럼 굴린다. 매일 겪은 것만 쓴다.

버그와 함정

겹친 모달에서 ESC 한 번에 둘 다 닫힌다 — window 리스너

스크롤 잠금 참조 카운터는 멀쩡했다. 문제는 모든 모달이 window 에 ESC 리스너를 달고 있던 것이었다.

모달 위에 모달을 띄워놓고 ESC 를 한 번 눌렀는데 둘 다 닫혔다. 게다가 배경 스크롤 잠금까지 풀렸다.

2026-08-09 에 여러 프로젝트에 흩어져 있던 모달을 하나씩 골라 합치고 있었다. 그중 가장 잘 만든 판에는 스크롤 잠금 참조 카운터가 들어 있었고, 주석에 왜 그게 필요했는지까지 적혀 있었다.

화면 어딘가에 isOpen={false} 로 늘 마운트된 모달이 있으면, 그 컴포넌트가 overflow = '' 를 실행해 정작 열려 있는 모달의 잠금까지 풀어 버린다. → 그래서 열린 개수를 세고, 0이 될 때만 되돌린다.

좋은 코드라 그대로 가져왔다. 그리고 실제로 도는지 보려고 카탈로그에 「겹친 모달 열기」 데모를 만들었다. 모달 위에 모달을 띄우고, 안쪽만 닫아도 배경이 계속 잠겨 있어야 정상이다.

브라우저에서 재현해봤다.

① 바깥 모달       hidden   ✅
② 안쪽까지        hidden   ✅
③ ESC 한 번       visible  ❌  ← 바깥이 아직 열려 있는데 잠금이 풀렸다

참조 카운터를 의심했는데 멀쩡했다

처음엔 옮겨 적다 뭘 빠뜨렸나 싶어 카운터 코드를 다시 봤다. 개수를 세고, 0일 때만 푼다. 그대로였다.

원인은 잠금이 아니라 ESC 였다.

ESC 닫기를 각 모달이 window 에 리스너를 달아 처리하고 있었다. 그러면 열려 있는 모달이 전부 그 키를 듣는다. 안쪽만 닫으려고 누른 ESC 가 바깥 모달에게도 가서 둘 다 닫히기 시작했고, 그 과정에서 잠금 해제가 두 번 불려 카운터가 0이 됐다.

참조 카운터는 잘못이 없었다. 그걸 두 번 호출한 쪽이 문제였다. 이 버그를 막으려고 만들어 둔 장치가 멀쩡히 있는데, 다른 경로로 같은 증상이 난 것이다.

맨 위가 누구인지만 아는 모듈을 만들었다

열려 있는 오버레이를 쌓아두고 「지금 맨 위가 누구인지」만 알려주는 작은 모듈을 만들었다. ESC 는 맨 위 하나만 먹는다.

③ ESC 한 번  →  hidden   ✅  안쪽만 닫히고 잠금 유지
④ ESC 또     →  visible  ✅  이제 바깥도 닫히고 풀린다

같은 병을 앓던 곳이 네 군데였다 — 모달·드로어·확인 대화상자·전체화면 편집창. 전부 windowdocument 에 리스너를 달고 있었다. 특히 확인 대화상자가 위험했다. 「다른 모달 위에 뜨는」 게 가장 흔한 자리이기 때문이다.

데모에 깨질 상황을 넣었다

잠금·모달·리스너처럼 전역에 거는 것은 겹칠 때를 따로 시험해야 한다. 하나만 띄워보면 네 군데 다 정상으로 보인다.

데모를 만들 때 「그냥 열리는 것」이 아니라 **「무엇이 깨질 수 있는 상황」**을 넣으니 그게 곧 시험이 됐다. 겹친 모달 데모를 안 만들었으면 이 버그는 실사용에서 났을 것이다.

← 목록으로