Clip-path scaling
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.
Urgh.
Clipping images
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 circle
, 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
alt
text
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.
Getting started
First of all, we need an SVG. Here’s what we’ll use:
See the Pen (@websmyth) on CodePen.
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:
See the Pen (@websmyth) on CodePen.
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
svg
- Defined a
clipPath
with anid
- 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 (#svgClip
).
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:
See the Pen (@websmyth) on CodePen.
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 0
and 1
.
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 1px
.
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 0
and 1
.
The SVG now successfully scales with the image:
See the Pen (@websmyth) on CodePen.
With a few more presentational styles, we can square this off and position the img
wherever we need:
See the Pen (@websmyth) on CodePen.
Wrapping up
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 0
and 1
, and how to scale the SVG.
Corrections and suggestions welcome!