How to crop an image in CSS

Image cropping with CSS is a well-covered topic, and there are plenty of articles about it on the internet, so why should there be another one? This is a good question, and I have an answer. Many posts cover 1000 and 1 hacky ways to crop your image, which might mislead the novice. We’ll drop the workaround techniques and concentrate on those with the original purpose of cropping images. Thankfully, now we have a good set of these techniques and even more.

“Why would you want to crop an image in a browser?” Would I ask?

“Why can’t we stop asking why and go to the topic, German?” You can reasonably ask me in response.

We need to continue asking “why” because we want to make a well-balanced decision. We want to understand where it is applicable and what it costs us. Sometimes we want to crop an image using CSS simply because we are front-end developers and cannot do this on a server. This may be either because of the lack of knowledge or access to the server. The good news is that there are some pre-built solutions on the plate. And before we start diving into cropping images via plain CSS, let's take Uploadcare to experiment a little.

Look at this beautiful picture of burning coals:

Picture of burning coalsPicture of burning coals

With some URL adjusting, we can crop the image and concentrate on the burning coal behind the center one on the right.

Let's take the original image URL:

https://ucarecdn.com/683ccc91-2a49-4b31-bec7-250f8f4a2d43/image.png

And apply some URL transformations:

https://ucarecdn.com/683ccc91-2a49-4b31-bec7-250f8f4a2d43/-/preview/1600x900/-/crop/500x500/680,180/image.png

We used a -/preview/ to put an image inside a known tile without changing its proportions. Then we added -/crop/:dimensions/:alignment/ modificator. :dimensions contains two values with width and height in pixels (percent values are also allowed). And :alignment means horizontal and vertical offsets in pixels or percents separated by ,.

Here is the result:

Cropped picture of burning coalsCropped picture of burning coals

Every Uploadcare URL transformation generates a modified image version on-the-fly and is cached on CDN nodes. Don't hesitate to try it yourself if you like the approach!

Anyway, this method forces us to use the external CDN service to keep our images. But what if our use case implies a simple CSS-based image cropping? For example, we want to implement a parallax effect or have a fixed-size carousel to display different images. Also, the lenses on e-commerce websites use cropping a lot.

Different ways to crop your image

In this article, we’ll look at the existing ways to crop an image using CSS from the most straightforward to the most complex:

  • The <img> tag with object-fit and object-position
  • The background-image property with background-size and background-position
  • Image or background image with persistent ratio
  • Round cropping using border-radius
  • Complex paths of cropping with clip-path

The <img> tag with object-fit and object-position

The first and basic approach. Use the common <img> element and two properties: object-fit and object-position. Let’s investigate object-fit first. I won’t do the formulation work and will use the definition from the CSS standard.

The object-fit property specifies how the contents of a replaced element should be fitted to the box established by its used height and width.

Please use the provided link to a standard to discover different variants of the value. I will supply several live examples to illustrate them.

The idea of the object-fit is that we have an <img>, and it has a specified size:

<img
  class="fitting-image"
  src="https://ucarecdn.com/dbffe489-e4c9-449f-a013-2f2381eb778c/-/preview/400x300/image.png"
  alt="Original Image"
/>
.fitting-image {
  width: 150px;
  height: 150px;
  object-fit: <some value>;
}

In this case the size of an <img> is 150 px by 150 px. The size of the picture we want to demonstrate is 201 px by 300 px. We need to reconcile this difference somehow. The object-fit property allows us to set the strategy of reconciliation. I have to admit that it doesn’t always lead to cropping. Sometimes you get stretching or scaling down. Still, it is useful to provide the full picture of object-fit, not to mislead you.

The scale-down value looks not that obvious. Let’s observe the following example to gain a better understanding of how it works.

At this point we’ve finally arrived at the object-position CSS property. This property exists to help us transition the displayed object. Have a look at the following examples. Read captions below to understand the variants of object-position property.

Now you understand how to adjust the position of a cropped image.

The background-image property with background-size and background-position

Phew, the last part was quite huge. Will this one be the same? Well, I hoped it would be something very similar so we could shorten it a bit. I thought we would see a little semantic difference, to which I would dedicate a small paragraph and a few examples. The background image turned out to have the false bottom and another one then.

Let me first point to the standards: background-image, background-size, and background-position. Don’t spend too much time there if you want some practical answers. Better use the examples below and investigate their CSS. Use these links if you need an in-depth understanding or some inspiration for experimenting.

Where would you like to use the background image instead of ordinary <img>? Well, using background images doesn’t provide you with a drag and drop feature. If we’re talking about perception in this context, I suggest using background images to create the mood. Plain images are good if they are the active actors of the narrative.

However, let’s step aside from perceptual reasoning and get back to the basic examples:

You can see that the initial state of the background image would rather have a slabbing name than the cropping. Other examples display the behaviour we expect from cropping. Using the background-size property gives you more flexibility in terms of a size you can set to stretch your picture.

.strange-size-background-image {
  background-size: 1234px 5678px;
}

The code above is perfectly valid.

The next part gives you extra cropping flexibility. You might remember the box-sizing property telling a browser what to include in the width. There are two properties for a background utilizing the same idea: background-origin and background-clip.

I’ve created an example demonstrating nine possible combinations:

Both background-origin and background-clip have three possible values: border-box, padding-box and content-box. In the first case, you define the place for settling background image. For border-box the upper left corner of the background would be at the upper left point of a border. The logic is the same for padding-box, and content-box. The only difference is where you apply the background.

The background-clip property tells where the “crop” happens. Have a look at the following CSS:

.origin-border-clip-content {
  background-origin: border-box;
  background-clip: content-box;
}

It makes your background image start at the top left corner of the border and continue to the bottom right. But you’ll see the only piece under the content because of clipping applied.

The described two properties were the first false bottom I mentioned. Why did I call them this? Because they are rare guests in other articles on the topic, and I only discovered them in the specification. And what is the second false bottom? It’s clipping to text.The fun part about the text value of the background-clip property is that it comes from a so-called HTML Living Standard. The story behind it is the conflict of the old days, and the -webkit- prefix is the old-day approach for verifying new features in browsers. These two factors solely can introduce a plot and a twist to this article, but let’s not go that far. Have a look at this charming CSS class:

.background-clipped-to-text {
  color: transparent;
  background-clip: text;
  -webkit-background-clip: text;
}

It allows us to implement the beautiful effect of having a picture coloring our text.

Before writing this article I knew that this effect is available in SVG and was going to describe it to you. Now we no longer need this as we have a much simpler CSS solution.

Image or background image with a persistent ratio

The thing that used the most generous number of hacks in previous times was preserving the content ratio of a cropped image. When you use an image having the 100% width of a container, you cannot set height explicitly to keep the proportions. The aspect-ratio CSS property will help you here. It has the decent support of modern browsers but not that good to stay careless. Please check caniuse.com for verification.

Round cropping using border-radius

Correctly set radius of a border and hidden overflow are two instruments of CSS masters drawing their pictures. We’ll use their techniques to do some rounded cropping. We won’t stay here for too long because this approach works with both usual and background images, and we’ve already covered them.

The beautiful picture of a dog above has a non-rectangular border. You can try hovering it and see that the browser doesn’t assume an invisible rectangular border but the actual one.

This CSS property is the only addition required to apply the proper cropping:

.some-class {
  border-radius: <required value>;
}

The syntax of the border-radius property is sophisticated, and I recommend using a good reference to understand it better.

Complex paths of cropping with clip-path

This technique is the most complex among the named and the most powerful. It might require a separate article to cover all its possibilities. Or a dedicated book if you are interested in the SVG topic. We’ll cover its syntax, basic usage and see several examples.

If you think of this CSS instrument for a while, you might recognize that in some sense, it’s the only one named in this article that is dedicated to cropping images. Other CSS properties have cropping as a side effect - did we even bother to consider them? Because these properties are much more accessible in use. Also, sometimes you need cropping as a side effect and not the major one.

Let’s look at the syntax of the clip-path property first:

.clipped-image {
  clip-path: <clip-source> | [ <basic-shape> || <geometry-box> ] | none
}

We’ll investigate each from the most primitive to the most complex.

none

No clipping path gets created.

basic-shape and geometry-box

This part of syntax allows us to operate using the predefined set of shapes. Despite its limitations, it is rather powerful. For basic-shape you can use inset(), circle(), ellipse(), polygon() or path(). The last one provides a possibility to use SVG syntax for cropping.

We could omit the geometry-box value. Well, we can use it and skip the basic-shape one as well. When you use geometry-box, you limit cropping with a specific area, e.g., padding-box or SVG-inspired stroke-box. I won’t provide examples of the geometry-box applied. If I tried to show every sample, I would need at least 42 of them.

Still, you can understand by looking at the examples of the background-clip property presented above.

clip-source

The clip-source here means the CSS url(<A link to clipPath element>) function. The majority of browsers at the time of writing do not support the external SVGs. What does this mean for us as developers? The syntax implies that somewhere in the page’s markup, you have an <svg> element containing a <clipPath> with a special id. The almost not supported external SVG is a separate file. Also, we’ll put the <clipPath> inside <defs>, a special place inside SVG dedicated to defining but not drawing. See the following example:

You can find the SVG I used in the HTML part of this example. It contains the <path> element with the description of a required zigzag in the d property. I was very satisfied at this moment, but the CSS exceeded my expectations. It turns out that I can crop an image visually and make the text around it reflect its shape. Please note that this approach works with only floating elements. Look at the following example:

You might think the shape-outside is an obscure feature from one of the top-notch nightly builds. I am glad to disillusion you as we work with a mature CSS property supported by 94.61% of available browsers. The bad part about the property is that you can’t use your SVG for clipping from the previous step. I think that the CSSWG and MDN materials are misleading about the availability of the path syntax - it doesn’t exist on the W3C website, and I couldn’t find it among the code on GitHub or make it run in Firefox or Chrome. Please follow my issue created in the MDN GitHub repo for updates on the investigation.

I manually transformed the named above SVG path property and used the polygon value of shape-outside. I also utilized the shape-margin: 1em to set some free space around my image for better visual effect. Please investigate the CSS section of the CodePen example.

Final thoughts

Images cropping with CSS turned out to be a much broader topic than I could have imagined. If you need a cropped image with no dynamics, I would recommend using pre-built CDN APIs solutions like Uploadcare. You can also settle a server, but it would require additional maintenance, so weigh the pros and cons. If you need your application to be responsive or rich in UI, consider the described options and choose the most suitable for your needs. Now you can do what you need without disputable hacks.

A new hope