Scaling SVG Clipping Paths for CSS Use

Avatar of Chris Coyier
Chris Coyier on

A legit CSS trick documented by Eric Meyer!

So there is polygon() in CSS and <polygon> in SVG. They are closely related, but there are all kinds of weirdnesses. For example, you can use path() in CSS to update the d attribute of a <path>, but you can’t do the same with polygon() and <polygon>.

Part of the problem is that polygon() in CSS only accepts numbers with units, like px, %, em, or whatever.

.clip-me {
  /* Works! */
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);

  /* Does NOT work */
  clip-path: polygon(50 0, 100 25, 100 75, 50 100, 0 75, 0 25);
}

Which is exactly the opposite in SVG:

<svg>
  /* Works! */
  <polygon points="50 0, 100 25, 100 75, 50 100, 0 75, 0 25"></polygon>

  /* Does NOT work */
  <polygon points="50px 0px, 100px 25px, 100px 75px, 50px 100px, 0px 75px, 0px 25px"></polygon>
  <polygon points="50% 0%, 100% 25%, 100% 75%, 50% 100%, 0px 75%, 0% 25%"></polygon>
</svg>

The trick is that you can force the SVG coordinates to behave like percentage coordinates (even with weird viewBoxes) with some light math, a transform attribute, and a special clipPathUnits attribute.

<svg viewBox="0 0 329.6667 86">
  <clipPath id="cloud02" clipPathUnits="objectBoundingBox"
   transform="scale(0.003033 0.0116279)">
    <path d="…(coordinates go here)…"/>
  </clipPath>
</svg>

Those two values are 1/329.6667 and 1/86, respectively, and they effectively scale every point in the d attribute to fit into the needed 0–1 range. Thus we have an SVG clipping path that scales with the element and fits to its dimensions!

Direct Link →