스타일 지정 옵션 더보기 <details>

게시일: 2024년 11월 6일

Chrome 131부터 <details><summary> 요소의 구조에 스타일을 지정할 수 있는 옵션이 더 많아졌습니다. 이제 공개 또는 악셀러레이드 위젯을 빌드할 때 이러한 요소를 사용할 수 있습니다.

특히 Chrome 131에서 도입된 변경사항을 통해 이러한 요소에 display 속성을 사용할 수 있으며 ::details-content 가상 요소를 추가하여 펼치고 접을 수 있는 부분의 스타일을 지정할 수 있습니다.

브라우저 지원

  • Chrome: 131
  • Edge: 지원되지 않음
  • Firefox: 지원되지 않음
  • Safari: 지원되지 않음

<details> 요소에서 display 설정

이전에는 <details> 요소의 디스플레이 유형을 변경할 수 없었습니다. 이제 이 제한이 완화되어 <details> 요소에서 그리드 또는 Flex 레이아웃을 사용할 수 있습니다.

다음 예에서 배타적 아코디언은 나란히 배치된 여러 <details> 요소로 구성됩니다. <details> 요소 중 하나를 펼치면 콘텐츠가 <summary> 옆에 배치됩니다.

데모

녹화

Chrome 131에서 https://codepen.io/web-dot-dev/pen/VwoBQjY 녹화

다음 CSS를 사용하여 <details> 요소에 플렉스 레이아웃을 사용하면 됩니다.

details {
  display: flex;
  flex-direction: row;
}

다른 표시 값(예: grid)도 허용됩니다.

display: inline 사용에 관한 메모

예기치 않은 결과를 가질 수 있는 display 값은 inline입니다. 작동하지 않기 때문이 아니라 HTML 파서 제한 때문입니다.

<details> 요소를 단락 내에 배치하면 HTML 표준 13.2.6.4.7 섹션에 정의된 대로 HTML 파서가 먼저 열려 있는 단락을 닫습니다.

태그 이름이 'address', 'article', 'aside', 'blockquote', 'center', 'details', 'dialog', 'dir', 'div', 'dl', 'fieldset', 'aosp', 'figure', 'fieldset', 'aosp', 'figure', 'section', 'menu', 'mainhgroup', ''summary', 'article', 'menu', '

열려 있는 요소 스택에 버튼 범위 내에 p 요소가 있으면 p 요소를 닫습니다. 토큰의 HTML 요소를 삽입합니다.

따라서 display: inline를 설정했는지와 관계없이 <details>가 블록 방향으로 흐릅니다.

예를 들어 다음 마크업을 들 수 있습니다.

<p>Hello <details>…</details> world</p>

파싱 후 다음과 같이 됩니다.

<p>Hello </p><details>…</details> world<p></p>

Chrome DevTools를 사용하여 파싱된 마크업을 검사하여 이 데모에서 직접 확인할 수 있습니다.

이는 <p> 내부에서 <details>를 중첩하는 경우에만 적용됩니다. <div> 내의 <details>에서 display: inline를 사용하면 됩니다.

::details-content 의사

브라우저에서 <details> 요소는 Shadow DOM을 사용하여 구현됩니다. 요약의 <slot>(기본 요약 하위 요소 포함) 1개와 나머지 모든 콘텐츠의 <slot>(<summary> 요소를 제외한 <details> 요소의 모든 하위 요소) 1개를 포함합니다.

<details>
  ↳ #shadow-root (user-agent)
      <slot id="details-summary">
        <summary>Details</summary>
        <!-- The summary goes here -->
      </slot>
      <slot id="details-content">
        <!-- All content goes here -->
      </slot>
</details>

이제 <details>에서 더 많은 디스플레이 유형을 사용할 뿐만 아니라 ::details-content 가상 요소를 사용하여 콘텐츠 슬롯을 타겟팅할 수 있습니다. 이 가상 요소를 사용하여 <details> 요소의 콘텐츠를 래핑하는 컨테이너의 스타일을 지정할 수 있습니다.

details::details-content {
  border: 5px dashed hotpink;
}

<details> 요소가 열린 상태일 때만 설정된 스타일을 적용하려면 [open] 선택기를 앞에 추가합니다.

[open]::details-content {
  border: 5px dashed hotpink;
}

<details> 요소가 [open] 상태일 때만 ::details-content 가상 요소에 스타일을 적용하는 것이 좋습니다.

데모

녹화

Chrome 131에서 https://codepen.io/web-dot-dev/pen/oNKMEYv 녹화

::details-contentdisplay 유형이 UA 스타일 시트에서 block로 설정되었으며 이전에는 display: contents였습니다. 이 변경사항은 height: 100%를 사용하는 공개 콘텐츠와 같이 경우에 따라 불리하게 작용할 수 있습니다. 이 문제가 발생하는 경우 display 유형을 contents로 다시 설정하여 문제를 해결할 수 있습니다(예: details[open]::details-content { display: contents; }).

::details-content 의사에 애니메이션 적용

<details> 요소가 확장될 때 콘텐츠의 애니메이션을 적용할 수 있습니다. 다음 예에서는 너비가 0px에서 300px로 애니메이션됩니다.

::details-content {
  transition: width 0.5s ease, content-visibility 0.5s ease allow-discrete;
  width: 0;
}

[open]::details-content {
  width: 300px;
}

width를 전환하는 것 외에도 content-visibility 속성도 전환해야 합니다. 이는 User-Agent 스타일 시트에 정의된 대로 값이 열지 않은 상태와 열려 있는 상태 간에 변경되기 때문입니다. 이 속성은 개별적으로 애니메이션할 수 있는 속성이므로 작동하려면 allow-discrete 키워드가 필요합니다.

이전에 공유된 독점 아코디언 데모에 추가하면 다음과 같은 결과가 나옵니다.

데모

녹화

Chrome 131에서 https://codepen.io/web-dot-dev/pen/XWvBZNo 녹화본

height는 애니메이션 처리할 수도 있습니다. height: auto로 애니메이션을 적용하려면 interpolate-size 또는 calc-size()를 사용해야 합니다. 또한 콘텐츠가 ::details-content 의사에서 표시되지 않도록 하려면 overflow: clip를 적용합니다.

::details-content {
    transition: height 0.5s ease, content-visibility 0.5s ease allow-discrete;
    height: 0;
    overflow: clip;
}

/* Browser supports interpolate-size */
@supports (interpolate-size: allow-keywords) {
    :root {
        interpolate-size: allow-keywords;
    }

    [open]::details-content {
        height: auto;
    }
}

/* Fallback for browsers with no interpolate-size support */
@supports not (interpolate-size: allow-keywords) {
    [open]::details-content {
        height: 150px;
        overflow-y: scroll; /* In case the contents should be taller than 150px */
    }
}

머티리얼 UI의 아코디언에서 영감을 받은 다음 데모에서 실제 코드를 확인할 수 있습니다. 각 <details> 요소의 콘텐츠가 멋진 애니메이션을 적용합니다.

데모

녹화

Chrome 131에서 https://codepen.io/web-dot-dev/pen/ExqpQZM 녹화본

::details-content를 지원하지 않는 브라우저에서도 구성요소는 계속 잘 작동합니다. 방문자에게는 애니메이션만 표시되지 않습니다.

기능 감지

CSS에서 ::details-content 가상의 지원을 기능 감지하려면 다음 스니펫을 사용하세요.

@supports selector(::details-content) {
  
}

또한 이 감지를 사용하여 방문자가 사용 중인 브라우저가 추가 표시 값을 지원하는지 여부를 알 수 있습니다.

접근성 고려사항

::details-content 가상 요소와 디스플레이 유형을 변경하는 기능의 도입은 <details> 요소의 접근성에는 영향을 미치지 않습니다.

이전과 마찬가지로 적어도 Chromium 기반 브라우저 및 HTML 표준에 따라 <details> 요소는 검색 가능하며 브라우저에서 페이지 내 찾기, ScrollToTextFragment, 요소 프래그먼트 탐색에 대한 응답으로 숨겨진 콘텐츠로 스크롤하려고 할 때 자동으로 확장됩니다. 이러한 상황은 바뀌지 않습니다.

하지만 독점 아코디언을 사용하기 전에 사용자에게 도움이 될지 해가 될지 고려해 보세요. 전용 아코디언을 사용하면 콘텐츠가 차지하는 시각적 공간의 양이 줄어들지만, 사용자가 모든 정보를 소비하려면 여러 항목을 열어야 할 수 있습니다. 이렇게 하면 여러 상품을 동시에 보려는 사용자가 실망할 수 있습니다.

마커 스타일은 어떻게 지정하나요?

현재 목록 마커의 스타일 지정은 상호 운용되지 않습니다. Gecko 및 (현재) Chromium에서 사용하는 접근 방식과 WebKit에서 사용하는 접근 방식 (이전에는 Chromium과 공유됨)이 서로 다르기 때문입니다.

이 기능이 상호 운용되면 마커 스타일을 더 효과적으로 제어할 수 있도록 할 계획입니다.

데모 더보기

마지막으로 몇 가지 데모를 확인해 보세요. 모두 ::details-content를 사용합니다.

UIKit 아코디언

데모

녹화

Chrome 131에서 https://codepen.io/web-dot-dev/pen/rNXrJyQ 녹화

이 데모는 UIKit Accordion을 기반으로 빌드됩니다. 이 코드는 이전에 공유된 Material UI 아코디언과 거의 동일합니다.

부분적으로 열린 공개 위젯

데모

녹화

Chrome 131에서 https://codepen.io/web-dot-dev/pen/PoMBQmW 녹화

이 데모에는 콘텐츠가 이미 화면에 표시되고 있는 부분적으로 열린 공개 위젯이 있습니다. 이를 위해 content-visibility가 항상 visible로 설정됩니다. 계산이 포함되어 있으므로 heightcalc-size()를 사용하여 애니메이션 처리됩니다.

::details-content {
  content-visibility: visible; /* Make it always visible */
    
  transition: height 0.5s ease;
  height: 150px;
  overflow: clip;
}

[open]::details-content {
  height: calc-size(auto, size + 0.5rem); /* calc-size because we need to add a length */
}

스타일 지정을 편리하게 하기 위해 콘텐츠가 래퍼 div로 래핑됩니다. 래퍼 div는 padding와 같은 레이아웃 스타일을 적용받고 ::details-content 가상 요소에 애니메이션이 적용됩니다.