Card folding out of page CSS effect

As part of my front-end work at Project Cece I got to make a CSS effect where a card seems to fold out of the background. This effect needs a shadow which gradually disappears under the element.

To create this effect we will use CSS filter property, drop-shadow() filter-function, and the clip-path CSS property.

The end result will look like this:

We start with a container element which defines the size of the whole card:

<div class="card-container">
</div>

In the container we add an element which is going to contain the shadow, and another element which will hold the card contents, but will also cover the created custom shadow shape.

<div class="card-container">
	<div class="card-shadow"></div>
	<div class="card-content"></div>
</div>

Using position: absolute; width: 100%; height: 100% we make the shadow fill the whole parent element. Let’s give it a background-color: red for now. Using clip-path we give the element the size it will need to have to get the fold out effect.

.card-container {
  position: relative;
  width: 215px;
  height: 300px;
  margin: 2rem auto 0 auto;
}
.card-shadow {
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: red;
  clip-path: polygon(
    /* top-left */
    0% 0%,
    /* bottom-left */
    6px calc(100% - 8px),
    /* bottom-right */
    calc(100% - 6px) calc(100% - 8px), 
    /* top-right */
    100% 0 
  );
}

So the shadow element is full width in the top, in the bottom the width is limited on each side and bottom by 6px. It will have the following shape:

If we would now give this element a box-shadow, it won’t work. The box-shadow would be applied to the shape of the original div. It would be rectangular, outside of the element. When applying clip-path, the shadow will be cut-off, as clip-path clips off any content outside of the specified shape.

To solve this we will use the filter property together with the drop-shadow() filter function to apply a drop-shadow to an arbitrary shaped element. When applying the filter to the just created shadow element you will see that the shadow won’t show up. It doesn’t show up for the same reason as that the box-shadow didn’t show up. The clip-path will hide anything outside of the clipping area.

To solve this we move the custom shaped element into a pseudo-element of the shadow, and apply the filter effect to the original shadow element. The CSS looks like this:

.card-shadow {
  position: absolute;
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 0 4px rgba(0, 0, 20, 0.3));
}
.card-shadow:after {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background-color: white;
  clip-path: polygon(
    0% 0%,
    6px calc(100% - 8px),
    calc(100% - 6px) calc(100% - 8px),
    100% 0
  );
}

When also removing the red background, the shadow starts to get the right shape:

Using the .card-content element we now cover the bottom part of the created shadow, but keep the top part visible:

.card-content {
  position: relative;
  background-color: white;
  width: 100%;
  height: 100%;
  z-index: 1;
}

Let’s also add some card content, and the result will look like this:

<div class="card-container">
  <div class="card-shadow"></div>
  <div class="card-content">
    <div></div>
    <h2>Cat</h2>
    <p>A cat is a very smart animal</p>
  </div>
</div>
.card-container {
  position: relative;
  width: 215px;
  height: 300px;
  margin: 2rem auto 0 auto;
}
.card-shadow {
  position: absolute;
  width: 100%;
  height: 100%;
  filter: drop-shadow(0 0 4px rgba(0, 0, 20, 0.3));
}
.card-shadow:after {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background-color: white;
  clip-path: polygon(
    0% 0%,
    6px calc(100% - 8px),
    calc(100% - 6px) calc(100% - 8px),
    100% 0
  );
}
.card-content {
  position: relative;
  background-color: white;
  width: calc(100% - 2rem);
  height: calc(100% - 2rem);
  z-index: 1;
  padding: 1rem;
  font-family: arial;
}
.card-content div {
  width: 100%;
  height: 100px;
  background-color: #eee;
  margin-bottom: 1rem;
}
.card-content h2 {
  margin-top: 0;
  margin-bottom: 0.5rem;
}
.card-content p {
  margin: 0;
}

A possible hover effect is one where the card fold back a bit more on mouse over: