mdomino
mdomino

Reputation: 1235

Fill container's remaining vertical space with image while inheriting image's width

I have a fairly specific setup of non-wrapping divs that are aligned next to each other horizontally and are (supposed to) flowing offscreen. Imagine one long row of divs flowing offscreen.

(Later the plan is to use JavaScript to implement some scroll functionality to scroll off-screen parts back on screen).

In each of this divs I have some text on top and an image on the bottom. Of the text on top I cannot know the exact height. The image on the bottom however should fill the remaining vertical space in each div. At the same time the original image aspect ratio should be maintained and the width of the image should determine the width of the containing div.

To clarify: images should not be cropped an not be squeezed or stretched in any way. They should just be scaled/displayed in a way that the fill the remaining vertical space in the div.

Well, I don't get this to work.

Here is what I currently have:

<div id="wrapper">
  <div id="slider">

    <div class="slide">
      <p>Some text</p>
      <img src="http://placekitten.com/200/300">
    </div>

    <div class="slide">
      <p>Some text</p>
      <img src="http://placekitten.com/600/500">
    </div>

    <div class="slide">
      <p>Some text</p>
      <img src="http://placekitten.com/600/200">
    </div>

  </div>
</div>
* {
  margin: 0;
  box-sizing: border-box;
  overflow-x: hidden;
}

#wrapper {
  height: 300px;
  position: relative;
}

#slider {
  height: 100%;
  white-space: nowrap;
  position: absolute;
  font-size: 0;
  background-color: lightgreen;
}

.slide {
  height: 100%;
  display: inline-block;
  margin-right: 15px;
  background-color: pink;
}

p {
  font-size: 16px;
  padding-bottom: 10px;
}

img {
  height: 100%;
}

This obviously does not work, as using 100% height on the image makes it to large for its container, scrollbars appear in each div where they should not appear. I tried using flexbox with a flex-grow: 1; on the image, but that distorts it, especially if I add some padding to the text above.

Here is a jsfiddle demonstrating the issue.

How can I solve this?

(In case this is relevant: we can assume that the text above the image is never wider than the image (as it is only gonna be numbers)).

Upvotes: 3

Views: 1681

Answers (5)

Kfir Dadosh
Kfir Dadosh

Reputation: 1419

Edit

To get a perfect aspect ratio with different font sizes, you can use em instead of px. In this jsfiddle https://jsfiddle.net/ormhukax/, I set the line height to 1.2 and used 1.2em in the CSS calc.

Final CSS:

* {
  margin: 0;
  box-sizing: border-box;
  overflow-x: hidden;
}

#wrapper {
  height: 300px;
  position: relative;
}

#slider {
  height: 100%;
  font-size: 0;
  background-color: lightgreen;
  flex-wrap: nowrap;
  display: flex;
}

.slide {
  font-size: 48px;
  line-height: 1.2;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  margin-right: 15px;
  background-color: pink;
  overflow: initial;
}

p {
  padding-bottom: 10px;
}

img {
  flex: 1;
  height: calc(100% - 1.2em - 10px);
}

Take a look at this fiddle: https://jsfiddle.net/4nw03vrd/2/

This is the CSS I used:

* {
  margin: 0;
  box-sizing: border-box;
  overflow-x: hidden;
}

#wrapper {
  height: 328px;
  position: relative;
}

#slider {
  height: 100%;
  font-size: 0;
  background-color: lightgreen;
  flex-wrap: nowrap;
  display: flex;
}

.slide {
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  margin-right: 15px;
  background-color: pink;
  overflow: initial;
}

p {
  font-size: 16px;
  padding-bottom: 10px;
}

img {
  flex: 1;
  height: calc(100% - 28px);
}

The calc() is needed to compensate a minor distortion in the aspect ratio, which is negligible if the image is larger enough than text height, and it is basically the font size + the bottom padding

Upvotes: 2

Prajyot Tote
Prajyot Tote

Reputation: 680

I Understand your issue.

Add following css and see if that works :)

* {
  margin: 0;
  box-sizing: border-box;
  overflow-x: hidden;
}

#wrapper {
  height: 300px;
  position: relative;
}

#slider {
  height: 100%;
  white-space: nowrap;
  position: absolute;
  font-size: 0;
  background-color: lightgreen;
}

.slide {
  height: 100%;
  display: inline-block;
  margin-right: 15px;
  background-color: pink;
}

p {
  font-size: 16px;
  height:10%;
  padding:5px;
}

img {
  height: 90%;
}

Upvotes: 0

Meziane
Meziane

Reputation: 1667

here is a working fiddle. The margin between the .slide-elements can be modified. Try to play with the value of padding-top property of img. You can see here how to make images scales to fit the allocated area. I used CSS Flexbox to layout the .slider and the .slide.

Here is my final code:

* {
  margin: 0;
  box-sizing: border-box;
  overflow: hidden;
}

#wrapper {
  height: 300px;
  position: relative;
}

#slider {
  display:flex;
  flex-direction: row;
  height: 100%;
  position: absolute;
  font-size: 0;
  background-color: lightgreen;
  overflow: hidden;
}

.slide {
  display: flex;
  width: auto;
  /* border: 1px solid blue; */
  flex-direction: column;
  justify-content: space-between;
  /*height: 100%;   */
  /* margin: auto;*/
  text-align: center;
  background-color: pink;
  overflow: hidden;
}

..

img {
  padding-top: 5%; 
  object-fit: contain; /* also try `contain` and `fill` */  
  height: auto;
  max-width: 100%;
}

Upvotes: -1

Frank Etoundi
Frank Etoundi

Reputation: 356

Not sure i fully understood what you are trying to achieve, maybe a sketch can help.

However, if i got you well, try using a background-image instead of an img tag.

Here is working fiddle https://jsfiddle.net/umf9eh03/

<div id="wrapper">
    <div id="slider">
        <div class="slide">
            <p>Some text and longer text as it goes and yet it is even longer</p>
            <div class="img-wrapper" style="background-image: url('http://placekitten.com/200/300')"></div>
        </div>

        <div class="slide">
            <p>Some text</p>
            <div class="img-wrapper" style="background-image: url('http://placekitten.com/600/500')"></div>
        </div>

        <div class="slide">
            <p>Some text</p>
            <div class="img-wrapper" style="background-image: url('http://placekitten.com/600/200')"></div>
        </div>
    </div>
</div>

<style>
    * {
        margin: 0;
        box-sizing: border-box;
        overflow-x: hidden;
    }

    #wrapper {
        height: 300px;
        position: relative;
    }

    #slider {
        height: 100%;
        white-space: nowrap;
        position: absolute;
        font-size: 0;
        background-color: lightgreen;
    }

    .slide {
        height: 100%;
        display: inline-block;
        margin-right: 15px;
        background-color: pink;
        overflow: hidden;
    }

    .slide .img-wrapper {
        width: 100%;
        height: 100%;
        background-size: cover;
        background-position: center;
    }

    .slide p {
        font-size: 16px;
        padding-bottom: 10px;
    }
</style>

Upvotes: 0

Byron
Byron

Reputation: 623

Here is an option that does not require using calc() on the image height.

I have wrapped the images in a div to ensure that flex does not skew their aspect ratio. The vertical alignment of the paragraphs can be controlled with the "align-self" property.

JS Fiddle example: https://jsfiddle.net/byronj/r42dx90g/31/

* {
  margin: 0;
  box-sizing: border-box;
}

#wrapper {
  height: 300px;
  position: relative;
}

#slider {
  align-items: stretch;
  display: flex;
  font-size: 0;
  background-color: lightgreen;
}

.slide {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  margin-right: 15px;
  background-color: pink;
}

.slide div {
  flex-basis: 100%;
  align-self: flex-end;
}


p {
  align-self: flex-end;
  flex-basis: 100%;
  font-size: 16px;
  padding-bottom: 10px;
}
<div id="wrapper">
  <div id="slider">

    <div class="slide">
      <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc placerat tristique pharetra. Nullam mollis et metus sit amet dictum. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla imperdiet egestas mauris. </p>
      <div>
        <img src="http://placekitten.com/200/300">
      </div>
    </div>

    <div class="slide">
      <p>laoreet nec urna. Donec nisl lectus, varius in aliquet eget, dapibus sit amet nibh. Maecenas blandit ipsum eros, a convallis magna varius a.</p>
      <div>
        <img src="http://placekitten.com/600/300">
      </div>
    </div>

    <div class="slide">
      <p>Some text</p>
      <div>
        <img src="http://placekitten.com/200/300">
      </div>
    </div>

  </div>
</div>

Upvotes: 0

Related Questions