My overall experience with SVG on web was pretty limited. Even considering that I had been delivering icons, vector-based illustrations, logos, and so on in this format for several years.
I have never dived into the amazing possibilities that svg brings along to implement customized layouts and forms until last month when the UX team of my project hand-off a beautiful layout for our client product.
I must say is one of the most amazing designs I have ever see, the whole page, colors, forms, svg lines swimming nicely on the backgrounds, truly transmit the brand's playful toyish spirit.
That also means, complexity. Tons of it, from the Frontend perspective, but who I'm to say no to an amazing challenge?. Having the plus of using Adobe's AEM and supporting IE11 (I know 😤).
Take this post as the result of how I approached the challenge of creating crazy masks for content with SVGs and what I learned in the process, I hope it will become a handful to you if you ever come to the same scenario and you need to implement such complexity in your layout.
What is SVG?
SVG is an image format for vector graphics and it means Scalable Vector Graphics. It compresses nicely, you can scale to any size and you can control stuff like interactivity and applying filters easily.
If you open the svg
image in any IDE, you will notice that the file is actually in XML Format.
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<path d="M0,370.6c-0.5,35,29.5,68,60,82.8c40.8,19.7,82.2,6.8,99.3,1.4c76-23.8,83.3-81.4,130.3-79.9c43.9,1.4,53.2,52.1,102.2,52.5
c38.6,0.3,67.2-30.9,79.9-44.6c44.4-48.3,49.5-116.9,33.1-165.5c-6-17.7-11.5-34.1-27.4-45.3c-30.9-22-62.5,2.7-96.2-16.2
c-27.9-15.7-17.7-39-44.8-68c-44.9-47.9-125.5-40.2-155.5-37.3C145.6,53.7,101.3,58,66.5,92c-43.9,42.9-46.3,107.1-46.8,120.2
c-1.7,45.2,14.1,62.2,1.4,103.6C12.1,345.6,0.3,348.8,0,370.6z"/>
<path d="M373.8,89.9c2.7-4.9,14.3-24.5,37.4-30.2c5.6-1.4,18.5-4.6,30.9,2.2c18.8,10.2,20,33.9,20.2,38.1c0.1,3.2,0.6,21.6-8.6,25.9
c-6.9,3.3-13-4.5-24.5-1.4c-7.4,1.9-7.1,5.7-13.7,7.9c-12.5,4.2-32-3.2-39.6-18.7C371.2,103.7,372.8,94,373.8,89.9z"/>
<path d="M432.1,133.8c-4.2,1.6-9.3,6-8.6,10.8c0.7,5.5,8.7,9.2,15.1,7.9c6.7-1.4,12.4-8.5,10.8-13.7
C447.7,133.4,438.5,131.3,432.1,133.8z"/>
</svg>
What is important for us here is the <path />
because they are the ones responsible for the shape of the mask we are going to apply to an image.
Using Clip-path
There are two ways you can use clip-path
:
- As an SVG element
<clip-path>
and an attributeclip-path="url(#myMask)"
- As a CSS property.
As an SVG element
For this example we are going to build something like this:
Resources:
Once you download the resources, let's start doing the markup:
First, we need to create an SVG object with the element <clipPath />
inside of the <defs>
element, this will contain the path defined by the abstract-shape.svg
you just downloaded.
<svg xmlns="http://www.w3.org/2000/svg" style="position:absolute">
<defs>
<clipPath id="mask">
<path
d="M0,370.6c-0.5,35,29.5,68,60,82.8c40.8,19.7,82.2,6.8,99.3,1.4c76-23.8,83.3-81.4,130.3-79.9c43.9,1.4,53.2,52.1,102.2,52.5
c38.6,0.3,67.2-30.9,79.9-44.6c44.4-48.3,49.5-116.9,33.1-165.5c-6-17.7-11.5-34.1-27.4-45.3c-30.9-22-62.5,2.7-96.2-16.2
c-27.9-15.7-17.7-39-44.8-68c-44.9-47.9-125.5-40.2-155.5-37.3C145.6,53.7,101.3,58,66.5,92c-43.9,42.9-46.3,107.1-46.8,120.2
c-1.7,45.2,14.1,62.2,1.4,103.6C12.1,345.6,0.3,348.8,0,370.6z"
/>
<path
d="M373.8,89.9c2.7-4.9,14.3-24.5,37.4-30.2c5.6-1.4,18.5-4.6,30.9,2.2c18.8,10.2,20,33.9,20.2,38.1c0.1,3.2,0.6,21.6-8.6,25.9
c-6.9,3.3-13-4.5-24.5-1.4c-7.4,1.9-7.1,5.7-13.7,7.9c-12.5,4.2-32-3.2-39.6-18.7C371.2,103.7,372.8,94,373.8,89.9z"
/>
<path
d="M432.1,133.8c-4.2,1.6-9.3,6-8.6,10.8c0.7,5.5,8.7,9.2,15.1,7.9c6.7-1.4,12.4-8.5,10.8-13.7
C447.7,133.4,438.5,131.3,432.1,133.8z"
/>
</clipPath>
</defs>
</svg>
It's very important that we assign an id
to the <clipPath />
element, this is the way we are going to reference it later to apply the mask.
For the image, svg
has an element dedicated to it <image>
, the magic happens when we add the attribute clip-path="url(#mask)"
Here is where we add the id we mention above.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 814 506" >
<image id="image" class="image__svg-image" width="100%" height="100%" clip-path="url(#mask)" x="-100px" xlink:href="https://res.cloudinary.com/alvarosaburido/image/upload/v1589435086/blog/The%20Magic%20of%20SVG%20Clip-path/pic_yo5eyq.png" />
</svg>
The result will be as awesome as this:
What about video?
This approach is also applicable to videos, or any other content (embedded views), but you will need to insert it inside an SVG <foreignObject />
tag.
The <foreignObject>
SVG element includes elements from a different XML namespace. In the context of a browser, it is most likely (X)HTML
.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 814 506">
<foreignObject clip-path="url(#mask)" width="814" height="800">
<iframe width="640" height="480" src="https://www.youtube.com/embed/oAuVf1coSjs" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</foreignObject>
</svg>
You get a similar effect ut with more dynamic content inside, you will probably will need to fight a little bit with the width
and height
of the element so it all fits on their site. You should end up with something similar to:
(If you can't see the pen, click here)
Consider also that shape form may affect access to video controls for example, so this one may not be the perfect choice for videos.
But wait... will this work in Internet Explorer 💩? You guessed right, <foreignObject>
is not supported for any Internet Explorer version... who would it guess 🙄 (Source caniuse).
As a CSS property
You can also achieve the same effect using clip-path
as a CSS property, the SVG containing the <ClipPath>
should remain the same, but for the image or video instead of also using SVG, you can use a normal HTML element like img
or video
.
Having that in mind, let's remove the svg element with the image/video and substitute it with something like this:
<img
class="abstract-shape"
src="https://res.cloudinary.com/alvarosaburido/image/upload/v1589435086/blog/The%20Magic%20of%20SVG%20Clip-path/pic_yo5eyq.png"
alt=""
/>
Were
.abstract-shape {
clip-path: url(#mask);
}
(If you can't see the pen, click here)
Of course, this would have been my choice by preference, is so much cleaner than using the SVG elements, also easier to calibrate the position of the image to get the best result, but then 🤦♂...
You guessed right, along with a lot of amazing stuff, css clip-path
is not supported by Internet Explorer 💩 (Source caniuse).
Conclusion
Wrapping up my experience creating crazy forms for a layout, this is what I learned:
- SVG is very versatile, you don't only have
clip-path
you can also define filters and animations inside of<defs>
that would make your markup even richer. - SVG is mostly well supported in browsers,
- Nothing cool works on IE 💩. So for your mental health and your users, stop using Internet Explorer or change to Microsoft Edge at least.
That's all for today folks! Keep rocking those SVG and drop some comments in the section below if you enjoy the article.
Top comments (3)
I thought your critical comment regarding the tutorial for the clipping path services was spot on. However, I have a blog that will clarify the situation more. I appreciate you publishing the post.
Back in the future: IE is dead. So we can now use clip path! 💪🏻
Thanks for the great tips. One thing I noticed is that clipping YouTube seems to be not working on iOS.