Aleks G
Aleks G

Reputation: 57316

Fit image into auto-sized flex child

I'm having a very peculiar problem that I've been trying to solve for the last 2 days to no avail. The page I'm building has the following structure:

required structure of the page

I can easily achieve the A-B layout with the overall parent having display: flex; flex-direction: column; align-items: stretch and setting A to be flex: 0 0 auto and B to be flex: 1 1 0; min-height: 100px;

However I'm having real trouble layout out C and D inside B. I feel like the flex/row is the right approach for B, but I just can't get the specifics. So I'm trying:

.B {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    justify-content: space-between;
}

.C {
    flex: 1 1 0;
}

.D {
    object-fit: scale-down;
}

But clearly this is not sufficient. The image either doesn't scale down at all, scales down but distorted or leaves a lot of space around if I set it to also have flex: 1 1 0 with min width.

Any ideas how I can achieve what I need here?

UPDATE: I tried putting jsfiddle together here - https://jsfiddle.net/2gsrzwwq/3/ - but for some reason it wouldn't even honour height:100% on the parent. As far as the image fitting goes, I need the image to scale down to the height of the D div and then have the D block decrease in width to just contain the scaled down image - and for C block to occupy the remaining width.

Upvotes: 8

Views: 8523

Answers (2)

William Whyte
William Whyte

Reputation: 4971

I was struggling with exactly the same problem myself:

Maximum possible size image and div expanding to fill the space

I came up with the following solution, which I've also provided as an answer to my own question. See https://jsfiddle.net/wwhyte/vjLps7qs/; replace the image with http://placekitten.com/1600/900 to see landscape behavior.

.container {
  width: calc(100vw);
  height: 100vh;
  overflow: hidden;
}

.top {
  height: 1.25em;
  background: yellow;
}

.innerCtr {
  height: 100%;
  overflow: hidden;
}

.left {
  height: 100%;
  background: red;
  overflow: hidden;
}

.right {
  max-height: 100%;
  max-width: 80%;
  background: blue;
  float: right;
  object-fit: contain;
  overflow: hidden;
  position: relative;
  top: 50%;
  transform: translateY(-52%) scale(0.95);
}
<div class="container">
  <div class="top">
  </div>
  <div class="innerCtr">
    <img class="right" src="http://placekitten.com/1600/900">
    <div class="left">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
      dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum</div>
  </div>
</div>

What I think is happening is:

  • In the right class:
    • max-height, max-width, and object-fit give me the scaling I need.
    • float:right gives the position I need. (I got this from an article I found yesterday but have now lost, I'll edit this answer to provide attribution if I re-find it).
    • the transform is inspired by the article on vertical alignment at: http://zerosixthree.se/vertical-align-anything-with-just-3-lines-of-css/.
    • the 95% scale improves the visibility of the image.
  • In the left class, height:100% gives the panel size I want
  • The innerCtr class gives a parent for the image to calculate its height against
  • The container class fits the viewport to the browser window.

Even this isn't quite ideal. There's some weird interaction between the height of the top bar and the height of the image so that the bottom of the image is pushed out of the display. The amount pushed out is less than but related to the height of the top bar -- I haven't fully investigated. If you remove the top bar the CSS above behaves perfectly. I addressed this with the 95% scale and slight adjustment to the Y-transform, but this still doesn't behave exactly right at small window sizes -- the image isn't perfectly vertically centered. I had thought that setting height=calc(100vh-1.25em) on the container class might fix this, but in fact it breaks the vertical scaling of the image so it now only scales horizontally. This was completely unexpected behavior! But other than that, this meets my needs.

Upvotes: 0

Aleks G
Aleks G

Reputation: 57316

After a lot more struggle and another sleepless night, I came up with something sort-of working. The sacrifice I had to make is not adjusting the width of the image container and always settling on it being half the width of the screen (note that in the real app, there are no background colours, so it won't look as strange, rather there will be some extra white space). I'll have to discuss this with the client, but I think I'll be able to convince them. Here's what I came up with:

https://jsfiddle.net/2gsrzwwq/6/

HTML:

<div class="page">
  <div class="A">
  </div>

  <div class="B">
    <div class="C">
    </div>
    <div class="D">
      <img src="http://res.freestockphotos.biz/pictures/10/10677-illustration-of-a-red-lobster-pv.png"/>
    </div>
  </div>
</div>

CSS:

div {
  box-sizing: border-box;
}

.page {
  width: 100%;
  height: 250px;
  border: solid 1px black;
  margin: 5px;
  background-color: lightYellow;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
}

.A {
  background-color: lightPink;
  margin: 5px;
  flex: 0 0 50px;
}

.B {
  background-color: lightBlue;
  margin: 5px;
  flex: 1 1 0;
  min-height: 80px;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  justify-content: space-between
}

.C {
  background-color: lightGreen;
  margin: 5px;
  flex: 1 1 0;
  min-width: 100px;
}

.D {
  background-color: lightGrey;
  margin: 5px;
  flex: 1 1 0;
  min-height: 50px;
  display: flex;
  justify-content: flex-end;
}

.D img {
  flex: 1 1 0;
  max-height: 100%;
  max-width: 200px;
  object-fit: scale-down;
  object-position: top right;
}

enter image description here

Upvotes: 5

Related Questions