Today I want to continue with more examples starting with one where we'll use a variety of SVG elements to build up a more complex clipping path.
Multiple Shapes Inside a clipPath Element
In one of the examples last week I used a single clipping path to clip multiple elements, by grouping the elements and referencing the clipping path on the group as opposed to the individual elements. You can also use multiple SVG elements to create the path.
In this example, I'm sticking with the circle and triangle group from last week. Here's a reminder of what it looked like unclipped.
This week instead of a single element to create a clipping path, I've combined 4 circles, a polygon, and some text to form something of a complex clipping path.
Here's the result. Notice that the clipping path doesn't need to be a single contiguous path. Aside from the text, none of the shapes in the path overlap each other. I also want to call your attention to the two semi-circles at the bottom. These shapes in the path appear to be clipped, but they aren't.
Here's the result again, though this time I added an outline to the two circles in the path that appear to be getting clipped. The blue outline shows the full path as created. The reason they aren't completely filled in is because there's nothing to reveal. These two circles revealed as much as they could of the triangle, but where the triangle ends only the background of the page was left to reveal.
Clipping an Image
Clipping an image is the same as clipping any other element or group of elements. This example uses the same clipping path as the previous examples, but I've replaced the group containing the circle and triangle with an image I took about 10 years ago of the Strawberry Fields memorial for John Lennon in Central Park.
At first glance it might appear as though the clipping path is different. You can see more of the two circles at the bottom of the viewport. They are the same though. The image fills the entire viewport, where in the previous examples, some of this area was empty.
Let's close with one more example using the same image of Strawberry Fields. The image is larger than the height of the viewport I've been using to this point. Here's the full image in a taller viewport.
One way you might want to clip this image is to show the circle with the word IMAGINE and clip everything else. I'd also like this to fit inside a viewport that's 330px in height and instead of the red outline, let's change the background color of the SVG element.
Because I want only the circle in the center of the image to be visible, I used an ellipse as the clipping path as the circle looks like an ellipse given the angle of the picture. I also moved the image up a little (y=”-100″) so that the word imagine was roughly in the center of the viewport.
Here's the result. I adjusted the values cx, cy, rx, and ry of the ellipse through trial and error until I had something close enough to what I was after.
Images will play even more of a role in SVG masking, which I'll get to next week.
Closing Thoughts
Hopefully you agree that clipping paths are relatively easy to work with in SVG. You create the path inside the clipPath element and you give the clipPath an id that you reference when and where you want to use the clipping path.
You can add the reference to any SVG shape or image and you can add it to a group of elements and images as well.
The main thing with clipping paths is that they're either/or. What's inside the clipping path will be visible and what's outside the clipping path is hidden.
That's not the case with masks which can partially reveal what's beneath the mask. Next week I'll continue this series and talk about masks, which are similar to clipping paths, but can be used for different and I think more interesting effects.
The last couple of weeks, I've been talking about SVG clipping paths and their attributes. So far in the series I've stuck to rectangles as the path in order to keep things simple, however you aren't limited to using rectangles. In fact clipping paths become a lot more interesting when they aren't rectangular or when you clip something more than a simple shape.
Today and next week, I thought I'd walk you through a variety of examples. I'll show you how to use paths and text to clip elements, how to clip groups of elements at the same time, and how to create clipping paths from multiple SVG elements. I'll close next week with an example where I clip an image using a variety of SVG elements.
Paths as Clipping Paths
Let's start with a couple of examples that use the path element to create the clipping path. In case you missed the previous posts in this series, here's the unclipped shape we're starting with.
Hopefully the code is familiar enough to you. If not I'll point you back to this post covering the basics. Assuming it is familiar, you can see I've created a circle inside the SVG element and filled it with a somewhat muted green. The red outline represents the boundary of the SVG viewport. As you can see the result is a green circle inside a red outline.
Now let's add a clipping path. I've defined the clipping path inside the <clipPath> element and I've given the clipPath element an id of path–1. Next I created a clipping path with straight lines using the <path> element. If you need a review of SVG paths, here you go. Finally I added a circle, which references the clipPath id it its clip-path property.
I'm not showing it in the code above, but I also added a path element after the circle with no fill and a blue outline so you could see the boundaries of the clipping path. Here's the result.
The circle is visible wherever it's inside the path and it's hidden or clipped wherever it falls outside the boundaries of the path.
This next example is similar to the first. The only difference is that I used curves instead of straight lines to create the clipping path. Here's another post if you need a reminder for working with curved paths.
Once again I created an additional path not shown in the code so you can see the outline of the clipping path.
Perhaps neither of these two examples is the most exciting use of clipping paths you'll ever see, but I hope you'll agree they're a little more interesting than a simple rectangle. Not that there's anything wrong with rectangles as we'll see in the next example.
Clipping SVG Groups
You aren't limited to clipping a single SVG shape like I've been doing with a circle the last few weeks. You can group SVG elements together and clip the entire group or clip only some of the elements in the group.
Here I added a triangle to the circle from the previous example and wrapped both inside a group element. I'll show the code momentarily, but here's what the group looks like unclipped.
I created the triangle using the polygon element with three points specified. I wrapped both the polygon and the circle with the group element, <g>. Since the focus of this example is the group of elements (circle and triangle) I went with a simple rectangle as the clipping path.
Notice that I referenced the clipping path and applied the clip-path property to the group and not to either or both of the elements inside the group.
Had I applied the clip-path property to one of the elements instead of the group, only that element would be clipped. Here's the same example with the clip-path moved to the polygon.
You can see the triangle (the polygon) is clipped, but the circle isn't.
Text as a Clipping Path
SVG also allows text to be used as a clipping path. Here I've kept the group that contains the circle and triangle, but changed the clipPath to a text element.
Here's the result and you can see the text allows part of the circle and part of the triangle to show through. The second 'p' in Clipping reveals a little of both shapes.
You can style SVG text in different ways so changing something like the font family of the clipping path is as simple as changing the value of the font-family property inside the text element. Alternatively you could give the <text> element a class and then use CSS to style the class and change the font-family.
The only difference between this example and the previous one is the font-family which I changed from Helvetica to Georgia.
Closing Thoughts
As I've hopefully shown, clipping paths can be more than simple rectangles. Today I presented straight line and curved paths as well as text as the clipping path. I also showed how to clip multiple elements inside a group.
Next week I want to share a few more examples. We'll look at using multiple SVG elements to create a more complex path and then we'll use that multi-element path to clip an image.
Last week I showed you the very basics of SVG clipping paths. I mentioned the difference between clipping and masking and then worked through a simple example to show you SVG clipping paths in action. I closed by showing how to do the same thing using the CSS clip-path property.
As you might guess, there's more to SVG clipping than what I talked about last week. Today I want to dig a little deeper into the basics. I want to talk about the different attributes you can add to the clipPath element to give you more control over your clipping paths.
First, though, I want to talk about the initial clipping path.
The Initial Clipping Path
The SVG canvas is infinite. You can create a rectangle and position it 4 trillion pixels to the left and SVG is fine with that. My laptop monitor has a lot less than 4 trillion pixels, but the SVG canvas is theoretically infinite in size. The viewport functions as a clipping path for the canvas.
If you've read any of my previous SVG posts, you've likely noticed I add an outline around the SVG viewport in most examples. The reason is to show you its boundaries and to show that when all or part of an element moves outside of the viewport, it's no longer visible.
The root SVG element operates according to CSS layout rules. It's a block level element and you can position it where you want in your document. You can style it like you would other block level elements. For example you could apply margins to the SVG element or float it left or right if you want.
Another property you can set on the SVG element is the overflow property. The default value of overflow is usually visible, but in the case of SVG elements, the default is hidden, which means the SVG element clips anything outside it's boundaries. This is the initial clipping path.
Other SVG elements like marker and pattern establish new viewports within the root SVG viewport. These too have overflow set to hidden by default creating an initial clipping path for the element.
You can change the default behavior in a couple of ways. One is to explicitly set the overflow property to visible allowing what's both inside and outside the viewport to display.
Here's an example where I positioned an SVG rectangle's top left corner at –50px –25px so that some of it sits outside the viewport.
The only difference between this and the previous example is that I've set the overflow property to visible. The clipped portion of the rectangle can now be seen, though outside of the viewport boundaries.
I can't think of too many reasons why you'd want to do this with the root SVG viewport, but you can do it. The only reason I've ever done it is in examples like this when I want to show the effects of setting overflow: visible.
The other way to change the initial clipping path is to use the CSS clip-path property on the SVG element. As I mentioned last week, the CSS clip-path property doesn't have great support at the moment. I bring it up now mostly to let you know you can change the default behavior of a rectangular viewport.
Here I changed the clip-path of the root SVG element to be a circle instead of the default rectangle. Inside the root SVG I added a rectangle.
The result is the entire viewport is clipped to the shape of a circle. Even the outline I added to show the boundaries of the viewport is clipped.
Since the code may or may not work for you depending on the browser you're currently using, here's an image of the result in case the above SVG isn't displaying correctly.
There is a use case for changing the initial clipping path. If you've created a viewBox, especially one with the preserveAspectRatio set, you might prefer the initial clipping path to match the viewBox as opposed to the viewport. If that's the case you would want to set the clip-path to the dimensions and coordinates of the viewBox instead of the default which will match the viewport.
clipPathUnits
One of the things you may have noticed about working with SVG is there are different coordinate systems that might be in use at any given time. You might be working with the coordinate system of the SVG canvas, the viewport, the viewBox, and yes, even the clipping path.
You define the coordinate system for the clipping path using the clipPathUnits attribute. It's value can be either userSpaceOnUse or objectBoundingBox
The value userSpaceOnUse is the default. It's the same as not setting the clipPathUnits at all so it's the value that's been in effect in the examples last week and so far in this post. It represents values in the current user coordinate system when the clipPath element is referenced. That will usually be the coordinate system for the viewport.
The value objectBoundingBox establishes the bounding box of the element to which the clipping path is applied as the boundaries for the coordinate system of the clipping path. What this means in practice is your values will need to be between 0.0 and 1.0 instead of pixels or some other absolute measurement.
Here's an example where both the right half and bottom half of a circle have been clipped and only the top left quadrant is visible. The blue outline represents the clipping path.
The clipPath is a rectangle with equal width and height of 100px. I've also added clipPathUnits=“userSpaceOnUse” to make it clear, which user coordinate system is in place. Because the system is userSpaceOnUse, the values in the clipping path represent pixels. So x="10" means x="10px" and similar for y, width, and height.
Here's the result, which is probably what you expected.
Here's the example again. The only difference is I've changed the clipPathUnits to objectBoundingBox and because of that change, I've also changed the units used to define the clipping path to 0, 0, 0.5, and 0.5.
I've redrawn the blue rectangle to reflect the complete size of the objectBoundingBox, which is now the boundaries of the circle element. Hopefully this illustrates why I chose values of 0, 0, 0.5, and 0.5 to define the width and height values inside the clipPath.
Values of 0 for x and y represent the left and top edges of the circle's bounding box and 0.5 for the width and height represent half the distance to the right and bottom edges of that same box.
The clip-rule Property
Last year when I covered fills and strokes, I mentioned the fill-rule property, which is used to determine what's considered inside the region to be filled and what's considered outside the same region.
There's a similar clip-rule which can take the same values as the fill-rule, nonzero or evenodd, to determine what's inside the clipping area and what's outside. The value of the clip-rule property will be either nonzero or evenodd.
As was the case with fill-rule, I'm not quite sure I understand how either algorithm works, so I'll again present the definitions of each as taken from the spec, along with an example of each.
nonzero—This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and then examining the places where a segment of the shape crosses the ray. Starting with a count of zero, add one each time a path segment crosses the ray from left to right and subtract one each time a path segment crosses the ray from right to left. After counting the crossings, if the result is zero then the point is outside the path. Otherwise, it is inside.
evenodd—This rule determines the "insideness" of a point on the canvas by drawing a ray from that point to infinity in any direction and counting the number of path segments from the given shape that the ray crosses. If this number is odd, the point is inside; if even, the point is outside.
I find the easiest way to know which value to use is to try them both and see what happens. Most of the time the default, nonzero will likely be what you want.
Closing Thoughts
I realize most of what's in this post is digging into the weeds a bit, but I'd rather give you too much information than not enough. Hopefully it hasn't been too much and combined with last week's post you now have a general idea of how to work with clipping paths.
However, I haven't given you much variation in the examples so far. That was on purpose so we could focus on how this all works. Now that we've worked through the basic information I want to present some varied examples and that's what I'll doc the next couple of weeks.
Last year I published several series (25 posts in total) on the subject of SVG. First was a series on the basics of creating SVG shapes, lines, and curves and adding fill colors and strokes to them. I followed that series with another with more intermediate topics such as reusing SVG code and using patterns and gradients to fill SVG graphics. I closed the year with a series on SVG Text.
As you can probably guess, I'm not done talking about SVG. I have a few series planned throughout the year and maybe into next year starting today with a series of posts about clipping paths. I'll follow the clipping path posts with a similar set of posts about masking with SVG.
Both SVG and CSS have ways to create clipping paths. however CSS support is still somewhere limited. No Microsoft browser currently supports the CSS clip-path property. Neither does Opera Mini. Everything else offers partial support. The good news is, all browsers support SVG in general and clipping in particular.
Clipping and Masking
Let me start by saying a couple of things about the difference between clipping and masking as they're conceptually similar. Both are used to visually hide and show parts of an element or image.
Clipping paths define a hard boundary between what's visible and what isn't. Anything inside the clipping path is visible. Anything outside is hidden.
Masks, on the other hand, cover all or part of an element and control how much of the element shows through. 100% of the element might show through one pixel of the mask, while 0%, 50%, or 29% might show through a different pixel. Masks can actually behave exactly like clipping paths, but I'll save that until we talk about masks in a few weeks.
Simple Example
The easiest way to understand clipping paths is to see them in action so let's jump into a simple example.
Here I created an SVG with a viewport of 660px by 220px to which I added a red outline so we can see its boundaries. Inside the viewport I created a circle with a radius of 100px (r="100"). I set the center of the circle to be located 110px from the top and left edges of the viewport (cx=“110” cy=“110”).
I changed the fill from the default black to #9c9, which should be a desaturated green. I haven't added a clipping path yet. This is the before so you have a frame of reference for when the circle is clipped.
Now for the after. Let's clip the circle so only its top half is visible.
To add a clipping path you define the path using the SVG clipPath element and then you reference the clipPath by adding a clip-path property to the element or group of elements to be clipped.
Here I added a clipPath element between <defs> tags and gave it the highly original id of "clip–1." Inside the clipPath element, I created a 200px by 100px rectangle located 10px from the top and 10px from the left edge of the viewport.
The circle references the clipPath using the clip-path property.
1
clip-path="url(#clip-1)"
Note the form. The value of clip-path will be url() with a reference to the clipPath you want to use inside the parenthesis.
Here's the result. The extra blue rectangle is something I added here to show the clipping path boundaries as the clipping path itself is never displayed.
As you can see anything inside the clipping path remains visible and anything outside the clipping path is hidden.
In the example I used a rectangle to create a simple clipping path, but you aren't limited to rectangles. You can use any of the basic SVG shapes to create clipping paths. You can also use text as the path and you can create your own paths using the <path> element. You can even combine all three to create some unique clipping paths. I'll show examples of all of these later in the series.
CSS Clipping Paths
Since I did mention CSS clipping paths, let me quickly show you how to use them. Remember this won't work in every browser so I suggest sticking with SVG for now, but once support is there my guess is we'll use the CSS method more.
In CSS you'll use the CSS clip-path property, as opposed to the SVG property of the same name, to either reference an SVG clipping path or to create the path using one of the allowed CSS shapes, polygon(), circle(), inset(), and ellipse().
Here's an example using inline CSS to reference a clipPath created in SVG.
It looks very much like the SVG example. In fact there's only one small change. Instead of adding the SVG clip-path property to the circle, I added the CSS clip-path property inline.
This example includes style="clip-path:url(#clip-2)" where the previous one included clip-path="url(#clip-1)". Not much of a difference and you might not even notice any difference with a quick glance.
Depending on what browser you're currently using, you may or may not be seeing the correct result. The examples should both look like the previous one where the bottom half of the circle is hidden. Here's an image just in case.
In this next example I used the CSS clip-path property to directly create and apply the path as opposed to referencing the id of a path defined elsewhere.
Instead of referencing a clipPath, I created the clipping path using a polygon that takes the coordinates of the circle as its own coordinate space, which is why the initial coordinate is 0px 0px instead of 10px 10px.
Note that Firefox doesn't support this method of adding the path directly. Firefox only supports referencing the id of a clipping path. If you're viewing this in Firefox near the time I've published this post, you'll see the full unclipped circle instead of the half circle from the last few examples.
Hopefully you agree the SVG method and the CSS method aren't all that different. CSS allows you to create and apply the clipping path in one place, but it's slightly more limited in what you can use to create the path.
Closing Thoughts
Let's leave things here for today. I think you'll agree that working with clipping paths in SVG isn't too hard. If you know how to create basic SVG shapes and understand how to define something in one place and reference it in another, much of what's here likely looks familiar.
In the future, I expect we'll do more clipping in CSS, but for now browser support isn't there and SVG is the better option until that changes. I don't expect it will be a difficult transition. If you understand how to create a clipping path using SVG, it should be easy enough to make the change to CSS when the time is right.
For the remainder of this series, I'll stick to SVG clipping paths where you define the path in one place using the clipPath element and then reference the id of the clipPath using the SVG clip-path property on the element you want to clip.
Next week I want to continue with SVG clipping paths. There are a few more details to talk about. In the weeks after I'll offer some examples so you can see clipping is more than rectangles hiding circles.