- Adding Shadows to SVG Icons With CSS and SVG Filters
- Original article by Joel Olawanle
- The Nuggets translation Project
- Permanent link to this article: github.com/xitu/gold-m…
- Translator: Hoarfroster
- Reviewer:
Why do we need to shadow SVG?
- Shadows are a common design feature that helps elements like ICONS stand out. They can be persistent, or they can be applied to different states (e.g. exclusive to
:hover
,:focus
或:active
To indicate the interaction with the user. - Shadows happen in real life, so applying them to a page can breathe life into our elements and add a touch of realism to the design.
Since we are making lists, we can apply shadows to SVG in two main ways:
- Using CSS
[filter()](https://css-tricks.com/almanac/properties/f/filter/)
Properties; - Using SVG
<filter>
;
Yes, both involve filters! And, yes, CSS and SVG have their own filter types. But there is some overlap between these. For example, a CSS filter can reference an SVG
; That is, we can use inline SVG in CSS instead of, say, using SVG as a background image in CSS.
** Unusable content: **CSS box-shadow property. This is usually used for shadows, but it will only follow the outer rectangular edge of the element, not the edge of an SVG element that we want it to follow. Here’s Michelle Barker’s clear explanation:
However, if we are using an SVG icon font, text-shadow is always an optional method for adding shadows. That really works. But let’s focus on the first two, because they fit most use cases.
Shadow with CSS filter
The trick to applying shadows directly to SVG via a CSS filter is the drop-shadow() function:
SVG {
filter: shadow(3px 5px 2px rgb(0 0 0 / 0.4));
}
Copy the code
This will apply a shadow that starts at 3px horizontally and goes down 5px, the blur radius is 2px, and the shadow color is 40% black. Here are some examples: Codepen Chriscoyier /rNypeeJ.
This browser support data comes from Caniuse for more details. Numbers indicate that the browser supports this version and later features.
Call the SVG filter in the CSS filter
Suppose we have an SVG filter in our HTML:
<svg height="0" width="0">
<filter id='shadow' color-interpolation-filters="sRGB">
<feDropShadow dx="2" dy="2" stdDeviation="3" flood-opacity="0.5"/>
</filter>
</svg>
Copy the code
We can use a CSS filter to call the SVG filter by ID instead of the value we saw earlier:
SVG {
filter: url(#shadow);
}
Copy the code
Now the filter is taken from THE HTML and referenced in the CSS to which it is applied: Codepen Chriscoyier /yLMpOoP.
Use SVG filter primitives
You may be wondering how we made SVG
work. To make shadows with an SVG filter, we use the Filter primitive type. A filter primitive type in SVG is an element that takes an image or graph as input and then outputs that image or graph when called. They are a bit like filters in a graphic-editing application, but they are in code and can only be defined in the SVG
element.
There are many different primitive filter types in SVG. We’re going to touch
. I’ll let you guess what to do just by looking at the name.
So, similar to how we do this with CSS filters:
svg {
filter: drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));
}
Copy the code
… We can do the same with the
SVG filter primitive type. There are three key attributes worth mentioning because they help define how shadows look:
dx
This moves the position of the shadow along the X-axis.dy
This moves the position of the shadow along the Y-axis.stdDeviation
This defines the standard deviation for shadow blur operations. We can also use other attributes, such as those for setting the shadow colorflood-color
And for setting the opacity of the shadowflood-opacity
.
Codepen olawanlejoel/xxqdaqN
The example includes three
elements, each with its own
filter primitive type.
Use an SVG filter
SVG filters are very powerful. We just learned about
, which is certainly very useful, but there’s a lot more they can do (including Photoshop-like effects), and the subset of things we get for shadows only is very broad. Let’s look at some, like colored shadows and insert shadows.
Let’s take the SVG tag for the Twitter logo as an example:
<svg class="svg-icon" viewBox="0 0 20 20">
<path fill="#4691f6" d="M18.258, 3.266-0.693 c, 0.405-1.46, 0.698, 2.277, 0.857 c - 0.653-0.686-1.586-1.115-2.618-1.115 - c - 1.98, 0-3.586, 1.581, 3.586, 3.53 c0 , 0.276, 0.031, 0.545, 0.092, 0.805 C6.888, 7.195, 4.245, 5.79, 2.476, 3.654 C2.167, 4.176, 1.99, 4.781, 1.99, 5.429 c0, 1.224, 0.633, 2.305, 1.596, 2.938 C2.999, 8.349, 2.445, 8.19, 1.961, 7.925 C1.96, 7.94, 1.96, 7.954, 1.96, 7.97 c0, 1.71, 1.237, 3.138, 2.877, 3.462-0.301 c, 0.08 0.123 0.945, 0.617, 0.123-0.23 c, 0-0.456-0.021-0.674-0.062 c0.456, 1.402, 1.781, 2.422, 3.35, 2.451-1.228 c, 0.947-2.773, 1.512 to 4.4 54,1.512 c - 0.291, 0-0.575-0.016-0.855-0.049 c1.588,,3.473 1, 1.586, 5.498, 1.586 c6.598, 0,10.205-5.379, 10.205-10.045 c0-0.153-0.0 03-0.305-0.01-0.456 c0.7-0.499, 1.308, 1.12, 1.789-1.827 - c - 0.644, 0.28, 1.334, 0.469, 2.06, 0.555 C17.422, 4.782, 17.99, 4.091, 18.258, 3.266" ></path>
</svg>
Copy the code
We need a
element to achieve these effects. This needs to be in the HTML < SVG > element. The
element is never rendered directly in the browser — it is only used as something that can be referenced via the filter attribute in SVG or the URL () function in CSS.
Here is the syntax for displaying an SVG filter and applying it to the source image:
<svg width="300" height="300" viewBox="0 0 300 300">
<filter id="myfilters">
<! All filter effects/primitive types are defined here -->
</filter>
<g filter="url(#myfilters)">
<! Filters will be applied to everything in this group -->
<path fill="..." d="..." ></path>
</g>
</svg>
Copy the code
The filter element aims to have the filter primitive type as a child element. It is a container for a series of filtering operations that are combined to create the filtering effect.
These filter primitive types perform a single basic graphical operation (such as blur, move, fill, combine, or distort) on one or more inputs. Like building blocks, each SVG filter can be used in combination with other filters to create an effect.
is a popular primitive type of filter used to add gaussian blur effects.
Suppose we define the following SVG filter using
:
<svg version="1.1" width="0" height="0">
<filter id="gaussian-blur">
<feGaussianBlur stdDeviation="1 0" />
</filter>
</svg>
Copy the code
When applied to an element, this filter creates a Gaussian blur effect, blurring the element with a 1px blur radius on x, but no blur on the y axis. Here are the results with and without effect:
CodePen olawanlejoel/rNyGbjw
We can use multiple primitive types in a single filter. This creates interesting effects, but we need to let the different primitive types know each other. Bence Szabo has a crazy cool model that he creates this way:
When combining multiple filter primitive types, the first primitive type uses the SourceGraphic as its graphic input. Any subsequent primitive type uses the result of its previous filtering effect as its input. And so on. But we can gain some flexibility by using the in, in2, and Result attributes on the original elements. Steven Bradley has an excellent article on the primitive types of filters that date back to 2016, but still apply today.
There are 17 primitive types we can use today:
<feGaussianBlur>
<feDropShadow>
<feMorphology>
<feDisplacementMap>
<feBlend>
<feColorMatrix>
<feConvolveMatrix>
<feComponentTransfer>
<feSpecularLighting>
<feDiffuseLighting>
<feFlood>
<feTurbulence>
<feImage>
<feTile>
<feOffset>
<feComposite>
<feMerge>
Notice the fe prefix on all of these. That stands for filter effect. Understanding SVG filters can be challenging. Effects like inserting shadows require lengthy syntax that can be difficult to master without a thorough understanding of mathematics and color theory. (Rob O’Leary’s “Deep Shadows” is a good place to start.)
We will use some prefabricated filters to bring ourselves into the wondrous surreal state or situation of things. Fortunately, there are plenty of SVG filters around.
Insert the shadow
To use the filter effect on the Twitter logo, we need to declare it in our “SVG source document” and reference it with a unique ID in our
tag.
<filter id='inset-shadow'>
<! -- Shadow offset -->
<feOffset
dx='0'
dy='0'
/>
<! Shadow radius -->
<feGaussianBlur
stdDeviation='1'
result='offset-blur'
/>
<! Reverse shadows to create embedded shadows -->
<feComposite
operator='out'
in='SourceGraphic'
in2='offset-blur'
result='inverse'
/>
<! Change the opacity of the color inside the shadow -->
<feFlood
flood-color='black'
flood-opacity='95'
result='color'
/>
<feComposite
operator='in'
in='color'
in2='inverse'
result='shadow'
/>
<! Drop shadow on element -->
<feComposite
operator='over'
in='shadow'
in2='SourceGraphic'
/>
</filter>
Copy the code
There are four different primitive types, each performing a different function. But, taken together, they implement insert shadows.
Now that we have created the insert Shadow filter, we can apply it to our SVG. We’ve seen how to apply it with CSS. Like:
.filtered {
filter: url(#myfilters);
}
/* or only for specific states, such as */
svg:hover,
svg:focus {
filter: url(#myfilters);
}
Copy the code
Codepen olawanlejoel/jOBBRjd
We can also apply SVG
directly in SVG syntax using the filter attribute, as follows:
<svg>
<! Apply a single filter -->
<path d="..." filter="url(#myfilters)" />
<! -- or applied to a set of elements -->
<g filter="url(#myfilters)">
<path d="..." />
<path d="..." />
</g>
</svg>
Copy the code
CodePen olawanlejoel/vYxmXVg
More examples
Here are some more examples of shadows from Oleg Solomka:
CodePen sol0mka/6eca814eda8ec7e758d0feab628bd390
Note that the base shadows here may be a little more complex than they need to be. For example, colored shadows can still be done using
, for example:
<feDropShadow dx="0.8" dy="0.8" stdDeviation="0"
flood-color="pink" flood-opacity="0.5"/>
Copy the code
But this emblazon effect is great as a filter!
Also note that we might see an SVG filter in the SVG syntax, as follows:
<svg height="0" width="0" style="position: absolute; margin-left: -100%;">
<defs>
<filter id="my-filters">
<!-- …… -->
</filter>
<symbol id="my-icon">
<!-- …… -->
</symbol>
</defs>
</svg>
Copy the code
In the first line, it says: This SVG shouldn’t render at all — it’s just something we’re going to use later. The
tag says something similar: we just define these things for later use. That way, we don’t have to repeat ourselves by writing things over and over again. We’ll reference filters by ID and symbol, perhaps like:
<svg>
<use xlink:href="#my-icon" />
</svg>
Copy the code
SVG filters are widely supported (even in Internet Explorer and Edge!) And the performance is very good.
This browser support data comes from Caniuse for more details. Numbers indicate that the browser supports this version and later features.
To summarize
Final comparison:
- CSS filters are easier to use, but more restrictive. For example, I think it’s impossible to use
drop-shadow()
Function add insert shadow. - SVG filters are more robust, but also more complex, and need to be used somewhere in HTML
<filter>
. - Both have excellent browser support and perform well on all modern browsers, although the SVG filter (surprisingly) has the deepest browser support.
In this article, you’ve seen examples of why and how shadows can be applied to SVG ICONS. Have you ever done that, but in a different way than what we see? Have you ever tried to make shadows that are impossible to achieve? Please share!
If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.
The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.