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.