• Original address: Creating Colorful, Smart Shadows
  • By Kirupa
  • Translation from: The Gold Project
  • This article is permalink: github.com/xitu/gold-m…
  • Translator: Hoarfroster
  • Proofread: CarlosChenN and Kim Yang

Pure CSS creates colorful smart shadows

A few days ago I was at Home Depot (a.k. Toys R Us for big kids) and they had a huge display showing all these colored light bulbs for sale! One item is a set of smart light bulbs behind the TV. They cast colored shadows on the back of the TV similar to what the TV is broadcasting, like this:

Pay attention to what’s going on behind the TV. The colors displayed on the screen are projected by the light bulb as colored shadows behind the TV set. As the colors on the screen change, so do the colors projected in the background. It’s really cool, right?

Naturally, after seeing this, my first thought was whether we could use Web technology to create a color shadow that was smart enough to mimic the foreground color. As it turns out, we could have built this case using just CSS. In this article, we’ll learn how to create this effect.

Start!

Make it real!

As you’ll see in the following sections, creating this kind of color shadow with CSS can seem like a daunting task (just to begin, of course). When we get into it and break down the core of this difficult task into smaller tasks, we can actually see how easy it is to achieve this effect. In the next few sections, we will create the following example:

What you should see is a picture of sushi with a colorful shadow on the back. (Just to emphasize that we’re doing all this, we’ve added pulsing animations to the shadows.) Leaving the examples aside, let’s dive into the implementation and see how HTML and CSS make this happen!

Show us our photos

The HTML used to display our sushi images was nothing special:


<div class="parent">
    <div class="colorfulShadow sushi"></div>
</div>
Copy the code

We have a parent div element that contains a child div element responsible for displaying the sushi. We display the sushi by specifying it as the background image, handled by the following.sushi style rule:

.sushi {
    margin: 100px;
    width: 150px;
    height: 150px;
    background-image: url("https://www.kirupa.com/icon/1f363.svg");
    background-repeat: no-repeat;
    background-size: contain;
}
Copy the code

In this style rule, we specify the size of the div as 150 x 150 pixels and set background-image and other related properties on it. So far, the HTML and CSS we’ve seen will give us something like this:

It’s shadow time

Now that our image is present, all that remains is the interesting part of defining the shadows. The way we define a shadow is by specifying a child pseudo-element (using ::after) that will do three things:

  1. Directly behind our image;
  2. Inherits the same background image as the parent element;
  3. Rely on filter to achieve colorful shadow effect;

These three things are accomplished through the following two style rules:

.colorfulShadow {
    position: relative;
}

.colorfulShadow::after {
    content: "";
    width: 100%;
    height: 100%;
    position: absolute;
    background: inherit;
    background-position: center center;
    filter: drop-shadow(0px 0px 10px rgba(0.0.0.0.50)) blur(20px);
    z-index: -1;
}
Copy the code

Let’s take a moment to see what’s going on here: First take a look at each of the attributes and their corresponding values, and there are some notable attributes — Background and Filter. The background attribute inherits inherit from the parent element, which means that the background can inherit from the parent element:

.colorfulShadow::after {
    content: "";
    width: 100%;
    height: 100%;
    position: absolute;
    background: inherit;
    background-position: center center;
    filter: drop-shadow(0px 0px 10px rgba(0.0.0.0.50)) blur(20px);
    z-index: -1;
}
Copy the code

We define two attributes for the filter attribute, drop-shadow and blur:

.colorfulShadow::after {
    content: "";
    width: 100%;
    height: 100%;
    position: absolute;
    background: inherit;
    background-position: center center;
    filter: drop-shadow(0px 0px 10px rgba(0.0.0.0.50)) blur(20px);
    z-index: -1;
}
Copy the code

Our drop-Shadow filter is set to display black shadows with an opacity of 50%, while our blur filter will blur our pseudo-elements by 20px. The combination of these two filters finally creates a colored shadow that will now appear behind our sushi image when applying these two style rules:

At this point, we have implemented smart Shadow. For completeness, if we want color shadow scaling animations, the following CSS code is added to help us achieve this goal:

.colorfulShadow {
    position: relative;
}

.colorfulShadow::after {
    content: "";
    width: 100%;
    height: 100%;
    position: absolute;
    background: inherit;
    background-position: center center;
    filter: drop-shadow(0px 0px 10px rgba(0.0.0.0.50)) blur(20px);
    z-index: -1;

    /* animation time! * /
    animation: oscillate 1s cubic-bezier(.17.67.45.1.32) infinite alternate;
}

@keyframes oscillate {
    from {
        transform: scale(1.1);
    }

    to {
        transform: scale(1.3.1.3); }}Copy the code

If you want some interactivity rather than looping animations, you can also use CSS transitions to change the way shadows behave over certain actions, such as hovering. The hard part is treating pseudo-elements like any other element explicitly defined in HTML or dynamically created using JavaScript. The only difference is that pseudo-elements are created entirely using CSS!

conclusion

Pseudo-elements allow us to use CSS to accomplish some of the elements that have historically been the domain of HTML and JavaScript. For our colorful and intelligent shadows, we can rely on the parent element to set the background image. This makes it easy to define a child pseudo-element that inherits the background image details of the parent element and allows us to set a series of attributes to it to achieve blur and shadow effects. While this is all very well and we minimize a lot of copying and pasting, this approach is not very flexible.

What if I want to apply such a shadow to an empty element that doesn’t just have a background image? What if I have an HTML element like a Button or ComboBox that I want to apply this shadow effect to? One solution is to rely on JavaScript to copy the appropriate elements in the DOM, place them below the foreground elements, apply a filter, and there you go. It’s feasible, but it’s a bit scary considering the complexity of the process. Unfortunately JavaScript doesn’t have an equivalent renderTargetBitmap API that renders our visual effects into bitmaps and then you can do whatever you want… 🥶

The above content is translated, and the following are some extensions:


expand

To be honest, we don’t need that much complex content. Images can be arbitrary, such as PNG, SVG, and finally, the HTML code is just any element, with a style that specifies the image address and size:

<div class="shadowedImage" style="--data-width: 164px; --data-height: 48px; --data-image: url('https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/dcec27cc6ece0eb5bb217e62e6bec104.svg');"></div>
Copy the code

CSS code is as follows:

.shadowedImage {
    position: relative;
    margin: 100px;
    width: var(--data-width);
    height: var(--data-height);
    max-height: 150px;
    background-image: var(--data-image);
    background-repeat: no-repeat;
    background-size: contain;
}

.shadowedImage::after {
    content: "";
    width: 100%;
    height: 100%;
    position: absolute;
    background: inherit;
    background-position: center center;
    filter: drop-shadow(0px 0px 10px rgba(0.0.0.0.50)) blur(20px);
    z-index: -1;
}
Copy the code

The sample code

An example code looks like this:

<! doctypehtml>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="Width =device-width, user-Scalable =no, initial scale=1.0, maximum-scale=1.0, Minimum-scale =1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>

    <style>
        .shadowedImage {
            position: relative;
        }

        .shadowedImage::after {
            content: "";
            width: 100%;
            height: 100%;
            position: absolute;
            background: inherit;
            background-position: center center;
            filter: drop-shadow(0px 0px 10px rgba(0.0.0.0.50)) blur(20px);
            z-index: -1;

            /* animation time! * /
            animation: oscillate 1s cubic-bezier(.17.67.45.1.32) infinite alternate;
        }

        @keyframes oscillate {
            from {
                transform: scale(1.1);
            }

            to {
                transform: scale(1.1.1.1); }}.shadowedImage {
            margin: 100px;
            width: var(--data-width);
            height: var(--data-height);
            max-height: 150px;
            background-image: var(--data-image);
            background-repeat: no-repeat;
            background-size: contain;
        }
    </style>
</head>
<body>
<div class="parent">
    <div class="shadowedImage" style="--data-width: 164px; --data-height: 48px; --data-image: url('https://sf3-scmcdn2-tos.pstatp.com/xitu_juejin_web/dcec27cc6ece0eb5bb217e62e6bec104.svg');"></div>
    <div class="shadowedImage" style="--data-width: 164px; --data-height: 164px; --data-image: url('https://sf1-dycdn-tos.pstatp.com/img/bytedance-cn/4ac74bbefc4455d0b350fff1fcd530c7~noop.image');"></div>
    <div class="shadowedImage" style="--data-width: 164px; --data-height: 164px; --data-image: url('https://sf1-ttcdn-tos.pstatp.com/img/bytedance-cn/4bcac7e2843bd01c3158dcaefda77ada~noop.image');"></div>
</div>
</body>
</html>
Copy the code

Effect of the sample

The effect is as follows:

If you find any errors in the translation or other areas that need improvement, you are welcome to revise and PR the translation in the Gold Translation program, and you can also get corresponding bonus points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


Diggings translation project is a community for translating quality Internet technical articles from diggings English sharing articles. The content covers the fields of Android, iOS, front end, back end, blockchain, products, design, artificial intelligence and so on. For more high-quality translations, please keep paying attention to The Translation Project, official weibo and zhihu column.