Shiania White
Shiania White

Reputation: 455

Cropping the top 10% of an image using CSS?

How to crop the top of an image has already been described in this question. However, I am trying to crop an image by a percentage when the image dimensions are not known ahead of time. The container's resulting height should then be dependent on the size of the image.

Using the following, I can crop the top of an image, but it requires manually specifying the amount of the image to show in pixels. Is there a way I can specify I want to crop the top 10% of the image without knowing the image size ahead of time?

.container {
  overflow: hidden;
  position: relative;
  height: 370px;
}

.container img {
  position: absolute;
  margin-left: auto;
  margin-right: auto;
  bottom: 0;
  left: 0;
  right: 0;
}
<div class="container">
  <img class="img" src="http://placekitten.com/400/500" />
</div>

Upvotes: 4

Views: 4948

Answers (5)

Temani Afif
Temani Afif

Reputation: 273807

Here is an idea that rely on scale. You keep the image in-flow (don't use position:absolute) then you scale the container by 0.9 which is 90% of the total height then you scale the image by 1.1 to keep it's original size. This will trim the image by 10% but since transform is only a visual effect you may have space at the top or the bottom of the container (based on the transform-origin)

.container {
  overflow: hidden;
  outline:1px solid red;
  display:inline-block;
}

.container img {
  display:block;
}

.cut {
  transform:scaleY(0.9);
  transform-origin:top; /* The extra space will be on the bottom*/
}

.cut img {
  transform:scaleY(1.1);
  transform-origin:bottom; /* This should be bottom to cut the top*/
}
<div class="container">
  <img class="img" src="http://placekitten.com/300/200" >
</div>
<div class="container cut">
  <img class="img" src="http://placekitten.com/300/200" >
</div>

To be more precise we can consider calc() like below:

.container {
  overflow: hidden;
  outline:1px solid red;
  display:inline-block;
}

.container img {
  display:block;
}

.cut {
  transform:scaleY(0.9);
  transform-origin:top; /* The extra space will be on the bottom*/
}

.cut img {
  transform:scaleY(calc(1/0.9));
  transform-origin:bottom; /* This should be bottom to cut the top*/
}
<div class="container">
  <img class="img" src="http://placekitten.com/300/200" >
</div>
<div class="container cut">
  <img class="img" src="http://placekitten.com/300/200" >
</div>

Upvotes: 6

weegee
weegee

Reputation: 3409

An alternative would be to use the top CSS property in a negative fashion on a relative image like the snippet below. This works for an image of an arbitary width and height. Just adjust your top value, accordingly.

html,body{ height:100%; margin:0; padding:0; }
.container {
    overflow: hidden;
    position: relative;
    height: 100%;
    width: 100%;
    display:flex;
    margin-bottom: -10%;
    align-items:center;
    justify-content:center;
}

.container img {
    position: relative;
    bottom: 0;
    left: 0;
    height: 100%;
    top: -10%;
    right: 0;
}
<div class="container">
    <img class="img" src="http://placekitten.com/400/500" />
</div>


To remove the extra bottom margin, just subtract the margin-bottom equal to the amount you subtracted from the top. Here it is margin-bottom: -10%;

Adjust the top value according to your dynamic images. Also note, I added height:100% to your container so you can see the full image but the top part is cropped. I used flex for centering.
Test for another image but this time, it is cropped 50% from the top

html,body{ height:100%; margin:0; padding:0; }
.container {
    overflow: hidden;
    position: relative;
    height: 100%;
    width: 100%;
    margin-bottom: -50%;
    display:flex;
    align-items:center;
    justify-content:center;
}

.container img {
    position: relative;
    bottom: 0;
    left: 0;
    height: 100%;
    top: -50%;
    right: 0;
}
<div class="container">
    <img class="img" src="https://www.fujifilm.com/products/digital_cameras/x/fujifilm_x_t3/sample_images/img/index/ff_x_t3_002.JPG" />
</div>


Upvotes: 0

Thiago Leych
Thiago Leych

Reputation: 11

This should do the trick, using translateY (got that from How can I get the height of an element using css only)

As you can see, the .container does not have a hardcoded height, however, it will load with the original image height, which is 500px, even though the image is loading as 450px (500px - 10%)

.container {
    overflow: hidden;
    position: relative;
}

.container img {
    margin-left: auto;
    margin-right: auto;
    bottom: 0;
    left: 0;
    right: 0;
    transform: translateY(-10%);
}
<div class="container">
    <img class="img" src="http://placekitten.com/400/500" />
</div>

Upvotes: 1

Amoliski
Amoliski

Reputation: 159

I think the best approach to this without Javascript would be to translate the image up a certain percent, then scale it to fill the original height of the container. Anything else will leave a gap at the bottom.

.img_container img {
  transform: translateY(-50%) scale(2);
}

https://jsfiddle.net/amoliski/n4ojdzyr/

Upvotes: 1

Julien
Julien

Reputation: 2329

You can do this with a little bit of JavaScript (I've inlined it for simplicity's sake but you could move it to it's own function)

<div class="container">
    <img class="img" src="http://placekitten.com/400/500" onload="javascript:this.parentElement.style.height = (this.height * 0.9)+'px';" />
</div>

Here's a working JSfiddle.

Upvotes: 0

Related Questions