Icon for parent category 'Websites'

Masks & Clipping

A few chapters ago, I explained “the box model” and ways to change its dimensions. This is extremely useful … but it still looks like a box. With just those tools, your CSS layout will always look like a bunch of perfect rectangles. This often isn’t enough to achieve your desired look.

So, is there a way to change the shape of the box? To turn it into a circle, or a hexagon, or anything our design desires?

Yes, there is!

Clip-Path

The clip-path property allows you to specify a shape or path. Anything inside the shape is rendered; anything outside it is hidden.

There are a few built-in shapes:

  • circle(radius)
  • ellipse(radiusX radiusY at centerX centerY)
  • polygon(x1 y1, x2 y2, ...)
  • inset(width, height)

The last one is a rectangle, but phrased in a weird way. “Inset” means that it moves the edges of the original box inward by the specified amount. (So inset(0 0) is the original rectangle, while inset(100px 100px) is a much smaller one.)

If you want something more advanced, you can input any shape by giving its path. (A set of points and lines that creates a polygon.) Feel free to ignore this if you have no idea what “SVG” is.

  • path("an SVG path")
  • url(path.to.SVG#shape)

Try the different values in the example and see what happens!

Remark

There used to be a clip property as well. But it only supported rectangles and has since been deprecated, which means it will be removed at some point from all browsers.

More Clipping

We can also “clip” things the other way around. The original box stays the same, but we change how large we make the objects inside. (And anything that overflows is clipped or hidden automatically, as we saw before.)

This only applies to something called “replaced elements”, which you can remember as “external media” (such as images or video). These elements are loaded from outside the HTML document and have their own intrinsic size ( = the width and height of the image).

Object-fit

The object-fit property basically tells CSS how to deal with the original size of the image (in relation to the box in which it’s placed).

It takes these values:

  • fill: the image resizes to fill the given space. It doesn’t care if it squishes or stretches. (This is default.)
  • contain: the image maintains aspect ratio, but is scaled such that it’s fully contained. (It fits completely.)
  • cover: the image maintains aspect ratio, but is scaled such that it fully covers the whole available area.
  • none: the image isn’t resized at all.
  • scale-down: the image is resized to whatever is smaller, none or contain.

In the example below, try the different values. Also try removing object-fit entirely to see the horrendous result.

These values are universal. Whenever a property sets a size, you can supply these values.

Object-Position

Furthermore, use object-position: posX posY if you want to change the image’s location. These can be numbers, but it …

  • Also allows setting one number, which will be used for both posX and posY
  • Supports three named values: left, center, right

Again, these values are universal. Whenever a property is used for setting both an X and Y value, you can supply these values.

Try these variants in the example below!

Mask

Okay, so clip-path allows clipping according to a path. A set of points and lines, connected perfectly.

What if we want something more detailed? Maybe we don’t want a smaller rectangle, we want a rectangle with some part cut out, or some decoration at the bottom border.

In other words … what if we want to clip according to an image?

Then use the mask properties.

A mask is an image with transparency. In other words, parts of the image should contain nothing. Those pixels? They are hidden (or masked). Only the parts of the mask image that show something are used to render the box.

You can set all the properties at once with the mask property. When learning CSS, however, I think it’s much more valuable to always set every individual property by hand. Otherwise you waste time memorizing the exact order and inputs—and whenever you read back old code, you have to look up (or think hard about) what every part meant.

Set each property explicitly, and your CSS literally tells you what it does, which is much better for beginners.

  • mask-image: the URL to the mask image.
  • mask-position: where to place the mask within the element. (This is a position, so you can supply the same values as explained at object-position!)
  • mask-size: the size of the mask image. (This is a size, so you can supply the same values as explained at object-fit!)
  • mask-repeat: if the box is bigger than the mask image, whether to repeat it or not to fill all space (x and y direction). Default is repeat, the alternative is no-repeat.

Unfortunately, here we get our first example of a property with different support in different browsers. Whenever this is the case, browsers will add their own “prefix”: an extra bit before the property name. In this case, you also need -webkit- before each property if you want support everywhere.

Notice how the text is masked by the Pandaqi image. By default, it repeats. I set it to contain, so the whole image is used. Try adding other properties or changing the values and see what happens.

Example

I heavily rely on masking in my Pandaqi websites. They all have a shared “style”, mostly recognizable through buttons that look a bit wonky (“not-exactly-perfect rectangles”) and rectangles with wavy borders. This is all accomplished by a simple mask applied to these elements.

Continue with this course
Support me and this website!

Want to support me?

Buy one of my projects. You get something nice, I get something nice.

Donate through a popular platform using the link below.

Simply giving feedback or spreading the word is also worth a lot.