Card stack
Breaks a long screen into cards so the eye can tell where one chunk of content ends and the next starts.
Live preview
Source
<div class="dc-stack">
<a class="dc-stack__card" href="#">
<span class="dc-stack__kicker">오늘 마감</span>
<span class="dc-stack__title">식품 포장 · 평택</span>
<span class="dc-stack__meta">일당 130,000원 · 08:00~17:00</span>
<span class="dc-stack__foot">
<span class="dc-stack__tag">초보 가능</span>
<span class="dc-stack__tag">기숙사</span>
</span>
</a>
<a class="dc-stack__card" href="#">
<span class="dc-stack__title">용접 보조 · 김해</span>
<span class="dc-stack__meta">일당 160,000원 · 주 5일</span>
<span class="dc-stack__foot">
<span class="dc-stack__tag">경력 1년</span>
<span class="dc-stack__tag">통근 버스</span>
</span>
</a>
<a class="dc-stack__card" href="#">
<span class="dc-stack__title">호텔 객실 정리 · 제주</span>
<span class="dc-stack__meta">월급 2,450,000원 · 4대 보험</span>
<span class="dc-stack__foot">
<span class="dc-stack__tag">숙식 제공</span>
</span>
</a>
</div>
.dc-stack {
display: flex; flex-direction: column; gap: var(--dc-3);
font-family: var(--dc-font);
}
.dc-stack__card {
display: flex; flex-direction: column; gap: var(--dc-1);
min-height: 72px; padding: var(--dc-4);
border: 1px solid var(--dc-line); border-radius: var(--dc-r-md);
background: var(--dc-surface); box-shadow: var(--dc-sh-1);
color: var(--dc-text); text-decoration: none;
transition: background var(--dc-fast);
}
.dc-stack__card:active { background: var(--dc-sunken); }
.dc-stack__kicker {
font-size: 11px; font-weight: 800; letter-spacing: .02em;
color: var(--dc-danger);
}
.dc-stack__title { font-size: 16px; font-weight: 700; }
.dc-stack__meta { font-size: 13px; color: var(--dc-text-sub); }
.dc-stack__foot {
display: flex; flex-wrap: wrap; gap: var(--dc-1);
margin-top: var(--dc-2);
}
.dc-stack__tag {
padding: 3px var(--dc-2);
border-radius: var(--dc-r-full);
background: var(--dc-sunken);
font-size: 11px; font-weight: 700; color: var(--dc-text-sub);
}
.dc-stack--overlap { gap: 0; }
.dc-stack--overlap .dc-stack__card {
border-radius: var(--dc-r-lg);
border-color: var(--dc-line-bold);
box-shadow: var(--dc-sh-2);
}
.dc-stack--overlap .dc-stack__card:not(:last-child) {
/* 겹치는 24px 은 아래 여백으로만 덮는다 — 글자가 가려지면 스택이 아니라 버그다 */
padding-bottom: calc(var(--dc-4) + var(--dc-6));
}
.dc-stack--overlap .dc-stack__card + .dc-stack__card {
margin-top: calc(var(--dc-6) * -1);
padding-top: var(--dc-6);
}
.dc-stack--overlap .dc-stack__kicker {
/* 쿠폰 유효기간은 급한 일이 아니다 — 빨강은 '오늘 마감' 에만 쓴다 */
color: var(--dc-text-sub);
}
.dc-stack--grouped {
gap: 0; overflow: hidden;
border: 1px solid var(--dc-line); border-radius: var(--dc-r-md);
background: var(--dc-surface);
}
.dc-stack--grouped .dc-stack__card {
border: 0; border-radius: 0; box-shadow: none;
min-height: 64px; padding: var(--dc-3) var(--dc-4);
}
.dc-stack--grouped .dc-stack__card + .dc-stack__card {
border-top: 1px solid var(--dc-line);
}
How to use it
- One card, one story — if you need a second heading you need a second card
- Keep the gap between cards no smaller than the padding inside them, or they read as one card
- Stack long lists end to end, not overlapping; overlap suits only a few items like coupons or passes
Watch out for
- If the whole card is tappable, don't nest another link inside it
- Use the same shadow on every card — different elevations imply a ranking you didn't mean
- When overlapping, never cover the title line of the card underneath