Funky image shapes are pretty popular and SVG
clip-path is a great way to create these.
Before this was widely supported, the only option was save images as a PNG with a transparent background, or add the website’s background colour to create a smaller JPG.
I’ve been experimenting with this on a couple of projects. Though there are several ways to clip an image with SVG, I’ve specifically needed to clip images using SVG-defined paths.
This is a little more complicated than using methods like
polygon or others. Clippy is a great tool if you need to clip a more basic shape.
We can either clip a
background-image or an
img element. Though I’ve used the
background-image on the CSS For Designers home page, the
img element technique is often more appropriate for client work because it:
- Allows content editors to change the image
- Lets content editors specify
Plus you retain all the other benefits of using an SVG
clip-path rather than saving a pre-cut PNG/JPG image (smooth edges, file size, etc).
Let’s get into it.
First of all, we need an SVG. Here’s what we’ll use:
This is taken straight from Sketch (via the useful SVGO plugin), and I’ve added a fill so you can see the shape.
We also need an image to clip. Here’s one from Unsplash:
In the Codepen below, we have the basic HTML and CSS we’ll use:
Breaking this down
There’s a fair bit of code here, so let’s break it down.
In our HTML, the
img element contains the image we want to clip, with an
alt description. Our SVG code is embedded directly underneath.
We’re using the SVG-defined clip-path method outlined here. In short, we’ve:
- Created a zero-width/height
- Defined a
- Specified the
path(copied from our original SVG)
In our CSS, we’ve used the
clip-path property. We’re referencing the SVG
clipPath we created in our HTML via its ID (
The result is a clipped image, but the position and size of the clip doesn’t correlate to the image itself. To make matters worse, if the image isn’t as wide as the SVG, it will appear to be cut-off:
SVG-defined clip-paths issue
In the article, Chris Coyier explains an issue with SVG-defined clip-paths, where they remain fixed in the upper-left of a document.
In my (brief) testing on Firefox, Safari and Brave (Chromium), I couldn’t replicate this so this may not be an issue on more recent browsers (the article was last updated in 2016). That said, there was a difference in how Safari rendered the SVG.
Scaling the clip-path
Ideally, we want the SVG
clip-path to scale with the image. To do this, we add
clipPathUnits="objectBoundingBox" to the
clipPath in our HTML:
<clipPath id="svgClip" clipPathUnits="objectBoundingBox">
However, if we want to use
objectBoundingBox, our SVG path values must be between
The simplest way to do this is to go back to our image editing software and resize our SVG to have a maximum width/height of
Here’s the same SVG we saw earlier, resized. The 1px dot may be difficult to see but, most importantly, the values are all between
The SVG now successfully scales with the image:
With a few more presentational styles, we can square this off and position the
img wherever we need:
This is a hastily written and brief run-down of this technique. The thing that stumped me for a while was the requirement for
objectBoundingBox paths to be between
1, and how to scale the SVG.
Corrections and suggestions welcome!