공지 하나 띄우자고 모달 라이브러리를 통째로 깔고, 포커스 가두기와 배경 클릭 닫기까지 코드로 떠안는다 — HTML dialog 요소가 자바스크립트 없이 '갇힌 창'을 다루는 시대

화면 한가운데에 창을 하나 띄우고 뒤를 어둡게 덮는 일. 흔한 요구지만, 지금까지는 이 작은 창 하나가 예상보다 많은 짐을 끌고 왔다. 배경을 덮는 검은 막, 창 밖을 눌렀을 때 닫기, ESC 키로 닫기, 열려 있는 동안 키보드 포커스가 창 밖으로 새지 않게 가두기까지 — 이 모든 것을 직접 짜거나, 그러기 싫어서 무거운 모달 라이브러리를 통째로 설치하곤 했다.

모달 하나에 딸려오던 것들

제대로 만든 모달은 생각보다 손이 많이 간다. 배경 막을 그리고, 스크롤을 잠그고, 바깥 클릭과 ESC를 감지해 닫고, Tab 키가 창 안에서만 돌게 포커스를 가둔다. 여기에 화면 낭독기 사용자를 위한 역할(role) 표시까지 붙이면 수십 줄이 금세 쌓인다. 공지창 하나 띄우자고 이 코드를 매번 다시 쓰거나, 라이브러리 하나를 더 얹는 셈이다.

dialog 요소는 무엇을 대신 해주나

HTML의 dialog 요소는 이 짐을 상당 부분 브라우저에 넘긴다. 마크업은 단순하다.

  • showModal()로 열면 배경이 자동으로 어두워지고, 그 뒤 내용은 클릭도 포커스도 되지 않는다.
  • ESC 키로 닫는 동작이 기본 내장되어 있어 따로 감지할 필요가 없다.
  • 포커스가 창 안에 자동으로 갇힌다. Tab을 눌러도 창 밖 요소로 새지 않는다.
  • 배경 막은 ::backdrop이라는 전용 선택자로 색과 흐림 효과를 CSS만으로 꾸밀 수 있다.

즉, 예전에 자바스크립트로 떠안던 '갇힌 창'의 핵심 동작 대부분이 태그 하나에 이미 들어 있다.

form method=dialog로 닫기까지

닫기 버튼도 스크립트 없이 처리된다. 창 안의 폼에 method="dialog"를 주면, 그 폼의 버튼을 누르는 순간 창이 닫힌다. 어떤 버튼으로 닫았는지도 값으로 남아, '확인'과 '취소'를 구분해 다음 동작을 이어갈 수 있다. 예약 신청이나 동의 여부처럼 선택의 결과가 필요한 창에서 특히 편하다.

작은 회사 사이트에서 쓸 만한 자리

거창한 기능이 아니라도 쓸 곳은 많다.

  • 쿠키·개인정보 동의창 — 첫 방문자에게 한 번 띄우는 전형적인 모달.
  • 휴무·이벤트 공지 — 명절 배송 지연 같은 안내를 눈에 띄게.
  • 이미지 크게 보기 — 제품 사진을 눌렀을 때 확대해 보여주는 창.
  • 간단한 문의·예약 폼 — 페이지 이동 없이 그 자리에서 입력받기.

그래도 챙겨야 할 것

기본기가 좋아졌다고 손을 완전히 놓아도 되는 건 아니다. 화면 낭독기 사용자를 위해 창의 제목과 dialog를 aria-labelledby로 연결해 두는 편이 좋고, 열고 닫힐 때의 부드러운 전환 효과는 여전히 CSS로 다듬어야 자연스럽다. 아주 오래된 브라우저를 함께 봐야 한다면 대비책도 필요하다. 그래도 출발점이 '빈 태그 하나'에서 '이미 갖춰진 창'으로 바뀐 것은 분명한 변화다.

결국 좋은 웹사이트는 화려한 기능이 아니라, 손님이 걸리는 지점을 하나씩 덜어낸 결과물이다. 이런 최신 표준을 어디에 얼마나 쓸지 가늠하고, 과하지 않게 손님의 동선에 녹여내는 일 — CYAN 에이전시가 작은 회사의 웹사이트를 만들 때 가장 신경 쓰는 부분도 바로 그 균형이다.