이번 편의 결과물: projects.html의 기술 배지를 누르면 짧은 설명이 popover 툴팁으로 뜨고, 프로젝트 상세 dialog가 열렸을 때 배경 내비게이션이 inert 상태가 되어 클릭·Tab 이동이 막힌 것을 개발자 도구로 확인합니다. · 다루는 개념: :popover-open, dialog와 popover의 top layer 스택 비교, inert가 막는 것과 안 막는 것
이 편에서 만드는 파일
web-practice/portfolio/
└── projects.html ~ (기술 배지에 popover 툴팁 추가)개념 정리
05편의 메뉴 popover와 03·04편의 프로젝트 상세 dialog는 둘 다 top layer(다른 모든 요소 위)에 표시됩니다. 하지만 배경에 미치는 영향은 다릅니다.
dialog(showModal()) | popover(auto) | |
|---|---|---|
| top layer 표시 | O | O |
| 배경 클릭 차단 | O(::backdrop이 클릭을 가로챔) | X(배경 요소를 그대로 클릭할 수 있음) |
배경 Tab 이동 차단 | O(배경이 inert 상태가 됨) | X |
| 닫는 방법 | close(), Esc, method="dialog" 폼 | 바깥 클릭, Esc, hidePopover() |
모달 dialog는 열리는 순간 브라우저가 배경 전체를 inert 상태로 취급합니다. inert는 그 서브트리를 클릭·포커스·텍스트 검색 대상에서 제외하는 전역 속성입니다. HTML 속성으로 직접 붙일 수도 있지만, 모달 dialog는 이 처리를 자동으로 해 줍니다. 04편에서 Tab이 배경으로 새어 나가지 않는다고 확인한 것이 바로 이 inert 처리의 결과입니다. 반면 popover는 라이트 디스미스만 제공할 뿐 배경을 막지 않습니다. 05편 메뉴가 열려 있어도 본문의 다른 링크를 그대로 클릭할 수 있는 이유입니다.
:popover-open
popover가 열려 있는 동안에만 적용되는 CSS 의사 클래스입니다. [popover]:popover-open { ... }처럼 써서 열린 상태의 모양을 다르게 줄 수 있습니다. 이 과목에서는 CSS를 최소로만 다루므로 존재만 확인하고, 실제 스타일링은 css_fundamentals에서 합니다.
실습
1. projects.html 열기
web-practice/portfolio/projects.html에서 03편까지 만든 프로젝트 카드의 <ul class="tags">를 찾습니다.
2. 기술 배지를 popover 버튼으로 바꾸기
각 태그를 버튼으로 바꾸고, 같은 개수의 작은 popover를 하나씩 연결합니다. 지면상 카드 2개만 보이며, 나머지 4개도 같은 패턴으로 채워져 있습니다.
<!-- web-practice/portfolio/projects.html -->
<div class="project-grid">
<article class="project-card">
<img src="images/project-01.svg" alt="오늘의 날씨 프로젝트 화면" width="1200" height="800" />
<h3>오늘의 날씨</h3>
<p>위치 기반 날씨를 카드로 보여주는 웹앱입니다. 오프라인에서도 마지막 데이터를 보여줍니다.</p>
<ul class="tags">
<li>
<button type="button" class="tag" popovertarget="tip-weather-js">JavaScript</button>
<div id="tip-weather-js" class="tooltip" popover role="tooltip">순수 자바스크립트로 위치 조회와 화면 갱신을 구현했습니다.</div>
</li>
<li>
<button type="button" class="tag" popovertarget="tip-weather-pwa">PWA</button>
<div id="tip-weather-pwa" class="tooltip" popover role="tooltip">Service Worker로 오프라인에서도 마지막 데이터를 보여줍니다.</div>
</li>
</ul>
<button type="button" class="btn-detail" data-project-id="weather">자세히</button>
</article>
<article class="project-card">
<img src="images/project-02.svg" alt="독서 기록 bookshelf 프로젝트 화면" width="1200" height="800" />
<h3>독서 기록 bookshelf</h3>
<p>읽은 책과 별점을 기록하고 통계를 보는 React 앱입니다.</p>
<ul class="tags">
<li>
<button type="button" class="tag" popovertarget="tip-bookshelf-react">React</button>
<div id="tip-bookshelf-react" class="tooltip" popover role="tooltip">컴포넌트 단위로 책 목록과 상세 화면을 구성했습니다.</div>
</li>
<li>
<button type="button" class="tag" popovertarget="tip-bookshelf-vite">Vite</button>
<div id="tip-bookshelf-vite" class="tooltip" popover role="tooltip">개발 서버와 번들링에 Vite를 사용했습니다.</div>
</li>
</ul>
<button type="button" class="btn-detail" data-project-id="bookshelf">자세히</button>
</article>
<!-- notes, a11y, tokens, todo-cli 카드도 동일한 tag+tooltip 패턴 -->
</div>
<dialog id="project-dialog" class="project-dialog">
<form method="dialog">
<button type="submit" value="closed" class="dialog-close" aria-label="닫기">×</button>
</form>
<h2 class="dialog-title"></h2>
<p class="dialog-background"></p>
<p class="dialog-role"></p>
<p class="dialog-learned"></p>
</dialog>role="tooltip"을 붙여 스크린 리더가 이 popover를 툴팁으로 인식하게 합니다. 버튼과 popover는 항상 짝을 이루므로 id가 겹치지 않게 tip-프로젝트-태그 형식을 씁니다. 03·04편에서 만든 dialog#project-dialog와 btn-detail 버튼은 그대로 유지합니다.
3. 실행
Live Server로 projects.html을 엽니다.
4. 확인
- 기술 배지(
JavaScript,PWA등)를 클릭하면 짧은 설명 popover가 뜬다 - 배지 popover가 열린 채로 다른 배지를 클릭하면 이전 것이 자동으로 닫히고 새 것이 열린다(같은
autopopover끼리는 하나만 열림) - “자세히” 버튼으로
dialog를 연 뒤, 개발자 도구 Elements 패널의 Accessibility 탭에서 배경의<nav>를 선택하면Ignored(무시됨) 상태와 그 사유에inert가 표시된다 dialog가 열린 상태에서 배경의 메뉴 버튼을 클릭해도 아무 반응이 없다
직접 해보기
프로젝트 카드 태그 버튼의 role="tooltip"을 지우고 다시 클릭해 봅니다. 화면은 똑같이 보이는데 무엇이 달라졌을까요?
정답 보기
화면 모양은 그대로지만 스크린 리더가 읽어주는 내용이 달라집니다. role="tooltip"이 없으면 이 popover는 그냥 이름 없는 div로 안내되어, 사용자가 이것이 배지에 대한 부가 설명이라는 것을 알기 어렵습니다.
자주 하는 실수
| 증상 | 원인 | 고치는 법 |
|---|---|---|
| 툴팁 버튼을 눌러도 안 열린다 | popovertarget 값과 div의 id가 다르다 | 두 값이 정확히 일치하는지 확인한다 |
| 두 개의 툴팁이 동시에 열린다 | popover 속성값을 manual로 잘못 썼다 | 기본값 auto를 쓰면 하나만 열리도록 브라우저가 관리한다 |
| dialog가 열려도 배경 메뉴 버튼이 눌린다 | showModal()이 아니라 show()로 열었다 | show()는 논모달이라 배경이 inert 처리되지 않는다. 03편의 showModal() 호출이 그대로 유지되어 있는지 확인한다 |
| 개발자 도구에서 inert 근거를 못 찾겠다 | Elements 패널의 일반 속성만 보고 있다 | Accessibility 탭에서 해당 요소를 선택해 Ignored 사유를 확인한다 |