ScreenshotNeo

BlogHow-to

How to Add Shadows to PNG Images in HTML and CSS

Use CSS drop-shadow() for shadows that follow transparent PNG artwork, or box-shadow for the image element’s rectangular frame.

By the ScreenshotNeo team1 October 20265 min read

Use filter: drop-shadow() when the shadow should follow the visible pixels of a transparent PNG. Use box-shadow when you want a shadow around the image element’s rectangular box.

drop-shadow() uses the rendered image alpha channel, so an irregular logo, icon, or cutout photo gets an irregular shadow. box-shadow shadows the element frame instead. See the MDN drop-shadow() reference and MDN box-shadow reference.

1. Add a shadow that follows a transparent PNG

Start with an image element and apply the filter in CSS:

<img class="logo" src="logo.png" alt="Company logo">
.logo {
  filter: drop-shadow(4px 6px 8px rgb(0 0 0 / 0.35));
}

The values mean:

Value Meaning
4px Horizontal offset. Positive values move the shadow right; negative values move it left.
6px Vertical offset. Positive values move the shadow down; negative values move it up.
8px Optional blur standard deviation. Larger values create a softer shadow.
rgb(0 0 0 / 0.35) Shadow color and opacity.

The color can appear before or after the lengths. If you omit it, the function uses the element’s color value. For a hard-edged shadow, omit the blur length or set it to 0:

.icon {
  filter: drop-shadow(3px 3px 0 rgb(0 0 0 / 0.45));
}

2. Use box-shadow for the image’s rectangular frame

Choose box-shadow when the image should look like a card, tile, or rectangular panel. The shadow follows the element’s box, including transparent areas inside that box.

.image-card {
  box-shadow: 0 8px 24px rgb(0 0 0 / 0.22);
}

box-shadow supports features that drop-shadow() does not, including spread and inset shadows:

.image-card {
  box-shadow:
    0 2px 4px rgb(0 0 0 / 0.18),
    0 12px 30px rgb(0 0 0 / 0.14),
    inset 0 0 0 1px rgb(255 255 255 / 0.25);
}
Requirement Property
Shadow follows transparent artwork filter: drop-shadow()
Shadow follows the rectangular image element box-shadow
Spread radius box-shadow only
Inset shadow box-shadow only
Multiple shadows Repeat drop-shadow() functions, or comma-separate box-shadow values

3. Build a layered PNG shadow

Multiple filter functions are separated by spaces and run in the order written:

.logo {
  filter: drop-shadow(2px 3px 3px rgb(0 0 0 / 0.35))
          drop-shadow(0 0 1px rgb(0 0 0 / 0.2));
}

The first shadow supplies the offset and depth; the second adds a tight outline. Keep the opacity low enough that the artwork remains readable.

4. Complete HTML example

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>PNG drop shadow</title>
  <style>
    :root {
      color-scheme: light;
      font-family: system-ui, sans-serif;
    }

    body {
      min-height: 100vh;
      margin: 0;
      display: grid;
      place-items: center;
      background: #eef2f7;
    }

    .stage {
      padding: 48px;
      background: white;
      border-radius: 16px;
    }

    .cutout {
      width: 240px;
      height: auto;
      filter: drop-shadow(12px 14px 10px rgb(0 0 0 / 0.28));
    }
  </style>
</head>
<body>
  <main class="stage">
    <img class="cutout" src="logo.png" alt="Company logo">
  </main>
</body>
</html>

5. Tune the effect for common designs

Soft floating object

.product-cutout {
  filter: drop-shadow(0 18px 18px rgb(15 23 42 / 0.24));
}

Small icon outline

.icon {
  filter: drop-shadow(0 0 1px rgb(0 0 0 / 0.5));
}

Light artwork on a dark background

.light-mark {
  filter: drop-shadow(0 4px 8px rgb(0 0 0 / 0.65));
}

Shadow above and to the left

.raised {
  filter: drop-shadow(-5px -5px 8px rgb(0 0 0 / 0.3));
}

Transparent padding inside the PNG affects where the alpha mask begins. If the artwork has large transparent margins, crop the source image or account for that space in the layout.

6. Debugging checklist

  1. Rectangular shadow: replace box-shadow with filter: drop-shadow() when the shadow must follow the visible silhouette.
  2. Too hard or too soft: change the third length. Smaller values sharpen the edge; larger values blur it.
  3. Wrong direction: check the signs. Positive horizontal and vertical offsets move right and down; negative values move left and up.
  4. Invisible shadow: set an explicit color with opacity and inspect whether another rule overrides filter.
  5. Clipped shadow: the blur and offset can extend outside the image box. Check ancestors with overflow: hidden or overflow: clip, and leave enough surrounding space.
  6. Unexpected appearance: inspect the complete filter list. Filter functions run in sequence, so a later function can change the result.

7. Performance and browser support

For ordinary logos and icons, one drop-shadow() is usually straightforward. Large images, very large blur values, many layered shadows, or hundreds of filtered elements increase rendering work. Prefer a small number of layers, avoid animating expensive blur effects unnecessarily, and test on the lowest-powered device you support.

MDN marks drop-shadow() as widely available across browsers since September 2016. Check the current compatibility table if you support an unusually old browser or a fixed device set.

8. Capture the finished result

To verify the shadow in a deployed page, capture the page at the same viewport and device scale your users will see. ScreenshotNeo can capture PNG, JPEG, WebP, or PDF output from one GET request. Its options include full-page capture, element capture by CSS selector, custom CSS and JavaScript, viewport and device presets, retina scale, waits, and caching. See the ScreenshotNeo documentation for request parameters.

9. Or skip the browser setup

Use ScreenshotNeo when you need a rendered screenshot without maintaining browser automation:

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)

Node.js

import { writeFile } from "node:fs/promises";

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
await writeFile('shot.webp', Buffer.from(await res.arrayBuffer()));

Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and response headers identify the page verdict and billing status. ScreenshotNeo also provides an MCP server so Claude, Cursor, and other MCP clients can take screenshots; 1,000 shots per month are free with no card, and paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

10. Troubleshooting FAQ

Why does my transparent PNG still have a square shadow?

The rule is probably using box-shadow, or the PNG has an opaque background. Use drop-shadow() and confirm the source file actually contains transparency.

Can I add a spread radius to drop-shadow?

No. drop-shadow() accepts offsets, optional blur, and color. Use box-shadow when you need spread.

Can I make an inset drop shadow?

No. The inset keyword is supported by box-shadow, not drop-shadow().

Why is the shadow cut off?

A blurred or offset shadow can extend beyond the image’s box. Remove restrictive overflow on an ancestor or add layout space around the image.

Does the PNG need to be displayed at its natural size?

No. The filter follows the image as rendered, so it also works when CSS changes its width or height. Keep height: auto when preserving the source aspect ratio.

When should I use a shadow baked into the image?

Use CSS when the shadow needs to change with themes, interaction states, or layout. Bake it into the asset when the effect is part of fixed artwork and must render identically everywhere.