Search code examples
csscss-transformsshadowclip-pathcss-filters

How to use filter:blur with clip-path?


I'm trying to add a shadow to a clip-path hexagon. Since the usual box-shadow (and filter:drop-shadow()) won't work with clip-path, I'm trying to fake the effect with a larger pseudo element underneath. The approach is taken from here and works just fine in a simpler example:

enter image description here

body {
  background-color: gray;
}

.rectangle {
  margin: 10%;
  position: absolute;
  background: white;
  width: 80%;
  padding-top: 25%;
}

.rectangle::before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  filter: blur(10px) brightness(20%);
  transform: scale(1.1);
  z-index: -1;
  background-color: black;
}
<div class="rectangle">
</div>

However using the exact same approach with a clip-path hexagon fails. This rough sketch shows the desired effect:

enter image description here

Instead I get:

enter image description here

body {
  background-color: gray;
}

.hexagon {
  width: 20%;
  padding-top: 25%;
  -webkit-clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  -webkit-shape-outside: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  position: absolute;
  background: rgb(0, 229, 154);
  margin: 10%;
}

.hexagon::before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  -webkit-filter: blur(5px);
  -moz-filter: blur(5px);
  -o-filter: blur(5px);
  -ms-filter: blur(5px);
  filter: blur(10px) brightness(20%);
  transform: scale(2.5);
  z-index: -1;
  background-color: black;
}
<div class="hexagon">
</div>

Two Questions:

  1. How can I make this work?
  2. What's a better way to fake shadows for clip-path elements?

Solution

  • You need the opposite layout.

    The container (in this case, the base element) must have the filter applied, the inner part (in this case, the pseudo) must have the clip property:

    body {
      background-color: gray;
    }
    
    .hexagon {
      width: 20%;
      padding-top: 25%;
      filter: drop-shadow(10px 10px 10px red);
      position: absolute;
      margin: 10%;
    }
    
    .hexagon::before {
      content: '';
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      left: 0;
      transform: scale(2.5);
      z-index: -1;
        -webkit-clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
      clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
      -webkit-shape-outside: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
      background: rgb(0, 229, 154);
    }
    <div class="hexagon">
    </div>