1. 들어가며…
- 서비스 플랫폼의 경우 FAQ, Q&A에 주로 아코디언을 사용한다. 그리고 FAQ나 Q&A는 유저가 자주 묻는 질문이거나 유저에게 기본으로 전달하고 싶은 내용이다.
- 그런데 유저가 일일이 항목을 열어 내용을 보기도 하지만, 특정 키워드가 궁금해 검색하는 경우는 없을까?
- 혹시나 싶어 검색 기능을 사용해봤지만 대부분의 사이트에서 내부 콘텐츠 검색 기능을 제공하지 않고 있었다.
❓ 어떻게 해야 검색이 가능한 아코디언 UI를 만들 수 있을까?
- 방법은 총 2가지가 있는데, 이번 시간에는 2가지 방법으로 컨텐츠 검색이 가능한 아코디언을 만들어보았다!
(만약 UI 라이브러리의 아코디언 구조가 궁금하다면 이 포스팅을 참고하자)
2. 콘텐츠 접근이 가능한 아코디언 만들기
1) details 태그로 구현하는 법
(1) details 태그란?
- HTML의
details
태그는 Accordion처럼 정보를 접었다 펼치는 UI를 개발할 때 유용하다. details
태그는summary
태그와 함께 사용되며,summary
태그에 추가 정보를 넣는다.- 사용자가
details
태그를 클릭하면summary
태그의 내용이 표시되고,details
태그를 다시 클릭하면summary
태그의 내용이 숨겨진다.
See the Pen detail tag default by KumJungMin (@kumjungmin) on CodePen.
open
속성(boolean)으로 아코디언 기본값을 펼쳐진 상태로 만들 수 있다.
See the Pen details tag default open by KumJungMin (@kumjungmin) on CodePen.
toggle
이벤트를 사용해, details의 열림 상태가 변할 때를 감지할 수 있다.
See the Pen details toggle event by KumJungMin (@kumjungmin) on CodePen.
(2) details 태그의 장점
- 아코디언을 구현할 때, JS로 컨텐츠의 높이를 계산하거나 스타일을 통제해야한다.
- 하지만,
details
,summary
를 사용하면 아코디언을 손쉽게 구현할 수 있다. - 또한 사용자가 검색 기능으로,
summary
내부의 콘텐츠에 접근할 수 있는 장점이 있다.
See the Pen details content accessible by KumJungMin (@kumjungmin) on CodePen.
😆 아코디언을 손쉽게 구현할 수 있는데 내부 콘텐츠 검색도 된다니? 너무 좋잖아!
그럼 UI 라이브러리들도 아코디언을 details로 구현했으려나?
(3) details 태그의 단점
- Star수가 18k 이상인 UI라이브러리의 아코디언 구조를 살펴보았다.
- 그런데 예상과는 달리 Accordion을
details
태그가 아닌,div
나button
으로 구현했다.
라이브러리 종류 | materialUI의 accordion | nextUI의 accordion | Vuetify의 expansionPanel |
---|---|---|---|
detail 영역 | div | button | button |
summary 영역 | div | div | div |
❓ 왜 details, summary로 구현하지 않았을까?
- details 태그를 사용하면 구현 코드가 줄어들지만, 스타일 자유도가 낮아지기 때문이다.
<div>
,<button>
의 경우, 아이콘을 컴포넌트로 주입하거나 제거하는 등, 스타일 변형이 자유롭다.- 하지만
<details>
은 아이콘 스타일 변경을 위해, 특정 CSS 속성(list-style, list-style-type, list-style-image)을 사용해야 한다.
See the Pen custom details tag by KumJungMin (@kumjungmin) on CodePen.
- 또한,
<details />
는 브라우저 호환성 문제와 일부 이슈가 있었다. (can i use 사이트) - 호환성 부분에서는 Firefox, Opera 이전 버전에서
<details />
를 작동하지 않았다. - 그리고 일부 브라우저에서 기본 폰트가 작아지거나, toggle 이벤트가 작동하지 않는 문제가 있었다 😢
2) until-found로 구현하는 법
(1) until-found란?
- HTML에는
hidden
속성을 제공하며, 이 속성을 사용하면 요소를 숨길 수 있다. - hidden 속성값은 총 2가지(
hidden
,until-found
)가 제공된다.
See the Pen hidden property demo by KumJungMin (@kumjungmin) on CodePen.
- 요소를
until-found
로 설정하면 페이지를 처음 로드될 때는 요소가 보이지 않는다. - 하지만 사용자가 페이지 검색 기능으로 해당 요소의 텍스트를 찾거나, 요소를 참조하는 링크를 클릭하면 요소가 나타난다.
- 실제 구현 코드를 보면서,
until-found
동작을 확인해보자!
(2) until-found로 Accordion 구현하기
- 우선, 접고자 하는 요소(.details)에
hidden=until-found
를 추가한다. - 그러면 기본적으로 요소가 숨겨지게 된다.
<!-- HTML 코드 -->
<div class="accordion collapsed">
<div class="summary">
<div class="icon">➡️</div>
<span>접히나?</span>
</div>
<div class="details" hidden="until-found"> <!-- this! -->
<div class="content">
여기에 상세 내용을 넣을 수 있죵~ 검색이 잘 될까용
</div>
</div>
</div>
beforematch
이벤트를 사용하면 사용자가 검색한 키워드가 접힌 요소(.details)에 있는지 감지할 수 있다.- 우리의 목표는 검색한 키워드가 있을 때 접힌 요소를 펼치는 것이다.
beforematch
이벤트를 이용해 접힌 요소를 펼치자.
// JS 코드
// 검색한 키워드가 숨겨진 요소에 있다면?
accordionEl.addEventListener('beforematch', expandAccordion);
function expandAccordion() {
// 접힌 요소의 hidden 속성을 제거해, 펼쳐준다!
if (detailsEl.hidden) detailsEl.hidden = false;
detailsEl.style.maxHeight = `${detailsEl?.scrollHeight}px`;
accordionEl.classList.remove("collapsed");
accordionEl.classList.add("expanded");
}
- 헤더 영역(summary) 클릭시 요소(details)를 다시 접고 싶다면, 클릭 이벤트 발생시
hidden
을until-found
로 변경한다.
summaryEl.addEventListener('click', onClickSummary); // 헤더 영역 클릭시!
function onClickSummary() {
// 아코디언(최상위 부모) 요소에 collapsed 클래스가 적용되어 있는지 체크
// collapsed 클래스 적용 여부에 따라 요소(details)를 접거나 펼침
const isCollapsed = accordionEl.classList.contains("collapsed");
if (isCollapsed) expandAccordion();
else collapseAccordion();
}
/** 요소(details)에 hidden 속성을 제거해서 펼친다. */
function expandAccordion() {
if (detailsEl.hidden) detailsEl.hidden = false; /* this! */
detailsEl.style.maxHeight = `${detailsEl?.scrollHeight}px`;
accordionEl.classList.remove("collapsed");
accordionEl.classList.add("expanded");
}
/** 요소(details)에 hidden 속성을 until-found로 지정해 숨긴다. */
function collapseAccordion() {
detailsEl.style.maxHeight = 0;
accordionEl.classList.add("collapsed");
accordionEl.classList.remove("expanded");
detailsEl.hidden = 'until-found'; /* this! */
}
🙂 동작 예시와 전체 코드는 하단에서 볼 수 있다.
See the Pen Accodion_Basic by KumJungMin (@kumjungmin) on CodePen.
😆
until-found
를 쓰면 div나 button을 사용할 수 있어 자유도도 높고, 내부 컨텐츠 검색까지 된다! 그럼, 이렇게 좋은 기능은 UI 라이브러리에서 쓰고 있을까? 안 쓰고 있다! ‘0’
(3) until-found의 단점
until-found
는 아직 모든 브라우저에서 지원하지 않는 기능이다. 그래서, 일부 브라우저에서는 정상적으로 동작하지 않을 수 있다. (Can i use 사이트)
- 또한,
until-found
는 요소를 숨길 때content-visibility: hidden
CSS 속성을 사용하는데, 이 속성 또한 일부 브라우저만 제공하므로 안정성이 보장되지 않는다. (Can i use 사이트)
3. 마치며…
- 이번 시간에는 내부 콘텐츠 검색이 가능한 아코디언을 만드는 2가지 방법에 대해 알아보았다.
- 첫 번째 방법은 '
details
' 태그를 사용하는 방법인데, 아코디언을 쉽게 구현할 수 있으나 스타일 자유도가 낮고 브라우저 호환성 문제가 있다. - 두 번째 방법인 '
until-found
' 속성은 div나 button을 사용할 수 있어 자유도가 높으나, 이 또한 모든 브라우저에서 지원하지 않았다ㅠ - 만약 해당 기능을 구현한다면 서비스가 목표로 하는 브라우저에 문제가 없는지 확인할 필요가 있다
'개발 기술 > 사소하지만 놓치기 쉬운 개발 지식' 카테고리의 다른 글
[TS] 입력 유효성을 체크하는 여러 정규식(feat. 한글, 전화번호, 사업자등록번호, 이메일 등) (0) | 2024.05.13 |
---|---|
[CSS] 확장자 제외하고, 파일명만 말줄임하는 방법(with. input file) (2) | 2024.05.05 |
input 유효성에 따라 스타일링하는 3가지 방법 (invalid, user-invalid, out-of-range) (0) | 2024.01.06 |
[CSS] 왜 transform 애니메이션 성능이 좋을까? (with. GPU, Reflow) (0) | 2023.11.28 |
키 타입을 보장할 수 있는 Map 객체(주의! array.map 아님) (0) | 2023.10.15 |
댓글