SVG Clip Path Coordinate Converter

Convert from absolute to relative path coordinates

Why use this tool?

The purpose of this tool is to take an SVG file which contains clipPath elements with absolute coordinates and convert these to fractional (or relative) coordinates.

What is a clip path?

The clipPath is an SVG element which defines a path that can be used to apply a clipping region around other SVG elements. Using the CSS clip-path property it can also be applied to HTML elements. Effectively it allows you to create elements with any shape you like.

There is a problem you will encounter when you use the CSS clip-path property. The next series of examples illustrates this. In each case we have 3 html boxes of different sizes. Each example demonstrates a different way of applying the clip path. The clip path for the first two examples looks like this:

<svg width="0" height="0" viewBox="0 0 100 100">
  <clipPath id="myClip">
    <path d="M10,30 A20,20,0,0,1,50,30 A20,20,0,0,1,90,30 Q90,60,50,90 Q10,60,10,30 Z" />
  </clipPath>
</svg>

The <path> within <clipPath> describes a heart shape.

In the first one there are 3 html boxes of varying sizes. Each box contains an SVG rectangle comprised of the same SVG units in all cases. You can see that the rectangle adjusts in size according to its html container. This is convenient since it allows us to easily change the size of the SVG just by changing the size of its container. In the first example, each box contains an SVG element, specifically a <rect> which has a red fill. Notice that the SVG entirely fills its containing html box. If you click the toggle button, the clip path is applied directly to the SVG element. We have 3 different sized hearts as the clip path adjusts to SVG element it is applied to. This is the behaviour I would expect from a clip path.

Things, however, are a bit different if we use the CSS clip-path property directly on HTML elements. Now, the hearts are all the same size. The clip path does not adjust to its container.

This is somewhat annoying. The whole point of SVG is that it is resolution independent and we can make the same SVG larger or smaller without any loss in quality.

The good news is that there is a solution to this. It turns out that what is happening here is that the the <clipPath> element takes an attribute called clipPathUnits. This can have two values: 'userSpaceOnUse' and 'objectBoundingBox'. If it's left off, as we have here, the default is 'userSpaceOnUse'. What this means is that the SVG coordinates used correspond to the coordinate system of the element it is applied to. In other words, the coordinates of the path are interpreted as pixels. The origin of the coordinate system is equal to the top left corner of the element.

As an aside, there was a time when Chrome interpreted the origin as being the top left corner of the document itself. This made clip-path CSS property unusable unless you were prepared to put your element right at the top left of the page, or else apply a crazy offset within the clip path!

So what is the other value 'objectBoundingBox'? This is what allows us to scale a clip path with an html element. What it means is that the clip path will scale to fit the size of the element it is applied to. The only problem is that the coordinates used within the clip path have to be expressed as fractions of the width and height of the element with (0,0) being the top left of the element and (1,1) corresponding to the bottom right.

What happens if your SVG isn't using these relative coordinates? This is where our tool comes in. It takes an SVG, searches for the clip path elements within, and converts the coordinates it finds to relative ones. You pass in a width and a height to enable the calculation to be made. The following is the generated code.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <svg width="0" height="0" viewBox="0 0 100 100">
    <clipPath clipPathUnits="objectBoundingBox" id="myClipRelative">
      <path d="M0.1 0.3A0.2 0.2 0 0 1 0.5 0.3 0.2 0.2 0 0 1 0.9 0.3Q 0.9 0.6 0.5 0.9 0.1 0.6 0.1 0.3Z"/>
    </clipPath>
  </svg>

This example uses this SVG.

Now the clip path works in the way that we want it to.