4

I have a container that holds an image. The image fills the container horizontally and the container responds to page size. See fiddle:

im html

<div id="container">
  <img src="http://silberschauer.de/img/pre/045.jpg" />
</div>

in css

#container {position:absolute;top:1em;left:1em;bottom:2em;
 width:30%;background:#0f0;overflow:hidden;}
#container img {width:100%;}

https://jsfiddle.net/t4um60k1/8/

Is it possible to have the image clip top and bottom equally if (and just if) the container gets smaller in y-axis than the image with css?

EDIT: You did not understand the question if your solution provides a green area ABOVE the image in any circumstances.

rhavin
  • 1,512
  • 1
  • 12
  • 33

2 Answers2

3

Is it possible to have the image clip top and bottom equally while staying top-aligned if the container gets smaller in v-axis than the image with css?

Yes, this can be done neatly and efficiently with CSS. Flexbox is well-suited for this sort of thing.

No need for JS. No changes to the HTML.

Add this to your CSS:

#container {
    display: flex;                   /* new */
    flex-direction: column;          /* new */
    justify-content: space-between;  /* new */
    position: absolute;
    top: 1em;
    left: 1em;
    bottom: 2em;
    width: 30%;
    background: #0f0;
    overflow: hidden;
}

#container::before, #container::after {
    content: '';
}

#container img {
    width: 100%;
    flex-shrink: 0;
}

https://jsfiddle.net/t4um60k1/10/


Explanation

We use flexbox to align the image on a vertical axis (flex-direction: column).

Then we tell the flex container that any child elements (aka, flex items) will align as space-between.

With justify-content: space-between, flex items are evenly spaced, with the first item aligned at one edge of the container and the last item aligned at the opposite edge. In this case, because we're in column direction, we're talking about the top and bottom edges.

To ensure that the image stays in the middle, we create "phantom" flex items on each end using pseudo-elements.

But why take these extra steps to center the image, when justify-content: center would have done the job with less hassle?

Because the second requirement of the question is that the image must be top-aligned when it exceeds the height of the container.

With justify-content: center the image will stay centered at all times.

But under the rules of space-between, if flex items overflow the container, space-between switches to flex-start, which aligns the image to the top (more details below).

Lastly, as flex items are generally flexible, flex-shrink: 0 is applied to the image to ensure it doesn't shrink from its original size.


Switching from space-between to flex-start

From the spec:

space-between

Flex items are evenly distributed in the line. If the leftover free-space is negative or there is only a single flex item on the line, this value is identical to flex-start.

center

Flex items are packed toward the center of the line. ... If the leftover free-space is negative, the flex items will overflow equally in both directions.

(emphasis mine)

source: https://www.w3.org/TR/css-flexbox-1/#justify-content-property


Note that flexbox is supported by all major browsers, except IE 8 & 9. Some recent browser versions, such as Safari 8 and IE10, require vendor prefixes. For a quick way to add all the prefixes you need, post your CSS in the left panel here: Autoprefixer.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
0

You can simply add some css tricks to your image. It's not the modern way, but it works.

#container img {
  width:100%;
  position: absolute;
  margin: auto;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}

jsfiddle

When the container gets smaller than the image in v-axis, the image is align-top. enter image description here

smdsgn
  • 1,736
  • 1
  • 11
  • 11
  • I don't understand why someone downvote this peace of code. Did you see the jsfiddle, It works. And it is supported by old browsers, not like flexbox... So if I said something wrong, it's better to explain with a comment. – smdsgn Jan 25 '16 at 08:26
  • I could be because your code doesn't answer the question. Although the image is centered in the container, it doesn't align-top when the window gets smaller. It remains centered at all times. – Michael Benjamin Jan 25 '16 at 12:20
  • You sure ? Look again my fiddle because the image is align-top when the window gest smaller. Maybe I'm missing something but I don't see any difference between our two results. – smdsgn Jan 25 '16 at 12:29
  • If you reduce the window in your demo, the image gets cut off evenly on top and bottom. Reduce as much as possible. You're left with the nose. It's supposed to be the top of the image (the forehead and hair). – Michael Benjamin Jan 25 '16 at 12:32
  • Interesting. In Chrome on my PC the behavior is different. Your image is correct. – Michael Benjamin Jan 25 '16 at 13:32
  • You reassure me, I was beginning to think I was stupid. – smdsgn Jan 25 '16 at 13:38