FIRST CH TOOLS / DESIGN / 52 CSS BOX-SHADOW GENERATOR
CSS box-shadow Generator
Shape a CSS shadow with sliders and copy the result. It is built around layered shadows: stack as many as you need, or press Make it smooth to split one shadow into a stack of faint ones. Presets for Material elevation, neumorphism and focus rings, plus paste-in of a box-shadow copied out of DevTools.
Dial in the shadow
The preview frame is overflow: hidden. A shadow that runs past the frame gets clipped here for exactly the reason it would on a real page: a shadow takes no layout space, so any ancestor that clips will cut it off.
The top row is the front layer — CSS paints the first shadow in the list on top. Make it smooth splits the selected layer into a stack of faint ones: the offset and blur grow step by step, and the opacity is shared out as 1-(1-α)^(1/n) so the stack ends up as dark as the single shadow you started from.
Colours may be HEX, rgb(), hsl(), oklch() or a CSS colour name. The opacity slider is the alpha of that colour; the swatch next to it only carries the opaque part.
Paste a value straight out of DevTools, with the box-shadow: prefix and the trailing ; if you like. Lengths are read in px (and a bare 0) only — em and rem depend on the font size in context, so they are deliberately not guessed at.
The blur number halves. A box-shadow blur radius is the width of the fade itself, while the third argument of drop-shadow() is the standard deviation of a Gaussian blur, which the spec defines as half of that width. drop-shadow() follows the opaque shape of the content rather than the box, which is what makes it the right choice for transparent PNGs and SVG icons (it has no spread parameter).
Mix the shadow colour in the Color Converter, build the background behind it with the CSS Gradient Generator, pick the speed curve for a shadow that animates in the Easing Preview, and check how far the shadow reads against its background with the Contrast Checker.
Loads the whole stack, layer by layer
A preset brings its background colour, element colour and corner radius along with the shadow layers, then returns to the Build tab — neumorphism and the dark-UI card only read correctly against the background they were designed for. Everything stays editable one layer at a time afterwards.
How to read it, and what usually goes wrong
Four numbers, in this order
The syntax is box-shadow: X Y blur spread colour;. Only trailing values may be dropped: leave out the spread and it is 0, leave out the blur too and you get a hard-edged shadow. Leave out the colour and the shadow uses currentColor, which is how people end up with an unexpectedly black or brand-coloured shadow. Put inset at the front and the shadow falls inside the box.
A shadow takes no layout space
Unlike border, a shadow does not change the size of the element, so adding one never shifts the layout. The flip side is that an ancestor with overflow: hidden clips it without warning — that is almost always the reason a shadow disappears on one side inside a carousel or a tab panel. Read the "reach beyond the box" figure above and leave that much padding on the parent.
Several faint shadows beat one dark one
Real light does not arrive from a single direction, so a real object casts a tight dark shadow close in and a wide faint one further out at the same time. Imitate that with one box-shadow and you have to choose: dark enough looks dirty, faint enough does not lift. Three to six stacked layers look far more convincing at the same overall darkness — which is what the "Make it smooth" button builds for you.
Stacked opacity is not addition
Two shadows at 20% opacity do not make 40%; they make 1-(1-0.2)² = 36%. For n layers it is 1-(1-α)ⁿ. Turned around: to land on 30% overall, each of n layers needs 1-(1-0.3)^(1/n). The splitter here uses exactly that, so changing the layer count does not change the overall darkness. The "darkest point" figure above is the upper bound, where every layer overlaps.
List order is stacking order (first is front)
Comma-separated shadows are painted with the first one on top. The convention is tight-and-dark first, wide-and-faint after. Swap them and the dark shadow hides behind the faint one and the whole thing goes muddy. z-index has nothing to do with it — the list order alone decides.
A negative spread keeps the shadow attached
Spread grows or shrinks the shadow shape itself. Make it negative and the shadow is smaller than the element, so even a large blur does not leak out sideways and the shadow stays pooled under the element. A slightly negative spread against a bigger blur — 0 10px 15px -3px — is what practically every UI library's card shadow is doing.
Blur fades half of its radius outwards
With a blur radius of b, the fade runs b/2 inside and b/2 outside the shadow edge. So the distance the shadow actually reaches is offset + spread + b/2, not the whole blur. The same fact is why the blur number halves when you rewrite the shadow as filter: drop-shadow(): that argument is the standard deviation of the Gaussian blur.
The shadow follows the box, not the artwork
box-shadow traces the border box — a rectangle, rounded by border-radius. Put one on a transparent PNG logo or a shape cut out with clip-path and you still get a rectangular shadow. When the shadow has to follow the artwork, use filter: drop-shadow() instead (no spread parameter, and stacking several of them gets expensive).
Zero blur, zero offset: that is a ring
Give a shadow nothing but spread — 0 0 0 2px — and you get a solid ring around the element. Unlike border it does not change the element's size, and unlike outline it follows the corner radius, which makes it the standard way to draw a focus ring. Stack two (a white one inside a coloured one) and the ring stays visible on any background.
Inset does not work everywhere
An inset shadow is drawn inside the padding box, but never on top of replaced content — <img>, <video>, <iframe> and friends. To sink an image into the page, put the inset shadow on a wrapper around it. Inset and outer shadows can otherwise be mixed freely in one declaration.
Translucent black is rarely the best colour
rgb(0 0 0 / 0.1) is safe, but over a saturated background it reads as grey sludge. Keep the hue of the background and drop the lightness instead — a deep navy shadow on a blue page — and the same darkness looks clean. In dark mode a black shadow is invisible to begin with, so the usual move is to drop the shadow and outline the top edge with a light inset, for example inset 0 1px 0 rgb(255 255 255 / 0.1).
Animate a pseudo-element, not the shadow
transition: box-shadow .2s works, but it re-renders the blur on every frame, which gets expensive for large shadows. To deepen a shadow on hover, put the stronger shadow on an ::after layer and animate only its opacity — that is a compositor-only change. Pick the curve in the easing tool.
How to Use
- Set the sceneMatch the preview's background colour, element colour and corner radius to the screen you are designing. A shadow changes character with what is underneath it — one tuned on white all but vanishes on a grey page.
- Stack the shadowSet X, Y, blur, spread and opacity with the sliders, then press "+ Stack one" for a second layer, or "Make it smooth" to split one into a faint stack. Loading a Material or neumorphism preset and editing from there is often quicker.
- Copy it out"Copy value" gives you the box-shadow value on its own; "Copy declaration" includes the property. Pick the colour syntax (rgb(… / …), rgba() or HEX) that matches your codebase.
About This Tool
A CSS shadow is four numbers and a colour. They come in the order box-shadow: X Y blur spread colour;, with an optional inset at the front to throw the shadow inside the box. This tool puts all five on sliders and shows the result on a real element next to the CSS. The preview's background colour, element colour, corner radius and size are adjustable too, so the shadow can be judged in the conditions it will actually live in — a shadow tuned on a white card is often invisible on a grey page.
Layered shadows are the point of the page. A real shadow is tight and dark near the object and wide and faint further away, both at once, and a single box-shadow can only be one of those. Stacking a few faint layers reads as far more natural at the same overall darkness. "Make it smooth" splits the selected layer into n layers, growing the offset and blur step by step while sharing the opacity out as 1-(1-α)^(1/n). Stacked opacity multiplies rather than adds — n layers at α come out at 1-(1-α)ⁿ — so dividing it that way keeps the total darkness fixed no matter how many layers you ask for.
You can start from the CSS you already have. Paste a value copied out of DevTools, with or without the box-shadow: prefix and trailing semicolon, and it is broken back into editable layers (lengths in px and bare 0 only). A single outer shadow with no spread is also printed as filter: drop-shadow(). The blur number halves in that form because drop-shadow() takes the standard deviation of the Gaussian blur, which is half the blur radius box-shadow asks for.
It also flags the ways shadows go wrong. The notes list catches shadows that cannot be seen at all, shadows dark enough to look dirty, a reach large enough to be clipped by an overflow: hidden parent, and inset shadows on elements where they will never paint. Generation and checks all happen in the browser and nothing is uploaded. Directly callable via URL parameters: /en/box-shadow/?css=0 10px 15px -3px rgb(0 0 0 / 0.1)&bg=%23faf8f4&radius=12
Other Tools
- 01Batch Image → WebP ConverterWebP Converter
- 02White Background RemoverWhite BG Remover
- 03WCAG Contrast CheckerContrast Checker
- 04Character CounterCharacter Counter
- 05llms.txt Generatorllms.txt Generator
- 06JSON-LD GeneratorJSON-LD Generator
- 07Markdown → PDFMD → PDF
- 08OGP Meta Tag WizardOGP Wizard
- 09Favicon GeneratorFavicon Generator
- 10TikTok PublisherTikTok Publisher
- 11Encoding & Line Ending ConverterEncoding Converter
- 12Batch Image → AVIF ConverterAVIF Converter
- 13Test Data GeneratorTest Data Generator
- 14Marp Markdown → SlidesMarp Slides
- 15Text & Code Diff CheckerDiff Checker
- 16Cron Expression ExplainerCron Explainer
- 17Base64 & Data URI EncoderBase64 & Data URI
- 18URL Parameter Editor & UTM BuilderURL Parameters
- 19HTML Entity Escape & UnescapeHTML Escape
- 20JSON ⇄ YAML ConverterJSON ⇄ YAML
- 21PX ⇄ REM / EM ConverterPX ⇄ REM / EM 単位変換
- 22Color Converter & AlphaColorコード変換&アルファ透過
- 23MD5 / SHA-256 Hash Generatorハッシュ生成
- 24JWT Decoder & Expiry CheckerJWTデコーダー&有効期限チェッカー
- 25User-Agent ParserUser-Agent解析&デバイス判定
- 26UUID & ULID GeneratorUUID (v4) & ULID 一括生成
- 27Aspect Ratio Calculatorアスペクト比計算&サイズ算出
- 28Markdown Table & CSV/TSV ConverterMarkdownテーブル整形&CSV/TSV変換
- 29SQL Query FormatterSQLクエリフォーマッター&整形
- 30QR Code GeneratorQR Code Generator
- 31Regex Tester正規表現テスター
- 32Unix Timestamp ConverterUNIXタイムスタンプ⇄日時変換
- 33New Tab Memo新規タブメモ帳
- 34Image Resizer & Cropper画像リサイズ&クロップ
- 35EXIF Viewer & RemoverEXIF情報の確認&除去
- 36robots.txt Generatorrobots.txt ジェネレーター
- 37Password Generator安全なパスワード生成
- 38Case Converter文字列ケース変換
- 39CSV/TSV ⇄ JSON ConverterCSV/TSV ⇄ JSON 相互変換
- 40PDF Merge, Split & ExtractPDF結合・分割・ページ抽出
- 41Full-width ⇄ Half-width Converter全角⇄半角変換&テキストクリーナー
- 42X (Twitter) Post CounterX(Twitter)投稿の文字ウェイト計算
- 43CSS clamp() Fluid Typography CalculatorCSS clamp() 計算機
- 44CSS Gradient GeneratorCSSグラデーションジェネレーター
- 45Image Colour Palette Extractor画像からカラーパレット抽出
- 46QR Code ReaderQRコード読み取り
- 47SVG Optimizer & Data URISVG最適化&data URI化
- 48Redirect Generatorリダイレクトルール ジェネレーター
- 49IP / CIDR CalculatorIPアドレス・CIDR計算機
- 50ICS Calendar Event GeneratorICS Generator
- 51cubic-bezier Easing Preview & ComparisonEasing Preview