CSS의 상자 그림자, 한 번에 하나의 값

하나의 속성은 레이아웃의 모든 그림자(소프트 카드, 누른 버튼, 광선 및 링)를 그립니다. 아래 슬라이더를 이동하여 인쇄되는 줄을 복사하세요.

영문 원문 보기

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>
각 값에 대한 슬라이더와 삽입 스위치. 드래그하면 CSS 라인이 업데이트됩니다.

그림자는 요소의 둥근 모서리를 유지합니다. 여기 상자에는 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>
각 카드에는 정지 상태에서 두 개의 그림자가 있고 들어 올려졌을 때 두 개가 있으며 위로 4px 이동이 가능합니다. 키보드 포커스에도 링이 표시됩니다.
.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이 이를 안내합니다.

페이지는 작성된 대로 렌더링되고 스크립트가 실행되므로 페이지를 받는 사람은 슬라이더를 이동하고 카드 자체에 마우스를 올릴 수 있습니다. 나중에 코드를 변경하면 동일한 링크에 새 버전이 표시됩니다.

자주 묻는 질문

box-shadow의 값 순서는 무엇입니까?

수평 오프셋, 수직 오프셋, 흐림 반경, 확산 반경, 색상 순입니다. 두 개의 오프셋이 필요합니다. 흐림 및 확산은 선택 사항이며 기본값은 0입니다. 삽입 키워드는 시작 또는 끝에 올 수 있습니다.

한쪽에만 그림자를 넣으려면 어떻게 해야 하나요?

그림자를 해당 쪽으로 오프셋하고 네거티브 스프레드로 끌어당겨 다른 가장자리에 표시되지 않도록 합니다. 아래 그림자에만 해당: box-shadow: 0 8px 6px -6px rgba(0, 0, 0, .3).

동일한 요소에 두 개 이상의 그림자를 추가할 수 있나요?

그렇습니다. 하나의 상자 그림자 값에서 그림자를 쉼표로 구분합니다. 목록의 첫 번째 그림자가 맨 위에 그려집니다. 두 번째 상자 그림자 규칙은 첫 번째 규칙에 추가하는 대신 첫 번째 규칙을 대체합니다.

box-shadow가 요소의 크기나 위치를 변경합니까?

아니요. 외부 그림자는 상자 외부에 그려지고 레이아웃에서 공간을 차지하지 않으므로 이로 인해 이웃이 움직이지 않고 스크롤 막대가 나타나지 않습니다. 이것이 바로 제로 블러 확산 그림자가 아무것도 이동하지 않는 링처럼 작동하는 이유입니다.

투명한 PNG 주위에 그림자가 표시되지 않는 이유는 무엇입니까?

box-shadow는 요소 상자 내부의 픽셀이 아닌 요소 상자를 따르므로 투명한 이미지는 직사각형 그림자를 얻습니다. 대신 이미지에 필터: drop-shadow()를 사용하여 눈에 보이는 모양을 추적하세요.

함께 읽어 보기