11

I'm trying to use an SVG to mask an image.

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width=500 height=300>
    <defs>
    <clipPath id="clip">
    <path d="M2.16,1.363h23.699c13.739,0,24.899,10.74,24.899,23.999s-11.16...

<img width="500" style="clip-path: url(#clip);-webkit-clip-path: url(#clip);" />

It works but I want the clipPath size to match the media. In Chrome I can control the size of the clipPath with CSS but in FF the clipPath stays small. In Safari with one asset nothing appears and with another it appears off-center.

I've read other questions that talk about using clipPathUnits:

 <clipPath id="clip" clipPathUnits="objectBoundingBox">

But I cannot get this to work at all. Apparently it expects the paths units to be decimals... but my shape is too complicated to write by hand and I don't know of any design software that supports that format.

Update

Following Robert's comments, I tried adding a CSS transform to the clipPath to "translate" the units...

    #clip {
        -webkit-transform:scale(0.004195862879,0.005554321262);
        transform:scale(0.004195862879,0.005554321262);
    }

This allowed objectBoundingBox to work as expected in Chrome. But still no luck with Safari or FF. It appears that Safari still renders the clipPath outside the the element to be clipped... making it invisible. FF developer tools make it less clear where it's placing the clipPath.

emersonthis
  • 32,822
  • 59
  • 210
  • 375
  • 1
    objectBoundingBox units go between 0 and 1. – Robert Longson May 20 '17 at 20:21
  • @RobertLongson I think this is stated in the question, no? – emersonthis May 21 '17 at 00:15
  • What you've given us is an incomplete example so we can't fix that, all we're left with is stating generalities as an answer and you don't want that, so what do you want as an answer? – Robert Longson May 21 '17 at 03:55
  • @RobertLongson can you clarify what's missing from my question? I literally copy/pasted it from my project. I just omitted the path element's d attribute to save space. Looks like I also missed the href for the img... what else do you want me to include? Also generalities are welcome... I just confused because you repeated the question. – emersonthis May 21 '17 at 07:13
  • An [MCVE] is missing. Please create a shortened valid path that we can correct. – Robert Longson May 21 '17 at 07:14
  • I see. You suspect the actual path data might be the problem? I'm fairly certain that's not the problem because I can load the same path normally (not as clipPath) without problems. I'll update the question shortly with the FULL path attribute – emersonthis May 21 '17 at 07:21
  • @RobertLongson that sounds promising but I don't entirely understand. Are you saying there is a way to use the current viewbox syntax as a clipPath that scales with the "host" element? Transform makes this possible? – emersonthis May 21 '17 at 07:28
  • stick a transform on the path to convert the path's size so its bounding box is between 0 and 1. Something like transform="scale(x,y) translate(a, b)". The translate may not be necessary. – Robert Longson May 21 '17 at 07:30
  • Ah I see. Want to submit an answer? I think the x and why would be x/VIEWBOX_WIDTH and y/VIEWBOX_HEIGHT respectively? Am I on the right track? – emersonthis May 21 '17 at 15:50
  • @RobertLongson I took a crack at what you said and updated the question above. – emersonthis May 21 '17 at 17:57
  • If you want it to work in Firefox use a transform attribute rather than a CSS transform. That will work in Chrome too. – Robert Longson May 21 '17 at 19:20
  • @RobertLongson strangely I couldn't get it so work with the attribute on the clipPath. I'm going to build a JS fiddle tonight – emersonthis May 22 '17 at 15:32
  • you want the attribute on the path, not the clipPath. – Robert Longson May 22 '17 at 15:39

3 Answers3

26

Run into this problem right now and found the solution. Thanks @RobertLongson for mentioning that when you applying clipPathUnits="objectBoundingBox", you should be sure that all of your coordinates are between 0 and 1. It means, that if you have, for example, a circle

<svg viewBox="0 0 20 20">
    <defs>
        <clipPath id="clip">
            <circle cx="10" cy="10" r="10" />
        </clipPath>
    </defs>
</svg>

then with clipPathUnits="objectBoundingBox" it should looks like this:

<svg>
    <defs>
        <clipPath id="clip" clipPathUnits="objectBoundingBox">
            <circle cx="0.5" cy="0.5" r="0.5" />
        </clipPath>
    </defs>
</svg>

In case of complex paths, I found one solution. All you need is an application for vector images editing. For Linux it could be Gravit Designer (I used it and it worked).

  1. Create new file of size 1x1
  2. Open you svg that contains your complex path without clipPath tag. If you don't have such source, then you can simply create new text file, paste your <path .../> into <svg>...</svg> and save it with *.svg extension, and then open it in your application (Gravit Designer).
  3. Copy your complex path from opened svg and paste it into created new file (1x1).
  4. Turn off "Preserve aspect ratio" (or something simillar) function if it enabled
  5. Set this parameters for your complex path: Width: 1px, Height: 1px, Top: 0px, Left: 0px.
  6. Save this 1x1 file as svg.
  7. Open this svg file in text editor and copy the value of d attribute.

Now you have your complex path in relative coordinates. Set it into you clip

...
<clipPath id="clip" clipPathUnits="objectBoundingBox">
    <path d="/* your copied value */" />
</clipPath>
...

Done! Now you can enjoy your responsive clip path without any additional transformations or other workarounds.

I know, it looks too complicated, but it really will be done in approximately 2 minutes (if you have vector image editing software installed).

Hope this helps someone despite of question was asked 1.5 years ago :)

Limbo
  • 2,123
  • 21
  • 41
7

I was using Adobe Illustrator to try and shrink my vectors down to 1px by 1px, and it wasn't capturing all of the coordinates correctly. I instead found this awesome online tool that will convert SVG path coordinates to CSS clip-path friendly coordinates relative to a "1" unit without needing a vector editing program. The quality is much better than Illustrator and easier to use.

https://yoksel.github.io/relative-clip-path/

Brenda
  • 835
  • 8
  • 11
1

I got a similar problem, I solved it like this:

  1. I transfer the svg file to figma (drag and drop)
  2. I align to a square 100 by 100 (without preserving the sides)
  3. export the file as svg
  4. I upload the file to the service https://betravis.github.io/shape-tools/path-to-polygon/ (not advertising, you can use something else)
  5. I get a clean polygon as a percentage, which can be used in clip-path;

example:

.elem-to-path{
clip-path: polygon(89.758% 99.457%, 67.178% 99.862%, 39.660% 99.621%, 7.748% 98.475%, 5.924% 98.004%, 5.742% 97.859%, 4.348% 92.036%, 1.807% 80.831%, 0.174% 36.869%, 1.052% 1.541%, 1.301% 1.012%, 2.237% 0.790%, 62.832% 0.559%, 78.860% 0.810%, 88.832% 0.810%, 96.913% 1.195%, 98.441% 3.283%, 99.616% 24.932%, 98.813% 86.202%, 96.703% 95.116%, 89.758% 99.457%)}