Shadows (그림자)
Foundation의 그림자 시스템은 4단계 Box Shadow를 제공하여 UI 요소에 깊이감과 계층 구조를 표현합니다.
그림자 철학
Foundation의 그림자는 다음 원칙을 따릅니다:
- Elevation: 그림자로 요소의 높이(elevation) 표현
- Subtle to Strong: sm부터 xl까지 점진적인 깊이감
- Consistency: 모든 컴포넌트가 동일한 그림자 토큰 사용
- Performance: 하드웨어 가속을 고려한 최적화
Shadow Scale
Foundation은 4단계 그림자를 제공합니다.
실제 토큰 값 (core.css)
@theme {
/* Shadows */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
}사용 가이드
| 토큰 | Elevation | 사용 사례 |
|---|---|---|
| sm | 1px | Input, Checkbox, Tag |
| md | 4-6px | Card, Dropdown (기본) |
| lg | 10-15px | Modal, Popover |
| xl | 20-25px | Modal Backdrop, Toast |
사용 방법
CSS Variables로 사용
.card {
box-shadow: var(--shadow-md);
}
.modal {
box-shadow: var(--shadow-xl);
}Tailwind Utility Classes로 사용
<div className="shadow-md">Card with medium shadow</div>컴포넌트별 그림자 가이드
Card
// Default Card
<div className="p-md bg-white border shadow-md rounded-lg">
Card with medium shadow
</div>
// Elevated Card (Hover)
<div className="p-md bg-white shadow-md hover:shadow-lg transition-shadow rounded-lg">
Card with hover effect
</div>Button
// Primary Button with subtle shadow
<button className="px-md py-sm bg-primary text-white shadow-sm rounded">
Primary Button
</button>
// Elevated Button
<button className="px-md py-sm bg-white border shadow-md hover:shadow-lg rounded">
Elevated Button
</button>Modal
export default function Modal() {
return (
<>
{/* Backdrop */}
<div className="fixed inset-0 bg-black bg-opacity-50" />
{/* Modal */}
<div className="fixed inset-0 flex items-center justify-center p-md">
<div className="bg-white rounded-lg shadow-xl max-w-md w-full p-lg">
<h2 className="text-2xl font-bold mb-md">Modal Title</h2>
<p className="text-gray-600">Modal content</p>
</div>
</div>
</>
);
}Dropdown
export default function Dropdown() {
return (
<div className="relative">
<button className="px-md py-sm bg-white border rounded">Open Menu</button>
{/* Dropdown Menu */}
<div className="absolute top-full left-0 mt-xs bg-white border rounded-lg shadow-lg py-sm min-w-[200px]">
<a href="#" className="block px-md py-sm hover:bg-gray-50">
Menu Item 1
</a>
<a href="#" className="block px-md py-sm hover:bg-gray-50">
Menu Item 2
</a>
<a href="#" className="block px-md py-sm hover:bg-gray-50">
Menu Item 3
</a>
</div>
</div>
);
}Hover & Focus States
Card Hover Effect
<div className="p-md bg-white shadow-md hover:shadow-xl transition-shadow duration-200 rounded-lg cursor-pointer">
Hover me for elevated shadow
</div>Button Focus State
<button className="px-md py-sm bg-primary text-white rounded shadow-sm focus:shadow-md focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2">
Focus me
</button>실전 예제
Product Card
export default function ProductCard() {
return (
<div className="bg-white rounded-lg shadow-md hover:shadow-xl transition-shadow duration-300 overflow-hidden">
<img
src="/product.jpg"
alt="Product"
className="w-full h-48 object-cover"
/>
<div className="p-md">
<h3 className="text-xl font-semibold mb-sm">Product Name</h3>
<p className="text-gray-600 mb-md">Product description</p>
<button className="w-full px-md py-sm bg-primary text-white rounded shadow-sm">
Add to Cart
</button>
</div>
</div>
);
}Toast Notification
export default function Toast() {
return (
<div className="fixed bottom-md right-md bg-white rounded-lg shadow-xl p-md max-w-sm">
<div className="flex items-start gap-md">
<div className="flex-1">
<h4 className="font-semibold text-gray-900">Success</h4>
<p className="text-sm text-gray-600 mt-xs">
Operation completed successfully
</p>
</div>
<button className="text-gray-400 hover:text-gray-600">×</button>
</div>
</div>
);
}접근성 고려사항
그림자와 대비
그림자만으로는 접근성을 보장할 수 없습니다. Border나 Background Color를 함께 사용하세요.
// ❌ 그림자만 사용
<div className="shadow-md">Content</div>
// ✅ Border와 함께 사용
<div className="shadow-md border border-gray-200">Content</div>Reduced Motion
애니메이션 그림자 효과는 prefers-reduced-motion을 고려하세요.
@media (prefers-reduced-motion: reduce) {
* {
transition-duration: 0ms !important;
}
}다음 단계
Last updated on