개요
카드는 관련된 콘텐츠 하나 또는 선택 항목 하나를 그룹화합니다. 고정된 시맨틱 또는 상호작용 모델이 아닌 시각적 패턴이므로 콘텐츠의 의미를 보존하고 목적에 맞는 네이티브 상호작용을 사용하세요.
가이드라인
콘텐츠와 상호작용의 시맨틱을 별도로 선택합니다.
- 대상에 연결되는지 여부와 관계없이
<article>를 카드 루트로 사용합니다. - 탐색에 네이티브 링크를 사용합니다. 전체 카드가 하나의 도착 페이지인 경우 카드에 다른 상호작용 요소 (
a,button,input,select,textarea)가 포함되지 않은 경우에만 단일 링크가<article>를 래핑할 수 있습니다. - 독립적인 작업을 위한 링크와 버튼은 별도의 네이티브 컨트롤로 유지합니다.
- 카드가 선택 항목인 경우 연결된
<label>가 있는 라디오 버튼 또는 체크박스나 네이티브<select>의option를 사용합니다.
미디어, 제목, 지원 콘텐츠, 액션을 의미 있는 소스 순서로 유지합니다. CSS order를 사용하여 이를 모순되게 만들지 마세요(CSS 레이아웃 및 반응형 디자인 참고).
구현
마크업을 최소화하고 CSS 선택자가 각 영역을 인식하도록 하여 간단한 카드는 간단하게 유지하고 더 풍부한 리치 카드는 가능하게 합니다. 카드에는 이 소스 순서대로 최대 4개의 영역이 있으며, 이 중 하나를 생략할 수 있습니다. 영역은 카드의 직접 하위 요소이며 .card__body와 같은 래퍼 요소로 그룹화되지 않으므로 선택기로 영역을 배치하고 스타일을 지정할 수 없습니다. 단일 요소가 있는 영역은 래핑되지 않은 요소 자체입니다. 단일 단락은 <p>입니다. 래퍼는 영역에 여러 요소가 있는 경우에만 사용합니다.
- 미디어: 첫 번째 하위 요소로
<img>,<picture>,<video>또는<svg>입니다. 이러한 요소 중 하나가 아닌 임의의 히어로 콘텐츠에만.media클래스를 추가하고 일반<img>를.media요소로 래핑하지 마세요. - 헤더: 제목 자체입니다. 제목에 부제목 또는 소개 문구가 있는 경우에만
<hgroup>를 사용하고, 영역에 바이라인 또는 배지와 같이 제목 이상의 내용이 포함된 경우<header>를 사용합니다. 카드에 기본 도착 페이지가 있는 경우 링크는 제목 내부에 표시됩니다. - 콘텐츠: 단일
<p>,<ul>또는<dl>가 독립적으로 존재합니다. 콘텐츠가 여러 단락 또는 단락과 목록과 같은 여러 요소인 경우 영역이 단일 그리드 항목이 되도록 하나의<div>로 그룹화합니다. - 바닥글: 독립적인 작업을 네이티브 링크 및 버튼으로 보유하는
<footer>입니다. '더보기' 링크는 제목 링크의 URL을 공유할 수 있지만, 동일한 '더보기' 링크는 스크린 리더의 링크 목록에서 모호하므로 시각적으로 숨겨진 텍스트 (예:Read more<span> about poached eggs</span>)를 사용하여 표시되는 텍스트로 시작하는 설명이 포함된 액세스 가능한 이름을 지정합니다. 제목의 URL을 반복하는 다른 바닥글 링크를 추가하지 마세요.
가장 간단한 카드는 제목과 단락이 포함된 <article>입니다. 카드의 동작과 일치하는 링크 및 작업 패턴을 선택합니다. 상호작용 모델을 참고하세요.
고정 비율 영역을 채워야 하는 카드 이미지나 동영상의 경우 <img> 또는 <video> 자체에 aspect-ratio 및 object-fit: cover를 설정하여 왜곡 없이 영역을 채우도록 합니다 (자르기가 발생할 수 있음). .media 컨테이너의 aspect-ratio는 다른 히어로 콘텐츠에만 사용합니다. 그렇지 않으면 미디어의 고유 비율을 유지합니다. 정보를 제공하는 이미지에는 적절한 대체 텍스트를 제공하고 장식용 이미지에는 alt=""를 사용합니다.
사용 가능한 공간에 맞게 조정
표시 영역이 아닌 카드의 사용 가능한 공간을 기준으로 레이아웃을 지정합니다. 카드의 하위 요소 (미디어, 텍스트, 작업)를 조정하려면 카드를 크기 컨테이너 (container-type: inline-size)로 만들고 하위 요소에 대해 @container 규칙을 작성합니다. 그리드 또는 목록 상위 요소에서 크기를 조정하지 마세요. 카드의 실제 너비는 열 수, 간격 등에 따라 달라질 수 있으므로 상위 요소 기반 중단점은 노이즈가 많습니다.
좁은 컨테이너에서는 소스 순서대로 영역을 쌓습니다. 넓은 컨테이너에서는 미디어를 다른 영역 옆의 측면 열에 배치하되, 미디어가 있는 카드에만 배치합니다. 미디어 하위 요소 (예: .card:has(> img))에 :has()를 사용하여 이러한 규칙의 범위를 지정하여 열 정의와 grid-column 배치가 미디어가 없는 카드에 적용되지 않도록 합니다. 미디어가 없는 카드는 모든 너비에서 단일 열로 유지되며 빈 미디어 열을 예약해서는 안 됩니다.
그리드에 카드 정렬
한 행의 카드가 영역의 높이를 공유해야 하는 경우 subgrid를 사용합니다. 각 카드가 공유 행 트랙 4개 (미디어, 헤더, 콘텐츠, 바닥글)에 걸쳐 있도록 하고 요소 선택기로 영역을 배치하여 미디어, 제목 또는 <footer>가 아닌 모든 항목을 콘텐츠로 처리합니다. 리전을 생략하는 카드는 트랙을 비워 두므로 나머지 리전은 여전히 인접한 카드와 정렬됩니다. 각 트랙에는 하나의 그리드 항목이 포함되므로 콘텐츠 영역에 요소가 두 개 이상 있고 카드가 트랙을 공유하는 경우에만 콘텐츠 영역을 <div>로 래핑합니다. 동위 요소와 정렬되지 않은 카드에는 래퍼나 하위 그리드가 필요하지 않습니다.
상호작용 모델
콘텐츠 카드
<article>를 카드 루트로 사용합니다. 링크와 버튼은 별도의 네이티브 컨트롤로 유지합니다.
단일 도착지 카드
전체 카드가 하나의 도착 페이지이고 독립적인 작업이 없는 경우 하나의 네이티브 링크를 사용합니다. 링크는 <article>를 래핑할 수 있습니다. 링크 내에 다른 링크, 버튼 또는 양식 컨트롤을 중첩하지 말고 '자세히 알아보기' 텍스트는 일반 <p> 또는 <span>로 유지합니다. 링크의 액세스 가능한 이름은 카드의 모든 텍스트이므로 콘텐츠를 짧게 유지하세요. 카드에 텍스트나 다른 작업이 많은 경우 아래의 확장된 링크 패턴을 사용하여 제목만 링크로 만드세요.
<a href="/recipes/poached-eggs">
<article class="card">
<h3>Poached eggs</h3>
<p>Two poached eggs served on toasted sourdough.</p>
</article>
</a>
독립적인 작업이 있는 클릭 가능한 카드
카드를 클릭할 때 탐색이 아닌 작업이 트리거되는 경우 링크 대신 <button>를 사용합니다.
콘텐츠 카드가 기본 도착 페이지에 연결되고 다른 상호작용 요소도 포함하며 전체를 클릭할 수 있어야 하는 경우:
- 기본 링크 자체에 단일 선택을 사용합니다. 카드당 정확히 하나의 링크 (제목 링크)에
.card-link를 배치합니다. 바닥글 및 기타 링크는 포커스를 받지 않거나, 각 링크가 자체 오버레이를 확장하고 마지막 링크가 전체 카드를 캡처합니다. ::after를 사용하여 제목을 연결하고 포인터 히트 영역을 카드 전체로 확장합니다.
.card:has(a.card-link) {
position: relative;
}
.card a.card-link::after {
content: "";
position: absolute;
inset: 0;
}
- 상호작용 요소가 계속 작동하도록
position: relative; z-index: 1를 사용하여 상호작용 요소를 높입니다. 클래스를 통한 선택을 요구하는 대신 요소의 타겟 유형 (예:a, button)을 지정합니다. - 전체 컨테이너에
z-index를 적용하지 마세요. 그러면 아무 작업도 생성하지 않는 포인터 이벤트를 캡처하게 됩니다.
.card:has(a.card-link) {
/* Keep other interactive elements above the overlay */
a:not(.card-link), button, input, x-button {
position: relative;
z-index: 1;
}
}
- 확장된 링크가 아닌 마우스 오버/포커스 시 카드 자체의 스타일을 지정합니다.
.card {
a.card-link {
&:focus-visible {
outline: none; /* Draw it on the card instead */
}
}
&:has(a.card-link:focus-visible) {
/* Focus ring */
}
&:has(a.card-link:hover) {
/* Hover styles */
}
}
선택 카드
사전 정의된 선택사항을 나타내는 카드의 경우 체크박스 또는 라디오를 직접 하위 요소로 사용하는 <label class="card">를 사용합니다.
:has(:checked)를 사용하여 선택한 카드의 스타일을 지정합니다. 선택 시 border-width, padding, font-weight와 같이 레이아웃에 영향을 미치는 속성은 변경하지 마세요. 카드와 인접한 카드가 점프하기 때문입니다. outline, box-shadow 또는 색상만 변경되는 투명한 테두리를 사용하여 강조를 표시하세요.
.card {
border: 2px solid transparent;
&:has(> :checked) {
border-color: var(--accent);
}
}
표시되는 체크박스 또는 라디오 버튼 자체가 선택 여부를 나타내는 색상 외 표시기이므로 색상 변경만으로도 충분합니다. 컨트롤이 시각적으로 숨겨져 있는 경우 (포커스 가능 상태로 유지하고 접근성 트리에 유지, display: none 사용 안함) 체크 아이콘이나 더 두꺼운 outline과 같이 레이아웃에 영향을 주지 않는 색상이 아닌 표시기를 추가합니다.
선택사항이 드롭다운 선택 도구에 속하고 옵션이 카드로 배치된 경우 선택사항을 <div> 카드로 대체하는 대신 appearance: base-select가 있는 네이티브 <select>를 사용하고 ::picker(select) 및 <option> 요소의 스타일을 지정합니다. 자세한 내용과 대체 방법은 맞춤 선택 도구 레이아웃을 참고하세요.