Flexbox - Image and Text

I’m looking to have a flex container have two sections on the same line; one side is a small portion of text, and the side is an image at the end. I’d like the image to always fill the height of the row, so the height value could be hard set (want to avoid the image stretching the flex container out of proportion).

Not sure if this is possible without using background or object-fit tags.

Kind of like this, however that’s using the background tag.

Any ideas?

Do you mean something like this old codepen of mine which came from a thread with a similar question to yours.

https://codepen.io/paulobrien/pen/baobra

Please read the old thread to understand the explanation etc.

Hi Paul,

Almost! Since you’re using object-fit, you’ll notice any browser not supporting the tag (such as IE11) doesn’t scale the image and will make the image look flat when the text is only one line.

I’m probably looking the image not to stretch, so maybe if the height was statically assigned, and the two flex items were something like 65%/35% in width ratio (latter allocated for the image, until of course the width of the image has been met).

What you have is close to that when assigning a static height on the row container of your sample css, however object-fit isn’t IE compatible. I’ve been searching for a while to solve this, and can only see the background tag being the only closest fit.

Thanks for your reply though, and I’d welcome more if you have any further suggestions :slight_smile:

That’s not quite true as I added a technique in there to scale the image while maintaining its aspect ratio and it will work fine in browsers that don’t understand object-fit (within certain limits). The demo looks exactly the same in IE11 with the image I was using. There may be issues if you are using massively oversized images or images that have ridiculous aspect ratios but for any normal images the technique works fine as can be seen by the demo in IE11 and others. BTW IE11 is a minor browser these days so its not that bad if it gets a slightly different effect.

You can’t do that for fluid content like text and makes no sense in the demo that I posted. Maybe you have a different use case but you should never be setting a fixed height. Maybe a min-height would be useful to stop the image getting too small but certainly not a fixed height.

I am out today otherwise I would knock up another demo with your 65%/35% options but I can assure you this method is the only method that will get close to what you want. Please read the other thread I linked to which explains the logistics.

The technique I am using in IE11 is to make sure the image is always at least as wide or as tall as the box it sits in but without breaking its aspect ratio at all. There may be issues though if your image is 2000px wide and you want it to fit in a box of 200px because although its aspect ratio will not be broken in IE7 it will only show a segment of the image in that box. This is the main difference between the technique and object-fit because object fit reduces the dimensions of the image to something that works for both width and height. As I said the method works fine for normal images of suitable sizes but may look odd for massively oversized images which you shouldn’t really be using anyway.

Unfortunately there is no other choice other than pulling out the image and using a background image instead (which could be done easily with js).

I’ll be back later and make another demo with multiple images to show that it works within the limits mentioned.:frowning:

Hi,

I’ve knocked up a quick example with larger text boxes.

https://codepen.io/paulobrien/full/GxGpmY/

It’s not foolproof as I mentioned but here is what it looks like in Chrome and IE11.

As you can see in IE11 (the rightside image) the images retain their aspect ratio and fill the text area completely. The difference is that in IE11 you get the middle part of the image because object-fit in the chrome version scales the image to an optimum size first. However both retain their aspect ratio.

If you use very large images then the difference is more noticeable but if you keep the images within a suitable range then the effect is pretty good.

This is the best you can do in CSS other than reverting to background images (which you could probably do with a script to automate the process).

Hope it helps but there are no other options if I have understood what you are trying to do.:slight_smile:

That’s a fair point, the aspect does appear to be fine (it’s centrally focused on the image). However, the image itself will be flat - see below for a comparison between Chrome and IE using the same individual image and your demo code (with less text):

The Chrome effect works well (as the text can be vertically centered), but it’s using object-fit. The experience in IE is such a big compromise though. If it wasn’t for IE, I’d have bounced straight onto CSS Grid and be done with a few other headaches. While IE is not the most popular browser it once was, there are still many using it unfortunately, and it doesn’t help that Microsoft aren’t going to update IE with these new CSS features.

Yeah I’m not actually sure what the answer would be… the use-case is simply having a feature photo and a brief textual description at the side of it (along with a button).

My thinking of using a static height is the text would wrap around the bigger half of the container - it would only be a sentence or so, not a huge amount of text, but does pose a risk like you said. Most important thing is you would see all of the image from a height perspective, and then it would allow more of the image to be shown from the horizontal view as screen size changes. If that makes sense?

Thanks for continuing to reply, this stuff is really fiddly to get right!

1 Like

Our posts probably crossed but if you look at my last post I put a min-height on the textbox so that the text gets centred if there’s not enough to fill the min-height.

From the look of the image you posted it looks like the orignal image is very wide and that’s why IE11 only gets the centre part. You could put a max-width on the ie11 routine (the code outside of the supports rule) but the danger is that if you allow the text box to get very tall then the height would not be enough to fill the space.

Another alternative would be to centre the image for IE11 in the space available rather than fill the space.

Here’s an example of that method:

https://codepen.io/paulobrien/full/ZxRQar/

Screenshot:

IE11 is on the right and as you can see in the third image down it just gets centred in the space available which I think is a pretty good compromise for an older browser.

In the end it’s a workaround because you are trying to do something that’s not supported natively. :slight_smile:

Here’s an example using vanilla JS which swaps the foreground image out for a background image instead and therefore will look exactly the same in IE11.

https://codepen.io/paulobrien/full/rdKeGE/

All I did was add a class to the images to make them easily identifiable. The js cyles through the images and adds a new class so that we can set the background of the image instead. The real image is set as a 1px transparent gif using a data uri so the image still remains in the html and still takes up the original space. The background image is then applied to the image itself and uses background-size:cover to good effect.

People with js turned off will still get the original image and object-fit format as before.

Interesting, @PaulOB. The last codepen examples are squashing the image for me in Chrome (while the first codepen didn’t).

The first worked well in Chrome, it just needed the text vertically aligned, and if IE can achieve a similar outcome that would be ideal. I personally think it’s best if the image primarily dictated the height of the text area (at least if it’s able to show the full image from a vertical perspective, even if it’s smaller), instead of the other way around, which might be the case in the latest two codepen examples mentioned - unless I’m getting muddled.

As you can see from the screenshots, if you can’t view the full image vertically, then you miss a lot of what’s going on. Whereas the sides aren’t as important if they get trimmed.

Initial code pen:

The latest two code pens (except for the last JS/bg alternative):

I bet you’re going to just tell me to use background now :joy:

I think you are mistaken as none of the images get squashed at all.:slight_smile:

They all maintain aspect ratio. You may mean something else but the images are not squashed as such. Indeed the last example is using background images and background-size:cover for all the images so there is no way the last example can be squashed in any browser.

I think you misunderstand the logistics of object-fit:cover and background-size:cover a little. What ‘cover’ does is increase the width and height of the image until it fills the area completely. That of course means that some of the image will be outside of the viewable area simply because of the laws of the universe:) You can’t cover all the space without doing so as that is not a css issue but a mathematical certainty.

So the question is that you desire a different behaviour to the one you first asked for and it now sounds like you want to ‘contain’ the whole image within the space so that no part of the image is missing. That means that you will get white space around the image because again that is simple laws of physics. You can’t make an image fit an aspect ratio it doesn’t own without oversizing or undersizing it.

I’ve forked the last example (the one with js) to use contain instead of cover.

https://codepen.io/paulobrien/pen/VXdyBo

You can clearly see the differences between cover and contain. There is no other choice that will not break the image aspect ratio.

It is still the text boxes dictating the height of both blocks as that is the only real way that makes sense. You can increase the min-height to something greater if you wish to avoid small images when there is little text.

If you are concerned about the height of the image then you can probably force the height to be 100% but the width would have to be auto which means it would most likely overflow the width. That would require a different technique but I feel it would be raise more issues than it solves.

I believe the best solution was the cover solution in my last post.

I think that is the limit of choices available to you .:slight_smile:

2 Likes

Squashed/flat was a bad term to use, I meant the image doesn’t provide the full view vertically (bit like looking through a letter box).

That is, until I discovered increasing the min-height of the textbox-1, it worked as expected and looks much more normal :blush:

I’m going to have a play about with this more - thanks for your help and the education!

I wouldn’t call my definitions “official”, but when an image is too big to fit the outcome is

  • “cropped” - the aspect and dimensions are preserved, but some of the image will not be visible
  • “resized” - the aspect and image are preserved, but it’s dimensions are displayed smaller
  • “squished” - the image is preserved, but it’s aspect and dimensions are not.

IMHO except maybe for a pixel or three “squishing” is unacceptable and can display horribly distorted images.

Cropped can work as long as portions of the image are not essential and only non-essential portions are what is cropped. Image content is sacrificed for image quality.

Resized can work when the entire image is essential and it’s displayed dimensions are less so. Image quality is sacrificed for image content.

None are 100% ideal. But when something doesn’t fit, something has to go.

1 Like

After learning more of image techniques from this thread, I just wanted to give resizing a try - in case that is what I actually need :sweat:

Basically the image should be limited to a minimum and maximum size (to avoid the image going above/below any of those extremes). Is that a bad idea?

See the code below (apologies I don’t have a codepen account yet). Please say if there is anything I’m not doing correctly by the way.

HTML:

<div class="container">
  <div class="image">
    <img src="https://insidehpc.com/wp-content/uploads/2016/08/18785323579_0c0c656598_c.jpg">
  </div>
  <div class="text">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloribus aliquid eius quia expedita illo sequi optio labore assumenda.
  </div>
</div>

CSS:

.container {
  background-color: #FFEEDD;
  display: flex;
}
.container .image {
  flex-grow: 1;
  flex-basis: 40%;
  min-width: 200px;

}
.image img {
  display: block;
  max-width: 100%;
  max-height: 300px;
}
.text {
  flex-grow: 1;
  flex-basis: 60%;
  min-width: 300px;
}

Lol unlike all the other methods posted that one will break the aspect ratio of the image because you have limited the width and the height (you can’t do both). As soon as limits are reached the image will be resized but will not retain aspect ratio. This is the main point that all my demos avoided :).

Also there is no guarantee that the image will fill the available space as there is nothing in place to do that.

You could add object- fit cover to avoid breaking the aspect ratio but that will result in cropping as already discussed.

The prime thing to avoid is image squashing where the aspect ratio is broken so I would never use the method you have shown.

Lastly you seem to have veered away from the image height matching the text content height which was prominent in my examples (except for contain) and if that is no longer required then you are more or less back to having a normal image and just let it resize normally (e.g. width: 100% and height auto or vice versa if space allows).

It all depends what you want to achieve now that you have seen the options but I would advise against breaking the aspect ratio as in your last example :slight_smile:

It would also help if you chose your images a little more carefully (if that’s possible) and ensure the focal point is the middle of the image and then cover would still be the best choice.

As I said in the other thread most people don’t really understand what they are asking when they talk about making images fit as it’s similar to making a square peg fit in a round hole :slight_smile:

2 Likes

When you say aspect ratio, do you mean its dimensions? The image always has the same ratio and is never squished, regardless of what limit it exceeds… the only ratio impacted is the 60/40 item container ratio - see below:

Resize screen - min exceeded (upload has made the image bigger for some reason):

Resize screen - max exceeded:

No no, I didn’t want the image height matching the content, as it crops the image which makes it look like I’m peering through a letterbox (whenever there is only one line of text). I’d much rather the image have the deciding factor of how big the container/text area be (within limits, as I don’t want the image be too overwhelmingly huge, which is why I tried to max-height the image in my poor attempt of an example).

My only gripe with using cover now is IE appears to miss a lot of the image, as it zooms in more. See the dartboard image below, it hits the bullseye but badly misses other parts of the image - object-fit handles this better (as we already discussed). The main part of the image would need to be directly in the center and a lot of redundant visual noise around the perimeter of the image for this to work.

Is there any best case way of resizing the image like I attempted to do, when max limits are set to avoid the image getting out of control?

When starting my sister’s website, I did not think this would be giving me the most bother :persevere:

No.

I didn’t think you understood the concept:)

When you have an image that is created at 500px width by 250px height for example then it has an aspect ratio of 2:1. That means the width is twice the height. For an image that is 1920 x 1080 the aspect ratio is 16:9.

Now to maintain that aspect ratio when you reduce/increase any of the dimensions then the other dimension must also increase/decrease accordingly to maintain the same aspect ratio. If you do not keep the same aspect ratio then the image becomes squashed or stretched and is no longer a natural image. Imagine stretching the width of an image of a real person but still keeping the height the same. You would end up with a very wide person at the same height. That is not a natural phenomenon :slight_smile:

Suffice to say that for real world images (other than miscellaneous shapes and colours) you should never lose the aspect ratio. I don’t like so say ‘never’ but 99% of the time a real world image must not be distorted. There are odd occasions and depending on the image it may not look too bad for a small distortion but if you have that kind of control over the image then you could have avoided the problem by choosing only suitable images to start with.

I’d need to see the live page but those image look distorted to me and the second image looks massive compared to the tiny bit of a text. I can’t see that working in any sense of the word:)[quote=“neil, post:15, topic:293073”]

No no, I didn’t want the image height matching the content
[/quote]

Well actually in your first thread you said:

That suggested to me that the image should always match the height of the text. What else could it mean?

Either the text creates the height of the row or the image does? You can’t say one without the other. The image would naturally fill the height of the row if it were the larger element so the statement only makes sense in that the image should match the height of the text and indeed would be my preference unless this is just an image gallery with captions. It also seemed to be the same question that was asked in the other thread I linked to where an image needed to fill the space at the side of some text no matter how much text was present.

Maybe I have misunderstood what you want to achieve but if all you are going to have is little snippets of text that are perhaps image captions and images of various heights then I think a complete change of design would be in order.

I gave you a very small JS fix for that and IE is showing exactly the same as other browsers because it is using background-size:cover. I still believe this to be the best (and best looking solution).

https://codepen.io/paulobrien/pen/rdKeGE

The above demo looks perfect to me and makes perfect sense in any situation. You may lose a bit of the image outside the viewport but with any reasonable image it looks great as in my example of various sized images. It works when the page is resized and the image still fills the space nicely. Of course at narrower widths a media query should be added to either allow the image more room or break them both onto separate lines so the text and image can have the full width…

It also looks exactly the same in IE11. :slight_smile:

Your image of a dartboard is a perfect example of aspect ratio and because the image is square (i.e. the dartboard is a circle) then its image aspect ratio is 1:1. However in you screenshot you are trying to show it in a space that is not 1:1 so I don’t see how you can think it will fit in any other way other than to ‘cover’ or ‘contain’. There simply is no other option!

At the moment we are going around in circles a bit here and you need to either settle for cover or contain:) There really is no other viable choice for real world images.

You could make the images a fixed height but that means the width would need to be fluid which doesn’t work for the 60/40 split as the width may need to exceed the available width when the aspect ratio requires it. If you had a letter box type image and you set it at a fixed height it’s with may need more than the whole screen width to show it so once again you would need to crop the image somewhere.

As I have said a few times this is a basic maths question and you can’t bend the laws of the universe and just make an image fit whatever - something has to give:)

Sorry to ramble on a bit but I’ve seen this question many times now and coded this in hundreds of real world sites so I know what will work and what certainly doesn’t work. Sometimes the concept is hard for people to grasp which is why I use the analogy of a picture of a face. That face will only look normal when its width and height are maintained at the same aspect ratio. Any deviation from that path results in the sort of thing you’d see in a crazy mirror at a fairground :slight_smile:

3 Likes

Here’s an example where just the height is set on the image and no contain or cover is used. The width will be cropped if its too big and the image will not follow the height of the text if the text is taller than the image.

https://codepen.io/paulobrien/pen/pLZNop

That will look the same everywhere as there is no making it fit. Of course it no longer matches the text or has a uniform width. In certain window sizes / image sizes there will be gaps under the image or the image width is cropped or both.

The height of the image has been set to 300px so you always get the full height of the image but of course the width will be fluid and if the image was 5000px wide then 90% of it would be missing.

You may of course open it at one view and think that its perfect but remember the web is not square and is not under your control :slight_smile:

1 Like

Apologies for the merry-go-round, @PaulOB. I guess I wasn’t clear in my initial post, but yeah, I didn’t mean the content should determine the height of the row, but instead the image (within a set limit). As you now know.

Hmm, I wanted to avoid using javascript for this if possible - even though that example is functionally sound, adding javascript feels a bit hacky.

The last codepen you wrote looks promising and I will probably use that if you don’t mind (will try to figure out how to center the image, as the right-side crops when the screen reduces its width).

I’m still a bit confused why this resizing code is an issue? I thought the aspect ratio would still be the same for the image itself (and does appear to be the case when copying into codepen). As the image grows, it grows in the same ratio. Even if the max-height of 300px was met, the width of that max-height is still 100%, so there is no conflict?

.container {
  background-color: #FFEEDD;
  display: flex;
}
.container .image {
  flex-grow: 1;
}
.image img {
  display: block;
  max-width: 100%;
  max-height: 300px;
}
.text {
  flex-grow: 1;
}

To be honest, I’m almost at the point of getting this done now, but that was one point I didn’t quite understand.

No not in the code you have just shown :).

Once the limits have been reached you are then distorting the image. If you restrict both width and height then it can’t fail to break.
I’m out for a few hours but I’ll show a demo later that shows how it will break. :slight_smile:

If the height of the image is 300px then there can only be one dimension for the width that will satisfy keeping the aspect ratio and not result in distorting the image.

If the ratio is 2:1 for example (as already explained) then the image width can only be 600px exactly in order for it not to be distorted. For images of different aspect ratios then that width will need to be something else which is why your algorithm cannot work because 100% can’t satisfy all of the criteria at the same time. The image will only look correct when the width of the container is 600px assuming you have set the height to 300px. For different aspect ratio images you would need different widths.

Remember width:100% means 100% of the available space and not the image’s natural width.

As Isaid I’ll put up a demo later when I get back to explain this more clearly.

Adding JS as en enhancement is not a hack and is the way it should be used. The page works fine without it but looks better in IE11 with it enabled. Obviously you don’t want to add JS just for the sake of it but used properly it can enhance a users experience.

1 Like