0

I want an image on a webpage to grow/shrink to the available height or width of a flexbox and keep the original aspect ratio.

I have used max-height:100%; max-width:100% on the image but that doesn't work.

The page always fills the browser window without overflow. It has 3 rows:

  1. a title at the top with fixed height
  2. an article, with image and description side by side
  3. a footer at the bottom with fixed height

The image should grow/shrink with the available height or width, depending on the aspect ratio of the image and surrounding box.

This means most of the times empty space is present left or under the image.

This is a example page:

<html><head>
<title>Title</title>
<style type="text/css">
*    {font-size:100%; font:inherit; padding:0; border:0; margin:0}
body {background:#FFC; color:#333; font-family:sans-serif}

body                {display:flex; flex-direction:column; height:100%}
h1                  {text-align:right; margin-right:20em; background:#CAA}

article             {flex:1; display:flex}
article figure      {flex:1}
article figure img  {display:block; max-width:100%; max-height:100%}

#description        {width:20em; background:#ACA}
footer              {background:#AAC}
</style>
</head><body>
  <h1>Title</h1>

  <article>
    <figure> <img src="https://placekitten.com/987/765" /> </figure>
    <div id="description">
      <p>The description.</p>
    </div>
  </article>

  <footer> Footer </footer>
</body></html>

I made a JSFiddle, but it does not place the footer fixed at the bottom as it does when viewed in a separate browser window.

It would be nice to use flexbox as it's promoted for it's easy layout. But if this cannot be done with it I'll use absolute positioning.

Kwebble
  • 2,065
  • 14
  • 23
  • Make a div use flex-box that stretches, put the image inside, give that 100% Max width and height. Im on my phone cant give an example Sorry. – Randy Jun 03 '16 at 22:13
  • I think I did that, but the image does not shrink when the window height is reduced. – Kwebble Jun 03 '16 at 22:30
  • possible duplicate: http://stackoverflow.com/a/37575733/3597276 – Michael Benjamin Jun 03 '16 at 22:38
  • @Michael_B that is about the height only. I want the image to scale to the available width or height. – Kwebble Jun 04 '16 at 09:36
  • Since I didn't find a solution with flexbox I switched to absolute positioning. See the updated JSFiddle: https://jsfiddle.net/0nw61s4t/1/ – Kwebble Jun 04 '16 at 20:57
  • obviously your fiddle was not updated, if it works post it as an answer and accept it yourself :), it will be usefull for others – G-Cyrillus Jun 04 '16 at 21:12
  • Hmm, I changed it and saw it work. But the URL changed to https://jsfiddle.net/0nw61s4t/2/ – Kwebble Jun 04 '16 at 21:25
  • This change does not use flexbox anymore, to me it doesn't answer the question. – Kwebble Jun 04 '16 at 21:26
  • If you go for absolute, go all the way down to the image, so it can center too ;) https://jsfiddle.net/0nw61s4t/6/ https://jsfiddle.net/0nw61s4t/6/show/?fullscreen=true and the flexbox version with your image in absolute: http://codepen.io/gc-nomade/pen/WxvZgG :) (i did not expect this to work properly ... but seems like it does .. the absolute approach) – G-Cyrillus Jun 05 '16 at 12:10
  • I think it looks better with the image on the right side of the container, it keeps it near the description. – Kwebble Jun 05 '16 at 19:36

2 Answers2

4

i believe you missed to make height:100% be inherited from viewport ,

for the rest, it is just a matter of flexbox inbrication , flex values overflow and max-size to be reset:( demo to play with )

html,/* viewport values for height/width % */
body {
  height: 100%;
  margin: 0;
}
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
body {
  display: flex;
  flex-flow: column;
}
article {
  display: flex;/* also a flex child */
  flex: 1;
  overflow: hidden;/* we'll squeeze children inside */
}
#description {
  width: 20em;
}
figure {
  flex: 1;
  display: flex;/* again also a flex child */
  overflow: hidden;/* we'll squeeze children inside */
}
img {
  margin: auto;/* will shrink to fit inside and sit in middle */
  max-height: 100%;
  max-width: 100%;
}
h1 {
  margin: 0;
  background: #CAA
}
#description {
  background: #ACA
}
footer {
  background: #AAC
}
<h1>Title</h1>

<article>
  <figure>
    <img src="https://placekitten.com/987/765" />
  </figure>
  <div id="description">
    <p>The description.</p>
  </div>
</article>

<footer>Footer</footer>

note: here image won't grow more than its original size, it will only scale down . min-height + max-height 100% is height 100%, idem for width.

until object-fit comes avalaible everywhere the fallback background-size will be an alternative but loosing image from content.


So the tricky way via CSS only and still keeping image into the content is :

  • to set the image as a background to figure and use contain for background-size,
  • to reduce width to image itself down to zero to only see it painted in the background.(this is to keep it part of the content and keep the alt attribute efficient for screen readers and search engines )

http://caniuse.com/#search=background-size (for older IE, check polyfills but flex is involved so i guess you did not mind those so much )

html,/* viewport values for height/width % */
body {
  height: 100%;
  margin: 0;
}
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
body {
  display: flex;
  flex-flow: column;
}
article {
  display: flex;/* also a flex child */
  flex: 1;
  overflow: hidden;/* we'll squeeze children inside */
}
#description {
  width: 20em;
}
figure {
  flex: 1;
  display: flex;/* again also a flex child */
  overflow: hidden;/* we'll squeeze children inside */
  background:url(https://placekitten.com/987/765) center no-repeat;
  background-size:contain;
}
img {/* hide it and show as a background */
  height:0;
}
h1 {
  margin: 0;
  background: #CAA
}
#description {
  background: #ACA;
  display:flex;
}
p {
  margin:auto 1em;
  }
br:last-of-type {margin-bottom:1em;line-height:2em;}
footer {
  background: #AAC
}
<h1>Title</h1>

<article>
  <figure>
    <img src="https://plcekitten.com/987/765" alt="kitty to pet" /><!-- broken link to show the alt attribute and  that image is still part of content -->
  </figure>
  <div id="description">
    <p>Hide image and place it into figure's background,<br/> So it scales without any distorsion.<br/>Link to image broken on purpose to show that alt is here to be the content </p>
  </div>
</article>

<footer>Footer</footer>

DEMO to play with

G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
  • This distorts the image in a small and tall window because the height then stays 100% of the enclosing box. – Kwebble Jun 04 '16 at 09:28
  • @Kwebble you are right, as i added as a note, actually, there is only via the background-size that can visually meet the full requirement but, it takes the image itself out of the page content :( I'll add the tricky way as a snippet to show what i mean) – G-Cyrillus Jun 04 '16 at 11:36
  • I turned the second snippet also in a codepen if you want to check it out http://codepen.io/gc-nomade/pen/xOGYvQ or dowload the full zip (html & css files) : http://codepen.io/gc-nomade/share/zip/xOGYvQ/ – G-Cyrillus Jun 04 '16 at 12:00
  • Thanks, but I think I prefer something else over flexbox if such tricks are necessary. My next try will use absolute positioning. – Kwebble Jun 04 '16 at 15:31
  • @Kwebble absolute, display:table, or else will bring the same issue, object-fit still won't be avalaible crossbrowser, if you do not want to use the bg tricky way, then you need javascript to handle this properly. :) – G-Cyrillus Jun 04 '16 at 18:08
  • a quick setup with absolute positioning seems to work: https://jsfiddle.net/0nw61s4t/1/ – Kwebble Jun 04 '16 at 21:01
  • @Kwebble not for me, image covers it all and produces scrollbar on HTML, maybe you missed something ? i see no absolute any where ?? wrong fiddle ? – G-Cyrillus Jun 04 '16 at 21:05
0

You not defined the width of "dad element"

<html><head>
<title>Title</title>
<style type="text/css">
*    {font-size:100%; font:inherit; padding:0; border:0; margin:0}
body {background:#FFC; color:#333; font-family:sans-serif}

body                {display:flex; flex-direction:column; height:100%}
h1                  {text-align:right; margin-right:20em; background:#CAA}

article             {flex:1; display:flex; width: 100%;}

article .image {width: 100%;}
article .image img{ width: 100%; }

#description        {width:20em;display:flex; background:#ACA}
footer              {background:#AAC}
</style>
</head><body>
  <h1>Title</h1>

  <article>
     <div class="image">
       <img src="https://placekitten.com/987/765" alt="" />
     </div>
     <div id="description">
       <p>The description.</p>
     </div>
  </article>

  <footer> Footer </footer>
</body></html>
  • This does not limit the page to the windows height and causes a scroll bar in a wide window. I want the image to be always completely visible. – Kwebble Jun 04 '16 at 09:33