Bootstrap img-fluid, responsive images and the srcset sizes?

I have a hard time understanding the sizes on srcset or how to set them.
Also there is img-fluid in Bootstrap.

Lets say i have this:

<section id="listing" class="row mb-4"><!-- Listing -->
  <ul class="col-lg-12 text-center">
    <li class="mb-4">
	  <header>
        <h2 class="mb-2">Entry 1</h2>
      </header>

      <a href="https://mydomain.net/entry1">                              
        <picture>
          <source srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w,
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w" type="image/jpeg">
                <img src="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg"
                  srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w,
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w"
                  sizes="(min-width: 900px) 1000px, (max-width: 900px) and (min-width: 400px) 50em, 50vw"
                  width="auto"
                 height="250"
                  class="img-fluid mr-3">
        </picture>
                                          
        <picture>
          <source srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w,
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w" type="image/jpeg">
                <img src="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg"
                  srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w,
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w"
                  sizes="(min-width: 900px) 1000px, (max-width: 900px) and (min-width: 400px) 50em, 50vw"
                  width="auto"
                 height="250"
                  class="img-fluid mr-3">
        </picture>
      </a>
    </li>

    <li class="mb-4">
	  <header>
        <h2 class="mb-2">Entry 2</h2>
      </header>

      <a href="https://mydomain.net/entry2 ">                              
        <picture>
          <source srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w" type="image/jpeg">
                <img src="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg"
                  srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w"
                  sizes="(min-width: 900px) 1000px, (max-width: 900px) and (min-width: 400px) 50em, 50vw"
                  width="auto"
                 height="250"
                  class="img-fluid mr-3">
        </picture>
                                          
        <picture>
          <source srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w" type="image/jpeg">
                <img src="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg"
                  srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w"
                  sizes="(min-width: 900px) 1000px, (max-width: 900px) and (min-width: 400px) 50em, 50vw"
                  width="auto"
                 height="250"
                  class="img-fluid mr-3">
        </picture>
      </a>
    </li>
  </ul>
</section>

In this case i want to show two images side by side width the same height.
The second image can have different widths.

The first image is 250H x 180W and that’s the sizes you see on a normal FHD PC Monitor.
I also made 500H x 360W and 1000H x 720W for 2x and 4x device pixel radio.

I need to take out img-fluid and set width and height. If i don’t do that the picture is stretched over the whole 12 columns.

But non tutorial i did read does set a fixed width or height?

What i have in “sizes” is just a placeholder because i don’t get what to put in there.

If you write articles the pictures you place in your text can have all kind of different sizes…

Also i did read that this takes the internet speed into account?
That means if somebody has a slow connection he gets the picture with the lowest resolution on his 4x device and thinks i have crappy images on my site?

Nobody?

Wow you like making life hard for yourself don’t you :slight_smile:

The picture element is mainly for art-direction in that you deliver different images at various widths/ resolutions. It’s not usually used when you just provide lower/higher quality versions of the same image. e.g. A large seascape image on desktop may be changed for a small sand-castle on small screens. Not just the large seascape made smaller or cropped badly.

https://cloudfour.com/thinks/dont-use-picture-most-of-the-time/

Your code is giving some validator errors anyway and you need the sizes attribute on your source tag when using the format you have. You also have width=“auto” which is invalid and will have no effect. It should be like this to be valid.

 <picture>
          <source srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w,
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w"
                          sizes="(min-width: 900px) 1000px, (max-width: 900px) and (min-width: 400px) 50em, 50vw" 
                           type="image/jpeg">
                <img src="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg"
                  srcset="/media/frontcover_00497665dd46c88fddd1253ccd1a95c4.jpg 180w,
                          /media/frontcover_a81dcdc47d435b3f3d65823d2d137fd0.jpg 360w,
                          /media/frontcover_952d4388dada8a9265cb79206a40abe4.jpg 720w"
                  sizes="(min-width: 900px) 1000px, (max-width: 900px) and (min-width: 400px) 50em, 50vw"
                 alt=""
                 height="250"
                  class="img-fluid mr-3">
        </picture>

However srcset and sizes are down to the browsers discretion to choose and if you want full control you would need to use the media attribute on the source tag. The media attribute is a directive that the browsers must use if conditions are met.

This is mentioned here:

https://cloudfour.com/thinks/responsive-images-101-part-6-picture-element/

(I suggest reading that whole article a few times. :))

I am unsure of why you have duplicated the srcet in the img tag as I believed the img tag was a fallback for those that didn’t understand the picture tag or srcset attribute but I guess it may also be a fall back for those that don’t understand the source tag. (Edit: Just having looked at caniuse it may be that a few older browsers will recognise srcset but not picture but I wonder if the complexity it adds is worth the price?)

Assuming your images don’t have the same height to begin with then you would need to do this with css preferably and set the image height to the height you want. You would then set the image width to auto but not as an attribute in the image tag.

e.g.

.my-image{
height:250px;
width:auto;
}

That will make the image 250px tall and maintain its aspect ratio. It will not make the image fill the width unless it happens to match the width available. It has nothing to do with what you have set up in the html and the image displayed will be the image that was selected in the picture element. The css will then set its width to auto and its height to 250px or whatever you set it to be.

Note that your img-fluid class in bootstrap will be contrary to what you want as that sets the width to 100% and height to auto which is the reverse of what you wanted.

Also note that by setting the height of the image to 250px it may mean that the image width is massive or tiny unless you have chosen specific aspect ratio images to use and the image may overflow or be too small. If images have been set with a max-width of 100% then you may also find your images will be squashed because the height will be 250px and the width will be the max-width available and will not match the original aspect ratio.

I believe srcset takes into account bandwidth and will provide the best image available but I think that only applies when not using the picture element because the picture element should provide different pictures not just different resolutions. That’s why I was concerned about the list of srcset images in the img tag alhough I guess they are not used when browsers understand the source tag.

I find that high bandwidth images simply do not load when I have a slow connection. The whole page on my phone just freezes. I would much rather get a crappy image than no content at all.

I think the main thing to consider is that if you want different images then you use the picture element. e.g. A picture of a forest for desktop but a picture of a single tree on small screen.

If on the other hand you just want lower or higher quality versions of the exact same image then you use srcset on the img tag and not the picture element.

To be honest I have avoided using srcset or the picture image because of the complexity and indeed I often find that I have optimised the largest image to a smaller filesize than most people are using in their srcsets anyway and without much loss of quality. Optimising images is one of the most important things to handle properly and indeed you can create larger images suitable for retina devices bycreating at larger sizes and squashing smaller.

More info:

I know I haven’t really answered your questions exactly as the issues are multiple and complex. The crux of the issue is that the image selection is done by the html you use but how the image will be displayed is down to your css.

If you are having trouble with one aspect of this like setting your images to a specific height then it would be helpful if you could make a live demo of the problem so that it can be debugged more easily.

My general thinking is that using well optimised images the first place will save on hundreds of lines of complex code although I do realise that sometimes this is unavoidable.

Also be aware that using srcset in some browsers means that a user may end up downloading all the images if they regularly resize their browsers window (as I do). Some browsers only do this on refresh but some do it it on resize. Also cached images may be selected by a browser even if its not the one specified in the srcset criteria (unless using the picture element of course).

As I said above I’m not an expert on picture or srcset so some of my conclusions may be a little wide of the mark. I think this article is a good resource although its a little old now.

3 Likes

Wow you really did write a lot.
Just a quick response (i will go trough it later step by step).

You need to group source and img together? And you need source for webp?

Isn’t that what its all about?
You serve the image in different sizes like i do. On a x1 device pixel radio the browser should take the “250 x 500px” image and on a x2 device the “500 x 1000px” image.

My biggest problem is that i don’t understand what values to set in “sizes”.

Then you say you need to set height/width in css. But that means inline css if images in articles have different sizes?

Here is some stuff i did read and they all use source, src and srcset in combination:

source, src and srcset:



source and src:
https://cloudfour.com/thinks/responsive-images-101-part-6-picture-element/

src and srcset:




He says you need minimum 6/7 sizes of your image:

As I understand it the comma-separated list in sizes describes the size of the image in relation to the viewport or as an actual size. So in your example:

sizes="(min-width: 900px) 1000px, etc...

You are saying that at greater than 900px viewport width you are going to show a 1000px width image. The browser will then choose the best image from your srcset that meets that criteria. What width the image will actually be rendered at will also depend upon the css that you have applied in the CSS media query for 900px (if any).

Of course if you are showing fixed width images then a 1000px width image is going to be too wide for a 900px screen. I would assume that you are using flexible images but if they are a series of fixed images then you’d need to ensure they will fit in the space you allocate them for and would usually match your media query breakpoints in your css.

As I mentioned a number of times that unless you use the media attribute in the source tag of the picture element then the browser decides which image to use as it thinks best. If you use the media attribute then you are telling the browsers to use this image explicitly as in the case for art direction.

There’s a good video here explaining sizes in some detail and the picture element here

Yes that’s correct but you missed the point I was making that if you explicitly set the height to 250px for the image then its width is auto. That may be fine for your purpose so may not be an issue but if you wanted two images side by side taking up 50% of the screen then setting the height would be out of the question.

It all depends on what you are doing but it never means inline css.

Usually when you display images you are placing them inside a flexible container and the image is sized to fit the width of that container. That means when you scale up and down the image grows and shrinks.In those cases you are just using setting the image width to 100% and the height to auto (or a max-width of 100%).

Of course there will be cases where you want a fixed width image only and then change with media queries for a series of adaptive fixed widths or whatever you want but generally you would want to keep it as simple as possible.

I follow the logic but its a lot of work and (probably) most users wouldn’t notice the difference. You can make it as complex as you like but I would try to keep it as simple as possible at first.

Looking at your picture element again it seems to be mixing up the methods a bit.

You want to use the picture element for art-direction so you would use the media attribute to set the media query and that will direct the browser to choose the image (or images in that srcset). The sizes attribute will merely relate to the browser how wide compared to the viewport those list of images will be. It only needs the one size because you already have the media query in the source tag.

E.G.

 <picture>
    <source media="(min-width: 1200px)" 
  				  srcset="https://via.placeholder.com/1500 1500w,
                          https://via.placeholder.com/3000 3000w"
                          sizes="50vw" 
                         >
    <source media="(min-width: 900px)" 
  				  srcset="https://via.placeholder.com/1200 1200w,
                          https://via.placeholder.com/2400 2400w"
                          sizes="75vw" 
                         >
    <source  
  				  srcset="https://via.placeholder.com/320 320w,
                          https://via.placeholder.com/640 640w"
                          sizes="100vw" 
                         >
    <img src="https://via.placeholder.com/1000" alt="" class="img-fluid"> </picture>
  

The point with the above is that at each media query there is a completely different image because of the art direction changes but there can still be multiple copies of each image in each set to cater for retina resolution etc.

If you don’t need art-direction and just want flexible images then you do it all in the img tag using srscet and no picture at all.

e.g.

<img src="https://via.placeholder.com/1000" 
  srcset="https://via.placeholder.com/320 320w,
          https://via.placeholder.com/640 640w,
          https://via.placeholder.com/1200 1200w, 
          https://via.placeholder.com/1500 1500w, 
          https://via.placeholder.com/2400 2400w, 
          https://via.placeholder.com/3000 3000w"  
	    sizes="(min-width:900px) 75vw, 
        		(min-width:1200px) 50vw, 100vw"		
alt="" class="img-fluid">

The difference here is that they are all the same image but just at different resolutions.

Here’s a codepen so it can be tested and changed more easily.

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

You should see that the html media attribute and sizes queries match the css media queries. The above is a simple example and you can of course set fixed (non-changing) width images into the mix if you want but the format would be much the same.

1 Like

As i understand it you need “picture” and “source” for webp and you need to set the type=“image/webp”

With just “img src” how do you tell the browser to prefer webp if it has support for it?

But lets forget the source tag for now. I first need to figure out the sizes.
I found this generator: https://www.responsivebreakpoints.com/

My picture is 350px on a Desktop so i set Resolution “from 350 to 350” and did select “Retina Resolution”.
So for Redina (x2) i get a 700px image and the example code is telling me:
sizes= "(max-width: 700px) 100vw, 700px"

With that Firefox is downloading the 700px and not the 350px image.
It seems to work for the images that need to be 700px.
So i have to generate somehow automatically the sizes tag in my CMS?

You can see it here:

Without img-fluid the pictures never fit on phones.
This is what i want (first image set to width = “350px”):


But if i set img-fluid i get:

EDIT:
Ok, i have to put a container arround the first image like:

<div class="container px-0">
  <div class="col-12 col-sm-12 col-md-6 col-lg-6 col-lx-6 px-0 mx-auto">

    image

  </div>
</div>

Back then it was bad practice to use that much div’s anywhere…

I’ll reply in detail tomorrow as out today but this code …

That code is saying that at 700px viewport width and under the image width is going to be 100vw. That means for viewport widths of 351px to 700px the 700px width image will be chosen.

At less than 351px viewport width the 350px image will be chosen unless it is a retina device then the 700px image will be chosen.

At viewport widths greater than 700px width the sizes attribute says the image will be 700px so a 700px image will be chosen unless the device is retina where it will choose a larger sized image if available in the srcset.

Yes currently you would need to use the picture element to provide fallback for webp.

If you don’t want art-direction then I believe the format is this:

<picture>
  <source srcset="imgnicepic_1.jpg 640w,
                  imgnicepic_2.jpg 768w,
                  imgnicepic_3.jpg 1024w,
                  imgnicepic_4.jpg 1366w,
                  imgnicepic_5.jpg 1600w,
                  imgnicepic_6.jpg 1920w"
                  sizes="100vw" 
                  type="image/jpeg">
    	
  <source srcset="imgnicepic_1.webp 640w,
                  imgnicepic_2.webp 768w,
                  imgnicepic_3.webp 1024w,
                  imgnicepic_4.webp 1366w,
                  imgnicepic_5.webp 1600w,
                  imgnicepic_6.webp 1920w"
                  sizes="100vw" 
                  type="image/webp">
  <img src="imgdefaultpic.jpg" alt="" class="img-fluid">
</picture>

The above just assumes that images will be at 100% viewport width but you can change the sizes attribute to match the actual css media queries you are using if you are fixing image widths at specific sizes.

If you want art direction at specific media query breakpoints then you would need the media attribute on the source tag as from my demo in post#6 but with the type attribute added and the source tag duplicated for jpg etc.

Yes when the image is set to 100% width it will then fill its container so needs to be in the appropriate structure. As you are using bootstrap then 99% of the time your content should be within the appropriate column class otherwise there’s no real point in using a framework.

Yes unnecessary tags should be kept to a minimum but there’s no harm in the odd extra div where appropriate. It’s the multiple nesting of unnecessary elements that complicate matters and should be avoided but of course frameworks come with a slight overhead on extra code in order to make the framework do its job.

I think I have answered most of your points (in one way or another) but if you have a specific question with example then perhaps we can address that in more detail rather than a general question of how things work.

All the images on this page were too small for me to read the details on the image (if I was supposed to) and in my mind it would be better to load slightly lower quality images to start with and then offer a link (or modal) to “View larger image option” so I could choose to load the higher quality image and see it properly.

As I said at the start I like to keep things simple and I would go with as few images as you can manage and make sure they are fully optimised. Some sites (like artist or graphic sites) need high quality images and users would expect the payload that they entail but most general sites do no need to go overboard with file sizes. I can rarely see the difference between a 100% jpg and an 80% jpg and most times I am interested in the content rather than the picture so perhaps I am a bad example of a visitor .:slight_smile: