box-shadow는 요소 상자 주위에 그림자를 그립니다. 최대 4가지 길이와 색상(box-shadow: x y blur spread colour)을 지정할 수 있습니다. 소프트 카드 섀도우의 경우 box-shadow: 0 4px 12px rgba(0, 0, 0, .15)가 좋은 시작입니다.
슬라이더를 움직여 상자를 살펴보세요. 맨 아래 줄은 복사할 CSS입니다.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Box shadow generator</title>
<style>
body {
margin: 0; padding: 16px;
font-family: system-ui, sans-serif; background: #eef1f5; color: #1d2330;
}
.wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; max-width: 640px; margin: 0 auto; }
@media (max-width: 520px) { .wrap { grid-template-columns: 1fr; } }
.stage {
display: grid; place-items: center; min-height: 200px;
background: #f8fafc; border-radius: 12px;
}
.box { width: 120px; height: 120px; border-radius: 16px; background: #fff; }
.controls { display: grid; gap: 8px; }
label { display: grid; grid-template-columns: 64px 1fr 44px; align-items: center; gap: 8px; font-size: 14px; }
label span:last-child { text-align: right; font-variant-numeric: tabular-nums; }
input[type=range] { width: 100%; }
.check { grid-template-columns: auto 1fr; }
pre {
grid-column: 1 / -1; margin: 0; padding: 12px 14px; border-radius: 10px;
background: #1d2330; color: #e5e7eb; font: 14px/1.4 ui-monospace, Consolas, monospace;
white-space: pre-wrap; word-break: break-word;
}
</style>
</head>
<body>
<div class="wrap">
<div class="stage"><div class="box" id="box"></div></div>
<form class="controls" id="form">
<label>x <input type="range" name="x" min="-40" max="40" value="0"><span></span></label>
<label>y <input type="range" name="y" min="-40" max="40" value="8"><span></span></label>
<label>blur <input type="range" name="blur" min="0" max="80" value="24"><span></span></label>
<label>spread <input type="range" name="spread" min="-30" max="30" value="0"><span></span></label>
<label>opacity <input type="range" name="alpha" min="0" max="100" value="20"><span></span></label>
<label class="check"><input type="checkbox" name="inset"> inset (draw inside the box)</label>
</form>
<pre id="out"></pre>
</div>
<script>
const form = document.getElementById('form');
const box = document.getElementById('box');
const out = document.getElementById('out');
function update() {
const v = Object.fromEntries(new FormData(form)); // checkbox is missing when unchecked
// show each slider's value next to it
form.querySelectorAll('input[type=range]').forEach((r) => {
r.nextElementSibling.textContent = r.name === 'alpha' ? r.value + '%' : r.value + 'px';
});
const shadow = (v.inset ? 'inset ' : '') +
`${v.x}px ${v.y}px ${v.blur}px ${v.spread}px rgba(0, 0, 0, ${v.alpha / 100})`;
box.style.boxShadow = shadow;
out.textContent = `box-shadow: ${shadow};`;
}
form.addEventListener('input', update);
update();
</script>
</body>
</html>
그림자는 요소의 둥근 모서리를 유지합니다. 여기 상자에는 border-radius: 16px가 있으며 그림자는 추가 코드 없이 해당 곡선을 따릅니다.
각 값의 역할
각 값은 한 가지를 제어하며 항상 동일한 순서로 나타납니다.

| 가치 | 필수 | 기능 | 음수 값 |
|---|---|---|---|
| 오프셋-x | 예 | 그림자를 옆으로 이동합니다. | 왼쪽으로 이동 |
| 오프셋 Y | 예 | 그림자를 아래로 이동합니다. | 위로 이동 |
| 흐림 | 아니요, 기본값은 0입니다. | 가장자리를 부드럽게 한다 | 허용되지 않음 |
| 퍼지다 | 아니요, 기본값은 0입니다. | 흐리게 하기 전에 그림자를 성장시킵니다. | 축소 |
| 색깔 | 아니요 | 그림자 색상 | – |
inset |
아니요 | 상자 안에 그림자를 그립니다. | – |
색상을 생략하면 그림자는 요소의 텍스트 색상(currentColor)을 사용합니다. 어쨌든 써서 텍스트 색상이 바뀔 때 그림자가 변하지 않도록 하세요.
스프레드는 사람들이 건너뛰는 가치이며 가장 특이한 작업을 수행합니다. 음수 스프레드는 요소 아래에 그림자를 집어넣어 오프셋 면만 표시되도록 합니다. 흐림 효과가 없는 스프레드는 단색 고리를 그립니다.
/* shadow only below */
.bar { box-shadow: 0 8px 6px -6px rgba(0, 0, 0, .3); }
/* a 2px ring that takes no layout space */
.ring { box-shadow: 0 0 0 2px #2563eb; }
복사할 사전 설정 6개
대부분의 인터페이스에는 소수의 그림자만 필요합니다. 다음은 같은 타일에 있는 6개의 공통 항목입니다.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Box shadow presets</title>
<style>
body {
margin: 0; padding: 16px;
font-family: system-ui, sans-serif; background: #eef1f5; color: #1d2330;
}
.grid {
display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 28px 20px; max-width: 640px; margin: 0 auto;
}
figure { margin: 0; }
.tile {
height: 90px; border-radius: 12px; background: #fff;
display: grid; place-items: center; font-weight: 600;
}
figcaption { margin-top: 10px; font: 12px/1.4 ui-monospace, Consolas, monospace; color: #475569; }
/* the six presets */
.subtle { box-shadow: 0 1px 3px rgba(0, 0, 0, .12); }
.raised { box-shadow: 0 4px 12px rgba(0, 0, 0, .15); }
.floating { box-shadow: 0 20px 40px -12px rgba(0, 0, 0, .35); }
.pressed { background: #e8ecf1; box-shadow: inset 0 2px 6px rgba(0, 0, 0, .25); }
.glow { background: #0f172a; color: #fff; box-shadow: 0 0 24px 4px rgba(56, 189, 248, .6); }
.layered {
box-shadow:
0 1px 2px rgba(0, 0, 0, .08),
0 4px 8px rgba(0, 0, 0, .08),
0 16px 32px rgba(0, 0, 0, .10);
}
</style>
</head>
<body>
<div class="grid">
<figure><div class="tile subtle">Subtle card</div>
<figcaption>0 1px 3px rgba(0,0,0,.12)</figcaption></figure>
<figure><div class="tile raised">Raised</div>
<figcaption>0 4px 12px rgba(0,0,0,.15)</figcaption></figure>
<figure><div class="tile floating">Floating</div>
<figcaption>0 20px 40px -12px rgba(0,0,0,.35)</figcaption></figure>
<figure><div class="tile pressed">Inner / pressed</div>
<figcaption>inset 0 2px 6px rgba(0,0,0,.25)</figcaption></figure>
<figure><div class="tile glow">Glow</div>
<figcaption>0 0 24px 4px rgba(56,189,248,.6)</figcaption></figure>
<figure><div class="tile layered">Layered</div>
<figcaption>0 1px 2px rgba(0,0,0,.08),<br>0 4px 8px rgba(0,0,0,.08),<br>0 16px 32px rgba(0,0,0,.10)</figcaption></figure>
</div>
</body>
</html>
- 미묘함은 카드와 테이블 행을 쉬게 하는 데 사용됩니다. 그림자가 아니라 가장자리를 주목하세요.
- 올려진 부분은 페이지 위에 있는 버튼과 패널에 맞습니다.
- 플로팅은 네거티브 스프레드를 사용하므로 그림자가 타일 아래에 머무르고 바닥에 모입니다.
- 눌림은
inset를 사용합니다. 마치 타일을 밀어 넣은 것처럼 그림자가 상단 가장자리 안쪽으로 떨어집니다. - 빛은 오프셋이 없는 색상이 있는 그림자입니다. 보여주기 위해서는 어두운 표면이 필요합니다.
- 레이어형은 세 개의 밝은 그림자를 쌓습니다. 다음에 다룹니다.
레이어드 섀도우가 더 부드러워보이네요
하나의 어두운 그림자는 회색 스티커처럼 보이는 경향이 있습니다. 실제 그림자는 물체에 가까울수록 선명하고 어두워지며, 물체에서 멀어질수록 희미해집니다. 그림자를 2~3개 쌓는 것이 그것을 흉내낸다.
.card {
box-shadow:
0 1px 2px rgba(0, 0, 0, .08), /* tight contact shadow */
0 4px 8px rgba(0, 0, 0, .08),
0 16px 32px rgba(0, 0, 0, .10); /* wide, faint ambient shadow */
}
각 레이어는 이전 레이어보다 더 큰 오프셋과 흐림 효과를 가지며 불투명도를 낮게 유지합니다. 쉼표는 그림자를 구분합니다. 목록의 첫 번째 항목이 맨 위에 그려집니다.
사용자 정의 속성으로 저장된 전체 고도 스케일에 대해서는 필터 버전도 비교하는 CSS 그림자 대 상자 그림자를 참조하세요.
그림자 삽입
inset를 추가하면 테두리 외부가 아닌 패딩 상자 내부에 그림자가 그려집니다. 오프셋은 여전히 동일한 방식으로 작동하므로 inset 0 2px 6px는 상단 내부 가장자리를 어둡게 만듭니다.
.input:focus { box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2), 0 0 0 3px #93c5fd; }
내부 및 외부 그림자는 하나의 목록에 포함될 수 있습니다. 위의 예는 텍스트 필드에 움푹 들어간 모양과 포커스 링을 동시에 제공합니다.
호버 시 그림자 애니메이션
box-shadow를 전환할 수 있습니다. 브라우저는 목록의 각 그림자를 다른 상태의 동일한 위치에 있는 그림자와 혼합합니다.
쌍 중 하나가 inset이고 다른 하나는 그렇지 않은 경우 해당 쌍은 혼합될 수 없으며 섀도우는 한 번에 전환됩니다. 동일한 수의 그림자를 동일한 순서로 유지하면 혼합을 예측할 수 있습니다.
카드에 마우스를 올리거나 Tab 키를 눌러 키보드로 카드에 접근하세요.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Cards that lift on hover</title>
<style>
body {
margin: 0; padding: 24px 16px;
font-family: system-ui, sans-serif; background: #eef1f5; color: #1d2330;
}
.cards {
display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
gap: 20px; max-width: 640px; margin: 0 auto;
}
.card {
display: block; padding: 18px; border-radius: 14px;
background: #fff; color: inherit; text-decoration: none;
/* resting: two soft layers */
box-shadow: 0 1px 2px rgba(0, 0, 0, .08), 0 2px 6px rgba(0, 0, 0, .06);
transition: box-shadow .25s ease, transform .25s ease;
}
/* lifted: the same two layers, larger and further down */
.card:hover,
.card:focus-visible {
box-shadow: 0 4px 8px rgba(0, 0, 0, .08), 0 18px 36px rgba(0, 0, 0, .14);
transform: translateY(-4px);
outline: none;
}
.card:focus-visible { box-shadow: 0 0 0 3px #2563eb, 0 18px 36px rgba(0, 0, 0, .14); }
.card h3 { margin: 10px 0 6px; font-size: 17px; }
.card p { margin: 0; font-size: 14px; line-height: 1.45; color: #475569; }
.icon { width: 36px; height: 36px; border-radius: 10px; }
@media (prefers-reduced-motion: reduce) {
.card { transition: none; }
}
</style>
</head>
<body>
<div class="cards">
<a class="card" href="#">
<div class="icon" style="background: linear-gradient(135deg, #60a5fa, #2563eb)"></div>
<h3>Starter</h3><p>Hover or press Tab to lift this card.</p>
</a>
<a class="card" href="#">
<div class="icon" style="background: linear-gradient(135deg, #34d399, #059669)"></div>
<h3>Team</h3><p>The shadow grows and the card moves up 4px.</p>
</a>
<a class="card" href="#">
<div class="icon" style="background: linear-gradient(135deg, #fbbf24, #d97706)"></div>
<h3>Business</h3><p>Both states have two shadows, so they blend smoothly.</p>
</a>
</div>
</body>
</html>
.card {
box-shadow: 0 1px 2px rgba(0, 0, 0, .08), 0 2px 6px rgba(0, 0, 0, .06);
transition: box-shadow .25s ease, transform .25s ease;
}
.card:hover,
.card:focus-visible {
box-shadow: 0 4px 8px rgba(0, 0, 0, .08), 0 18px 36px rgba(0, 0, 0, .14);
transform: translateY(-4px);
}
:hover가 아닌 휴지 규칙에 transition를 배치하면 카드도 다시 내려오게 됩니다. CSS 호버 전환에서 이유를 설명합니다. 예제의 prefers-reduced-motion 쿼리는 시스템에 움직임을 줄여달라고 요청하는 사람들을 위해 동작을 끕니다.
그림자를 변경하면 요소가 다시 그려집니다. 카드 몇 장이면 괜찮습니다. 긴 그리드의 경우 공통 패턴은 ::after 의사 요소에 큰 그림자를 배치하고 대신 opacity를 전환합니다.
상자 그림자 또는 그림자
box-shadow는 border-radius를 포함하여 항상 요소의 상자를 따릅니다. 내부에 무엇이 있는지 결코 보지 않습니다. 따라서 투명한 PNG 로고나 SVG 아이콘은 주위에 직사각형의 그림자를 갖게 됩니다.
filter: drop-shadow()는 대신 보이는 픽셀을 추적합니다. 스프레드나 인서트가 없으므로 카드를 대체할 수 없습니다. CSS 드롭 섀도우는 언제 도달해야 하는지를 다룹니다.
작동하지 않을 때
두 번의 실패에는 그림이 필요합니다. 첫 번째는 overflow: hidden가 있는 상위 항목으로, 그림자를 포함하여 상자 외부에 칠해진 모든 항목을 클립합니다.

두 번째는 강조 표시된 <span>와 같은 인라인 요소의 그림자로, 두 줄로 묶입니다. 기본적으로 브라우저는 행을 하나의 상자 조각으로 처리합니다.

.highlight {
-webkit-box-decoration-break: clone; /* some browsers still need the prefix */
box-decoration-break: clone;
}
| 당신이 보는 것 | 원인 | 수정 |
|---|---|---|
| 그림자가 일부 면에서 납작하게 잘립니다. | 상위 항목에 overflow: hidden(또는 auto)가 있습니다. |
상위 요소에 패딩을 추가하거나 overflow를 내부 요소로 이동하세요. |
| 어두운 페이지에는 그림자가 보이지 않습니다 | 검은색에 가까운 표면의 검은 그림자 | 카드 표면을 밝게 하거나, 컬러 광선을 사용하거나, 희미한 조명 테두리를 추가합니다. 다크 모드 CSS를 참조하세요. |
래핑된 <span>의 그림자가 줄 끝에서 끊어진 것처럼 보입니다. |
인라인 상자는 여러 줄에 걸쳐 분할됩니다. | box-decoration-break: clone 또는 display: inline-block |
| 그림자는 진흙투성이의 회색 안개처럼 보입니다. | 높은 불투명도에서 매우 큰 흐림 | 불투명도를 낮추고 작고 날카로운 그림자를 크고 희미한 그림자와 함께 레이어링합니다. |
| 투명한 로고 주위의 사각형 그림자 | box-shadow는 픽셀이 아닌 상자를 따릅니다. |
이미지에 filter: drop-shadow()를 사용하세요. |
두 번째 box-shadow 규칙이 첫 번째 규칙을 제거했습니다. |
나중에 선언하면 전체 목록이 대체됩니다. | 두 그림자를 하나의 규칙에 쉼표로 구분하여 넣습니다. |
| 완화 대신 호버 그림자 점프 | transition는 :hover에만 있거나 inset는 한 상태에서만 있고 다른 상태에서는 그렇지 않습니다. |
휴면 규칙에 transition를 넣고 두 목록 모두에서 inset를 일치시킵니다. |
링크로 공유하세요
그림자는 설명보다 화면에서 판단하기가 더 쉽고, 호버 효과는 스크린샷에서는 전혀 표시할 수 없습니다. .html 첨부 파일은 전화기에서 일반 코드로 열릴 수 있습니다.
작업 버전을 보내려면 페이지를 NOS 문서에 붙여넣고 공유 링크 만들기를 선택하세요. 링크할 HTML이 이를 안내합니다.
페이지는 작성된 대로 렌더링되고 스크립트가 실행되므로 페이지를 받는 사람은 슬라이더를 이동하고 카드 자체에 마우스를 올릴 수 있습니다. 나중에 코드를 변경하면 동일한 링크에 새 버전이 표시됩니다.