Clip-path scaling

25th Jun, 2020

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:

  1. Allows content editors to change the image
  2. 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:

Tourist holding a camera in a street market.

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:

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!