Understanding the CSS Clip Property

Learn about the underused and often misunderstood CSS clip property and understand how to apply it for some nifty effects.

Understanding the CSS Clip Property

Understanding the CSS Clip Property

Hi guys! First of all let me wish a belated happy new year to all of you. Today we are going to do something different: dig deep into one single CSS property. And that property is going to be the “clip” property.

I’m pretty sure some of you don’t even know there is a CSS property called clip since it’s probably the less used property in the world. It’s no big deal guys, we will cover pretty much everything you have to know about it.

The clip property aims at defining what portion of an element you want to show. You may have heard of this stuff as “crop”. There are a bunch of JavaScript plugins out there to crop an element, but actually you can do pretty much the same thing with the CSS clip property. Probably, with some limitations of course. We’ll take a look at them later.

Syntax

Let’s get started straight away with the syntax of the clip property which is not only a little bit weird but also probably difficult to understand at first glance. Please consider the following example:

.my-element {
	position: absolute;
	clip: rect(110px, 160px, 170px, 60px);
}

First thing you should note: the clip property only works on elements with position: absolute or position: fixed. It won’t work with relative or static positioning.

To be honest, I don’t really know why it is like that. At least, I didn’t find anything on the web on the topic so if you want to share some knowledge, please do.

As I said on Twitter a few days ago — and as you might think — this is a huge downside to the clip property.

However, it still might be interesting to experiment with the clip property and to find some cool use cases. Still with me? Great, let’s dig into the syntax.

The clip property accepts only three different values:

  • auto: this is the default behavior. Setting clip to auto is the same thing as not using clip at all.
  • inherit: well, it inherits the clip value from its parent.
  • a shape function. Currently only rect() exists.
clip: { shape | auto | inherit } ;

In most cases, you’ll want to use the shape function. I hope that someday we’ll have access to more shapes than just rect() (like circle() for example) but as of today, this is the only thing we can do. But don’t worry, we can still do pretty cool stuff with it. ๐Ÿ˜‰

The rect() function

Now, let’s finally dig into the rect() syntax. It requires four length values, separated by commas: top, right, bottom and left. As for padding or margin shorthands, it’s clockwise.

clip: rect(<top>, <right>, <bottom>, <left>);

Now pay attention because it can be tricky. Both the top and the bottom values define the offset from the top border and the left and right values define the offset from the left border.

schema-clip

Let’s make a little example to make things clear. Please consider the following CSS:

clip: rect(40px, 260px, 150px, 80px);

This means we want to keep the portion of the element between 40 and 150px vertically and between 80 and 260px horizontally. If it’s still not clear, please have a look at the following picture.

schema

Once you’ve understood how the rect() function works, it’s pretty easy to use the clip property, but I understand that it can be quite confusing in the beginning.

Now a quick question to see if you’ve wrapped your head around the clip property. Let’s say I have a 400px (width) by 200px (height) element. Now I want to remove 50px from the right of the element, 10px from the top, and 30px from the bottom. Which one of the following lines is the one I should use?

  1. clip: rect(50px, 30px, 350px, 70px);
  2. clip: rect(0, 10px, 30px, 50px);
  3. clip: rect(10px, 50px, 30px, 0);
  4. clip: rect(50px, 30px, 10px, 10px);
  5. clip: rect(10px, 350px, 170px, 0);

Click here to get the answer!

The correct answer is the fifth one: clip: rect(10px, 350px, 170px, 0);. Be sure to check this JSFiddle to have a visual explanation. Congratulations if you were correct. ๐Ÿ˜‰

Miscellaneous

Okay, now we have covered the basic usages of the clip property. I think there are a few more things you’d like to know about it.

First, the rect() function accepts auto as a value for each one of the four parameters. Basically it means “100%”. Let’s say you clip something to rect(0, 50px, 50px, 0) and want to display it in full size (100×100 let’s say). You could either do rect(0, 100px, 100px, 0) or rect(0, auto, auto, 0).

Secondly, since the rect() function requires length values for each parameter, it means it’s animatable either with CSS transitions or CSS animations. This is excellent news to make sweet effects. Of course you can’t animate to auto since it’s not an integer.

Third, percentage values for the rect() function are not supported. It’s too bad because it would make responsive clip stuff easier.

Browser support

And there you say “yes Hugo, this is nice but what about the browser support?”. You’re right to ask this question but you’ll probably be surprised to know that the browser support for the clip property is freaking good (according to MDN)!

Feature Chrome Firefox Internet Explorer Opera Safari
Support 1.0 1.0 4.0 7.0 1.0
8.0
Correct comma syntax supported in this version.

Yeah, you read right: Internet Explorer 4! But, until Internet Explorer 8, you have to use the old syntax which requires the four rect() values to be separated by spaces instead of commas. Okay no big deal, what about this?

.my-element {
	position: absolute;
	clip: rect(10px  350px  170px  0); /* IE4 to IE7 */
	clip: rect(10px, 350px, 170px, 0); /* IE8+ & other browsers */
}

Demos

In order to make things a little clearer, I made two demos. The first one is just a little example of the clip property. In this demo, I used a few things:

  • The clip property (oh, really?)
  • CSS transitions; as we saw earlier, values are animatable
  • A sibling selector (~ or +)

So what happens? At first, the image is cropped to be invisible. Then, when you hover the little “button”, the next image is being clipped to appear in about 0.5s from its center.

Pretty neat, right? Now let me show you what you can do as a real live thing with the clip property, some advanced CSS selectors, and CSS transitions.

Explaining the whole code would probably not only be a bit heavy but also certainly not that interesting since what was the most difficult to do was finding the accurate advanced CSS selectors to target only the pictures I wanted. Things like li:nth-of-type(n+7):nth-of-type(-n+9):hover img { ... }.

However there was a little overlapping bug caused by both CSS transitions and z-index when hovering pictures, which has been fixed by Ana Tudor so big thanks to her.

Anyway, if there is anything you’d like to know about this demo, be sure to ask a question in a comment. I’ll try to get back to you as soon as I can. ๐Ÿ˜‰

You may still wonder what else you can do with this strange property. Here are some ideas of use cases; if you have any, please be sure to share them.

  • An image gallery as above
  • A way for cropping variously sized pictures
  • CSS sprites (source)
  • An accessible method to hide content (source)

The next tutorial on Codrops will also show you how to use the clip property practically to create an expanding overlay effect: Putting CSS Clip to Work: Expanding Overlay Effect

Final words

In the end, what can we say about the clip property? First, that it’s a weird one. It has an odd syntax calling a function requiring counter-intuitive values. The fact that both, top and bottom values are offsets from the top border and not respectively from top and bottom borders, can be pretty hard to get. However, the W3C may fix this in the future by editing the syntax.

Note. In CSS 2.1, all clipping regions are rectangular. We anticipate future extensions to permit non-rectangular clipping. Future updates may also reintroduce a syntax for offsetting shapes from each edge instead of offsetting from a point.

Source W3C

Secondly, we can surely say it’s not a common CSS property. It has a fairly limited usage, but I can assure you it gives really a bunch of possibilities and I think its low usage is probably due to a lack of understanding. Be sure to use it when you feel like it’s a good place for it, especially since it has a really great browser support.

Well guys, I think we have covered pretty much everything you need to know about the CSS clip property in order to be able to use it in real live projects. If you have any question or want to show any related work, please be sure to do so. Thanks for reading!

Tagged with:

Kitty Giraudel

Non-binary accessibility & diversity advocate, frontend developer, author. Real life cat. They/she.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 46

Comments are closed.
  1. An A+ article, Hugo, as always. Top notch quality on Codrops, also as always. Thank you for taking the time to write this tutorial ๐Ÿ™‚ It’s been very beneficial since I haven’t really gotten into the CSS clip property before.
    Well done ๐Ÿ™‚

  2. I used clip property for cutting printer-friendly icons from sprite (because browser wouldn’t print a background icon);

    .line { position: relative; padding-left: 30px; } .line:before { content: url(img-sprite.png); position: absolute; left: 0; width: 20px; height: 20px; clip(0, 20px, 20px, 0); }

  3. chouette article, comprรฉhensible avec de bons exemples, merci pour le partage.

  4. Didn’t realise the x-browser support was so good – the clip property is a fantastic tool – particularly for providing differently proportioned images for responsive design – of course you have to ensure that your images will still work for each aspect ration and crop you use, but if you are into using a minimum number of elements.

    Also potentially useful for CSS sprites without worrying about providing whitespace around each sprite. Will give that a try for my next sprite sheet.

    Surely the position:absolute; limitation can be overcome by simply wrapping your clipped element in a relatively positioned parent?

    • I don’t think that will work. As far as I know absolute positioning does not work that way.
      You can have relative positions divs in an abosolute positioned div but if you put it in a relative position div it will simply ignore it and position itself in relation with the page
      Do Correct me I am wrong

    • creem: Actually, absolute positioning works just fine in relatively positioned elements. And it’s a very useful method for certain situations. An absolutely positioned element is positioned relative to it’s parent – as long as it is within a parent element that has it’s layout explicitly declared. It will position itself relative to it, and not the page.

  5. Hey there,

    Great article! Just one thing in the “The rect() function” section, the example you use is…

    clip: rect(40px, 260px, 150px, 80px);

    …shouldn’t it be this?…

    clip: rect(40px, 150px, 260px, 80px);

    Thanks!

    Chris

    • Hi!

      As far as I know, there is no mistake. I made a little JSFiddle to show you: http://jsfiddle.net/Pf7KU/1/. The first example is the one in the article. The second one is what you suggest.

      Hope it’s clear enough! ๐Ÿ™‚

  6. Loved the second DEMO..
    Its awesome…then 2nd one..will going to use it on my site too.
    Thanks for the demo

  7. I have never used this, instead relying on a wrapper-div to act as a viewing window. (Outer div given dimensions of the image size you want with overflow:hidden; then the image positioned within the div). I feel like it is a bit more flexible than the clip property. Anyone see a particular benefit to using clip other than less markup?

    • Less markup is actually a sufficient reason for using clip instead of two nested div if you want my opinion. ๐Ÿ™‚

  8. Awesome article!

    Just one question… Digging into the second fiddle, i changed this section:

    li:nth-of-type(n+4):nth-of-type(-n+6):hover img {
    top: -100px;
    }

    li:nth-of-type(n+7):nth-of-type(-n+9):hover img {
    top: -200px;
    }

    And removed the second :nth-of-type, changing the code to:

    li:nth-of-type(n+4):hover img {
    top: -100px;
    }

    li:nth-of-type(n+7):hover img {
    top: -200px;
    }

    And i don’t know if i missed something, but worked exactly the same way for me. Can you explain me why have you used this second :nth-of-type and what exactly do this work for?

    Thx ๐Ÿ˜€

    • Hi!

      This is an explanation of what I did:
      li:nth-of-type(n+4):nth-of-type(-n+6):hover img { ... } means “li tags between the 4th and the 6th”.
      li:nth-of-type(n+7):nth-of-type(-n+9):hover img { ... } means “li tags between the 7th and the 9th”.

      This is an explanation of what you did:
      li:nth-of-type(n+4):hover img { ... } means “li tags after the 4th (included)”.
      li:nth-of-type(n+7):hover img { ... } means “li tags after the 7th (included)”.

      So basically, your 1st rule also includes li tags after the 7th as does your 2nd rule. What I did was specifically targeting li tags between the 4th and the 6th then between the 7th and the 9th.

      Honestly both methods are good. Yours is probably slightly better performance speaking though. ๐Ÿ™‚

    • So the only difference is that your way is a little more specific, right?
      Now i’ve got curious about this performance thing… Do you know any tool to test css selectors performance?

      Thank you for the article again ๐Ÿ˜€

  9. I think the usage of property “clip” is not too much, it’s because it only can be used on image tag. And for sprites, it’s not the content of the website, so we don’t want to use the image tag. But I think it will be very useful in the responsive design!

    • The clip property can be used on any type of element as long as its position is set to either absolute or fixed. You’re absolutely not restricted to image tags.

  10. It would seem that using border radius you could use the clip property to create circular or oval shapes. I’ll definitely play around with the first demo to see what happens with that. Not saying border radius wouldn’t work with the second, or any more complex use case, but I want to keep it simple for a start.

  11. Hi! Definitely a great article but, as could make the image is displayed in full size or preferably fill the page?

  12. Cool! Pretty much exactly what I thought it was. I’ve come across clip before but never knew what the syntax was to actually use it.

  13. Just a quick css question. I see that you nicely used li:nth-of-type(3n+1) { clear: both; }, presumably to make the 4th, 7th, and 10th list items clear their rows and begin a new one. Is that part correct? If so, I notice that I can remove the rule in Dev Tools yet the behavior remains the same. Am I missing something?

    • Your understanding is correct but as the container is 300px and each of the items is 100px wide then every 4th element will drop onto a new row anyway as that’s the natural behaviour of floats when they don’t fit in its parent. However, it may have been added as a safety net incase people are dealing with different height elements as that would cause some weird layout issues with the floats if the clears weren’t in place.

  14. A great article. I’m just wondering whether it could be used with media enquiries to show a better image on mobile devices. Has anyone tried it?

  15. Hi there, if anyone is interested doing this animation with jquery, you cant do this directly through a CSS property but you need to “borrow” a different property which isnt used like backgroundPositionX. Here is an example:

    $(“.foo”).stop().animate({
    backgroundPositionX: 130
    },
    {
    step: function(now, fx) {
    now = 130 – now;
    $(this).css(“clip”, “rect(0px, 182px, 30px, ” + now + “px)”);
    },
    complete: function() {
    $(this).css({ backgroundPositionX: 0 });
    }
    }, 1000
    )

  16. can someone explain why its

    span:hover ~ img {
    clip: rect(0, 400px, 200px, 0);
    }

    and not

    span:hover ~ img {
    clip: rect(0, 0, 0, 0);
    }

    in the first demo.

    • Because the point it to show the image when the button is hovered, not to hide it (especially since it’s hidden from the start).