Adding a shadow to an image in CSS is normally done with two properties: box-shadow draws a rectangular shadow around the element's bounding box, while filter: drop-shadow() produces a shadow that follows the visible silhouette of a transparent PNG. The box-shadow property is straightforward and widely supported, but it ignores transparency — a transparent PNG drawn with box-shadow ends up with a square shadow outline that looks like an extra border. The filter: drop-shadow() function reads the alpha channel of the image and builds a shadow shaped like the actual artwork, which is usually what designers want. Both approaches live entirely inside the browser's rendering layer; the shadow is recomputed every time the page loads and is not written into the image file itself. When you need a shadow baked into the pixels — for a thumbnail, a mockup, a sticker, or any file you want to email or upload — you have to render the effect into the bitmap. The Add Shadow to Image tool does exactly that: it takes a local JPG, PNG, or WebP, applies a Canvas-rendered drop shadow, and exports a transparent PNG with the shadow already included.

add shadow to image css
add shadow to image css

CSS Methods for Adding a Shadow to an Image

Developers usually reach for one of two CSS properties when they want a shadow under an image. Each one handles transparency differently and each one works inside a different layer of the rendering pipeline.

The simpler of the two is box-shadow. It treats the image like any other box and adds a shadow at a chosen offset, with a chosen blur radius and color. The browser draws the shadow using the rectangle defined by the element's width and height — not the pixels of the image. That behavior is fine for solid photos but becomes a problem when the source is a transparent PNG with cut-out edges, because the shadow ends up looking like a rectangular frame rather than a shape that follows the cut-out.

The other option is the filter property with the drop-shadow() function. Per the CSS specification, filter: drop-shadow() generates a shadow that uses the alpha channel of the element as its shape, so a transparent PNG with a curvy silhouette gets a shadow that matches the silhouette. The syntax mirrors box-shadow: an x offset, a y offset, an optional blur radius, and a color. drop-shadow() is supported in every modern browser, including Safari, Chrome, Firefox, and Edge.

Both properties apply the shadow inside the page's rendering pipeline. Removing the CSS removes the shadow. Saving a screenshot or copying the image to the clipboard does not carry the shadow into the saved file.

box-shadow vs filter: drop-shadow

Aspect box-shadow filter: drop-shadow()
Follows transparency No — shadow uses the element box Yes — shadow uses the alpha channel
Best for Solid photos, icons, rectangular images Transparent PNGs, cut-out graphics, logos
Syntax box-shadow: 4px 6px 12px rgba(0,0,0,0.4); filter: drop-shadow(4px 6px 12px rgba(0,0,0,0.4));
Spread radius Supported as the fourth value Not supported
Multiple shadows Supported via comma-separated list Supported via chained filter values
Hardware acceleration Generally yes Generally yes
Persisted in the saved file No No

The two properties overlap on most basic use cases, but the alpha-aware behavior of drop-shadow() is what makes it the default choice for transparent artwork. If you are styling a square product photo, either property works; if you are styling a logo with a soft outline, drop-shadow() is almost always the right call.

Where CSS Shadows Fall Short

CSS shadows are powerful inside a web page but they have several practical limits that send designers looking for a raster-based alternative.

The first limit is persistence. A shadow produced by box-shadow or filter: drop-shadow() lives in the stylesheet, not in the image file. Copying the image into a Word document, an email draft, a slide deck, or a design tool that does not re-evaluate the CSS will produce an image without the shadow. Anything that needs the shadow to travel with the file has to bake the shadow into the bitmap.

The second limit is animation and editing control. CSS shadows are recomputed each time the page is rendered, which is great for hover effects but unhelpful when you want a static file you can tweak in a vector tool. Once the page is closed, the settings used to make the shadow are not stored alongside the image.

The third limit is engine-level variance. CSS shadow rendering depends on the visitor's browser engine. Different engines may anti-alias the edges slightly differently, especially at very small blur radii. For pixel-precise mockups or print previews, that variance can be a problem.

A fourth limit is server-side reuse. If you want to ship the same shadowed image to a content management system, a marketing email, or a third-party platform that does not execute your CSS, the shadow will be lost. The fix is to commit the shadow to pixels.

When You Need the Shadow Baked Into the File

There are several practical situations where a rasterized shadow is the right answer instead of a CSS rule.

  • Stickers and overlays: a transparent PNG with a soft drop shadow drops onto a background and reads like a physical object. CSS cannot help when the PNG is the deliverable.
  • Mockups and product cards: online stores often want the same shadowed image rendered on multiple themes or in apps that do not parse CSS. Baking the shadow once means every consumer sees the same look.
  • Thumbnails and social graphics: a flat shadow under a thumbnail reads better in feeds and previews than an unshadowed image with no visual weight.
  • Documents and slide decks: PowerPoint, Keynote, Google Slides, and most email clients ignore box-shadow and drop-shadow() entirely. The shadow has to live inside the image.

For these use cases, the fastest path is to apply a shadow to the image itself and download the result as a new PNG.

How to Add Shadow to an Image in Your Browser

  1. Open the Add Shadow to Image tool in your browser. The whole process runs locally on your machine, so the source file is never uploaded.
  2. Choose a local JPG, PNG, or WebP from your computer using the file picker. The tool accepts browser-decodable JPG, PNG, or WebP files up to 25 MiB, and the source and its planned expanded output are both checked against the canvas budget before any pixel work begins.
  3. Enter a horizontal offset and a vertical offset in whole pixels between -500 and 500. Positive horizontal moves the shadow right; negative horizontal moves it left. Positive vertical moves the shadow down; negative vertical moves it up in the downloaded image.
  4. Set a blur radius in whole pixels between 0 and 250. Larger values soften the edges of the shadow.
  5. Pick an opacity as a whole percentage between 0 and 100, and a shadow color using an exact six-digit hexadecimal value such as #000000 for pure black or #1F2937 for a softer slate.
  6. Select Add shadow. The browser decodes the source, draws it once with the chosen Canvas shadow state, draws it once more without the shadow so the source pixels stay sharp, and encodes the result as a PNG.
  7. Verify the reported expanded width and height. Because the canvas reserves twice the blur value on every side and adds the absolute directional offset on the affected side, the output dimensions are larger than the source.
  8. Select Download PNG. The file is named after the source, for example portrait-shadow.png, and the previous temporary download link is revoked once a new render replaces it.

Why the Downloaded PNG Is Larger Than the Source

The tool does not simply paste a shadow behind the original image — it allocates a larger canvas so the blur and the directional offset are not cropped at the original edges. The formula reserves a margin of twice the blur value on every side and adds the absolute directional offset on the affected side only.

Consider a 40 by 20 source image with an 8-pixel right offset, a 4-pixel upward offset, and 6 pixels of blur.

  • Left margin = 2 × blur = 2 × 6 = 12 px
  • Right margin = 2 × blur + |horizontal offset| = 12 + 8 = 20 px
  • Top margin = 2 × blur + |vertical offset| = 12 + 4 = 16 px (because the offset is upward)
  • Bottom margin = 2 × blur = 12 px

Plugging those into the width formula: 12 + 40 + 20 = 72 pixels. Plugging those into the height formula: 16 + 20 + 12 = 48 pixels. The added margin around the source totals 12 + 20 + 16 + 12 = 60 extra pixels, which is exactly what prevents the blur and the offset from being silently clipped at the original edge.

Shadow Settings Reference

Setting Accepted values Behavior
Horizontal offset -500 to 500, whole pixels Positive moves the shadow right, negative moves it left
Vertical offset -500 to 500, whole pixels Positive moves the shadow down, negative moves it up
Blur radius 0 to 250, whole pixels Higher values soften the shadow edges
Opacity 0 to 100, whole percent Applied as the alpha of the shadow color
Shadow color Six-digit hex (for example #1F2937) Exact value, no shorthand or named colors
Source file JPG, PNG, or WebP up to 25 MiB Decoded to pixels; original bytes are not retained
Output Transparent PNG named after the source File name pattern: filename-shadow.png

These ranges are enforced by validation before the render starts. An invalid offset, an invalid color string, an unsupported file type, a file above the size limit, or a result that would exceed the canvas budget produces a visible error instead of a corrupted PNG. Per the MDN documentation on shadowBlur, the browser Canvas shadow is a rendering effect rather than a print prepress measurement, so exact feather pixels can vary slightly between browser engines.

Privacy and Local Processing

For users who care about where their images go, every step of the pipeline runs inside the browser tab. According to the Canvas API documentation, the browser can decode images, draw them with a shadow state, and encode a new bitmap without contacting a server. The Add Shadow to Image tool uses that local pipeline exclusively.

No upload happens when the file picker is opened, no upload happens during the render, and the download link is created from a temporary object URL inside the page. Changing the source or any setting invalidates the old result and revokes the previous object URL, so there is no leftover temporary data sitting in memory. JPG and WebP sources are decoded to browser pixels, which means their original compression bytes and any embedded metadata are not carried into the output PNG — a useful side benefit for users who do not want EXIF data or color profiles leaking out alongside the new image.