# Using filter and box-shadow together

We all know by now that a `box-shadow` is used to create a shadow around a DOM element like this : `box-shadow:2px 3px 10px 0 rgba(0,0,0,.25);` - same solution using `filter` like this `filter: drop-shadow(2px 3px 10px rgba(0, 0, 0, 0.15));` but `filter` applies to the div and all its contents too as its an ‘atomic’ property. So if we want a shadow around a DIV only, we use a `box-shadow`.

But here are some notes on why I need `box-shadow` *and* `filter` together.

When exporting the HTML page to a PDF, macOS's default PDF viewer requires a filter as in `filter: drop-shadow(2px 3px 10px rgba(0, 0, 0, 0.15));` otherwise it shows a box with a background colour behind the content.

This is a known rendering bug between Chromium's PDF engine and macOS Preview.

Claude : When box-shadow with transparency (rgba) is applied directly to child flex items (especially with percentage widths like 40%/60% or CSS gap), macOS Preview fails to calculate the alpha/clipping layer for those nested flex children, flattening the semi-transparent shadow into a solid gray block behind and around them.

Take this code as an example :

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>filter and box-shadow</title>    
    <style>
    *, *::before, *::after
    {
        box-sizing: border-box;
        margin: 0;
        padding: 0;
    }
    .container
    {
        margin: 20px;
    }

    #two-boxes
    {
        margin-top: 20px;
        display: flex;
        flex-direction: row;
        gap: 20px;
    }
    #two-boxes > div
    {
        flex: 1;
        display: flex;
        flex-direction: column;
        padding: 25px 20px;
        border-radius:18px;
        box-shadow:2px 3px 10px 0 rgba(0,0,0,.25);
        filter: drop-shadow(2px 3px 10px rgba(0, 0, 0, 0.15));
    }
    #two-boxes > div > img
    {
        display: block;
        margin: 15px auto 0;
        filter: none;
        box-shadow: none;
    }
    </style>
</head>
<body>
<div class="container">

    <div id="two-boxes">
        <div>
            <img src="https://anjanesh.s3.us-east-1.amazonaws.com/blogs/images/coral-crouch.png" alt="" />
        </div>
        <div>
            <img src="https://anjanesh.s3.us-east-1.amazonaws.com/blogs/images/teal-yoga.png" alt="" />
        </div>
    </div>

</div>
</body>
```

It shows a shadow around the 2 images too which I didn't ask for - even though I specified `filter: none;` and `box-shadow: none;` in `#two-boxes > div > img` - because filter gets 'passed' down to the child elements.

![](https://cdn.hashnode.com/uploads/covers/5e5e8afd205a551d167f94ef/430739de-3e7a-4359-a254-b77feb198816.png align="center")

The solution, as pointed out by PaulOB from Sitepoint Community Forums is to place the filter in the parent container's pseudo element `::before`

```css
#two-boxes > div
{
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: 25px 20px;
    /*
    border-radius:18px;
    box-shadow:2px 3px 10px 0 rgba(0,0,0,.25);
    filter: drop-shadow(2px 3px 10px rgba(0, 0, 0, 0.15));
    */
    position: relative;
}
#two-boxes > div::before
{
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 18px;
    box-shadow: 2px 3px 10px 0 rgba(0, 0, 0, 0.25);
    filter: drop-shadow(2px 3px 10px rgba(0, 0, 0, 0.15));
    pointer-events: none;
    /*z-index: -1;*/
}
```

Demo : [https://anjanesh.s3.us-east-1.amazonaws.com/demo/filter.html](https://anjanesh.s3.us-east-1.amazonaws.com/demo/filter.html)
