개발 기술/사소하지만 놓치기 쉬운 개발 지식

콘텐츠 접근이 가능한 아코디언을 만들어보자! (with. until-found, details)

by GicoMomg 2024. 2. 13.

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 태그가 아닌, divbutton으로 구현했다.
라이브러리 종류 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)를 다시 접고 싶다면, 클릭 이벤트 발생시 hiddenuntil-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을 사용할 수 있어 자유도가 높으나, 이 또한 모든 브라우저에서 지원하지 않았다ㅠ
  • 만약 해당 기능을 구현한다면 서비스가 목표로 하는 브라우저에 문제가 없는지 확인할 필요가 있다




반응형

댓글