SVG mask and clipPath: show only part of a shape
An SVG clipPath cuts a shape or picture to a hard outline. A mask fades it by brightness, so edges can be soft. Code for both, the differences and the faults.
Published
SVG has two ways to show only part of something. A <clipPath> holds shapes, and whatever it is applied to is visible only inside their outline, with a hard edge. A <mask> holds a picture in shades of grey: where the mask is white the element shows, where it is black the element is hidden, and greys leave it partly see-through. Use a clip path for a clean cut-out and a mask when the edge should fade.
<clipPath> | <mask> | |
|---|---|---|
| Applied with | clip-path="url(#id)" | mask="url(#id)" |
| Uses | The outline of its shapes only | The brightness and transparency of its contents |
| Edge | Hard | Hard or soft |
| Partial transparency | No | Yes |
| Colours of its contents | Ignored | White shows, black hides |
Both are defined once, by convention in <defs>, and can be applied to a shape, a picture, text or a whole group.
clipPath
This complete file clips a square to a circle:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<defs>
<clipPath id="round">
<circle cx="50" cy="50" r="40"/>
</clipPath>
</defs>
<rect width="100" height="100" fill="teal" clip-path="url(#round)"/>
</svg>
The result is a teal disc of radius 40. The rectangle is still a full square in the file. The clip only decides which part of it is painted.
Things to know about clip paths:
- Only the geometry counts. The fill colour, opacity and stroke of the shapes inside a
<clipPath>are ignored. A line with a thick stroke leaves nothing showing, because a line has no inside. - Several shapes add together. Two circles in one
<clipPath>show the element inside either of them. - Text can clip. A
<text>element inside a<clipPath>shows the element through the letters. - Groups are not allowed inside. A
<clipPath>may contain shapes, text and<use>, but not<g>. Shapes wrapped in a group are ignored and the clipped element disappears. - The name has a capital P. In an .svg file,
<clippath>in lower case is not recognised. The attribute that applies it isclip-path, with a hyphen.
Clipping a picture
The same clip turns a photograph into a round portrait:
<image href="photo.jpg" width="100" height="100"
preserveAspectRatio="xMidYMid slice" clip-path="url(#round)"/>
preserveAspectRatio="xMidYMid slice" makes the photo cover the whole 100 by 100 box before it is clipped, in the way object-fit: cover does in CSS. This fragment belongs inside an <svg> that also holds the <clipPath>. A picture linked like this shows when the SVG is inline in a page, but not when the SVG file itself is used in an <img> tag, where outside files are not loaded.
mask
A mask is drawn like any other SVG content, then read as brightness. This complete file fades a rectangle from solid on the left to nothing on the right:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 100">
<defs>
<linearGradient id="fade">
<stop offset="0" stop-color="white"/>
<stop offset="1" stop-color="black"/>
</linearGradient>
<mask id="soft">
<rect width="200" height="100" fill="url(#fade)"/>
</mask>
</defs>
<rect width="200" height="100" fill="teal" mask="url(#soft)"/>
</svg>
Where the mask is white, the teal is solid. Towards the black end it thins away. SVG gradients explains the stops.
Two rules catch most people:
- Shapes in a mask need
fill="white". The default fill is black, and black hides. A mask built from unstyled shapes makes the element vanish. - Anything the mask does not cover is hidden. Empty parts of a mask count as black.
Cutting a hole
A clip path keeps the inside of a shape. To remove the inside and keep the rest, use a mask that is white all over with the hole drawn in black. These two fragments go inside an <svg>, the mask in its <defs>:
<mask id="hole">
<rect width="100" height="100" fill="white"/>
<circle cx="50" cy="50" r="20" fill="black"/>
</mask>
<rect width="100" height="100" fill="navy" mask="url(#hole)"/>
This draws a navy square with a round hole 40 units across. Whatever lies behind shows through the hole. Text in place of the circle gives knocked-out lettering.
Where the clip or mask sits
The coordinates inside a <clipPath> or <mask> are those of the element it is applied to, including that element’s transform. Move the element with a transform and the clip moves with it. To slide artwork about behind a fixed window, put the clip-path on a <g> and the transform on the artwork inside the group.
A mask has one more limit. By default it only works within the element’s bounding box plus a tenth of its size on every side. Anything beyond, such as a wide stroke or a long shadow, is cut off. To widen the area, set x, y, width and height on the <mask>, for example with maskUnits="userSpaceOnUse" and plain coordinates that cover the drawing.
To make one clip fit elements of any size, set clipPathUnits="objectBoundingBox" and draw it in fractions, where 0,0 is the top-left of the element’s box and 1,1 the bottom-right. <circle cx="0.5" cy="0.5" r="0.5"/> then clips anything to an ellipse filling its box.
CSS clip-path and mask
On a web page, CSS can clip without any SVG markup: clip-path: circle(50%), inset(10px) and polygon(...) work on HTML elements. clip-path: url(#id) in CSS can also point at a <clipPath> defined in an inline SVG on the same page, provided that SVG is not hidden with display: none.
A whole SVG file can serve as a mask for an HTML element with mask-image: url(icon.svg). That is the usual way to recolour a one-colour icon, shown in changing SVG colour with CSS.
Clips, masks and cutting machines
A clip path or mask hides part of a shape on screen. It does not change the shape. A cutting machine follows outlines, so software that ignores the clip cuts the full hidden shapes, and some software reports the file as unsupported. Cricut Design Space lists clipping paths among the unsupported items in an uploaded SVG.
For a cut file, make the cut-out real. In a vector editor, select the shape and the outline it should be trimmed to and intersect them: in Inkscape, Path, Intersection keeps only the part covered by both. If the file already has a clip applied, release it first. The guide to uploading to Design Space lists the other things to remove.
Common problems
| What you see | Cause | Fix |
|---|---|---|
| A masked element vanishes | The shapes in the mask have the default black fill | fill="white" on the mask’s shapes |
| A clipped element vanishes | The shapes in the <clipPath> are inside a <g>, or lie somewhere else in the drawing | Put the shapes directly in the <clipPath>. Check the coordinates |
| No clipping at all | The id and the url(#...) do not match | Match them exactly |
| A stroke or shadow is cut off by a mask | The mask area ends a tenth beyond the bounding box | Set x, y, width, height on the <mask> |
| The clip moves when the shape moves | The clip uses the element’s own coordinates | Clip a parent group and transform the child |
| The stroke of a clip shape has no effect | Only the fill area of a clip shape counts | Use a mask, or turn the stroke into a shape in an editor |
| Works in the browser, refused by the cutter | Clip paths and masks are not real outlines | Intersect the shapes in an editor |
Questions
Which is faster, a clip path or a mask? A clip path is usually the lighter of the two, since it needs only an outline. Prefer it when the edge is hard.
Can a clip path be inverted? Not directly. Use a mask with a white background and the shape in black, as in the hole example above.
Can a mask or clip path be animated? Yes. The shapes inside are ordinary SVG elements. Inline in a page, CSS and JavaScript can change them.
How can the code be tried? Paste a complete example into the SVG viewer and edit the numbers.