rbuchberger / jekyll_picture_tag

Easy responsive images for Jekyll.
https://rbuchberger.github.io/jekyll_picture_tag/
BSD 3-Clause "New" or "Revised" License
622 stars 106 forks source link

W3C <img> validation error #163

Closed alexandre1985 closed 4 years ago

alexandre1985 commented 4 years ago

The tag produced with this plugin does not pass the W3C validation. Here is the error message:

Error: When the srcset attribute has any image candidate string with a width descriptor,
the sizes attribute must also be present.

href="/"> <img src="/generated/assets/img/logo-transparent-texto-branco-230-75011b.webp"
alt="FreeWriters logo" srcset="/generated/assets/img/logo-transparent-texto-branco-230-
75011b.webp 230w"> </a

Can the sizes attributed also be added/generated within each picture? I need it, for my website W3C validation test approval. Thank you :pray:

rbuchberger commented 4 years ago

I can't automatically generate sizes for you because I know nothing about your layout. It takes some work on your part, though JPT will help you out with it. The relevant docs are here:

https://rbuchberger.github.io/jekyll_picture_tag/presets

The sections on media presets and sizes are what you're looking for. Alternatively, you can write it manually as an HTML attribute if you don't want JPT's help with it (also documented on that same page).

Note that if the sizes attribute is missing, browsers will assume the image is 100% the width of the browser window, meaning that if this is approximately true it can safely be omitted (W3C validation aside).

If the docs can be improved to make this more clear, I'd love to hear about it. Thanks!

alexandre1985 commented 4 years ago

I'm using Twitter Bootstrap and the default JPT settings. My _data/picture.yml is the following:

# Picture Tag
markup_presets:
  default:
    formats: [webp]

I have no clue what to do, sorry. I want your help, please

rbuchberger commented 4 years ago

So the sizes attribute is part of the basic HTML spec for responsive images. Its job is to tell the browser how large the image will be in your layout, so it knows which resolution will fit best. (This is necessary because it starts image downloading before it has rendered the page, meaning it doesn't know what the layout will be at that time.) You can give a single size which will be true for all screen sizes, or you can give media queries to associate them with.

I think you're missing some background knowledge on responsive images in general. You need to have a decent understanding of that in order to understand how to use this plugin properly. I'd recommend that you work through a tutorial or two, and then play around with a basic HTML file and some image files. Write a few <picture> tags by hand and you'll get the hang of it.

The MDN article on the subject is very good: https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images

alexandre1985 commented 4 years ago

Thank You for the link @rbuchberger . I'm reading now

alexandre1985 commented 4 years ago

I'm specifying Twitter Bootstrap presets for my page. sm, md, lg and xl are Bootstrap's media query breakpoints (image full width). If the image is one third of full width for Bootstrap's small (sm) breakpoint (sm is bootstrap language for smartphones) the preset will be sm-3, for example.

# Picture Tag
media_presets:
  sm: 'min-width: 576px'
  md: 'min-width: 768px'
  lg: 'min-width: 992px'
  xl: 'min-width: 1200px'
  sm-2: 'min-width: 288px'
  md-2: 'min-width: 384px'
  lg-2: 'min-width: 496px'
  xl-2: 'min-width: 600px'
  sm-3: 'min-width: 192px'
  md-3: 'min-width: 256px'
  lg-3: 'min-width: 330px'
  xl-3: 'min-width: 400px'

markup_presets:
  default:
    formats: [webp]
  sizes:
    sm:
    md:
    lg:
    xl:
    sm-2:
    md-2:
    lg-2:
    xl-2:
    sm-3:
    md-3:
    lg-3:
    xl-3:

@rbuchberger can you help me with filling the sizes: code above with the default images generated by JPT?

rbuchberger commented 4 years ago

So you're on the right track, but going a bit overboard. I highly doubt you will need to use every single breakpoint that bootstrap gives you! I can't just tell you what sizes to set, because it depends on the layout of the page you'll use it on.

I'll try a different explanation:

A srcset is just a way to offer the same image in multiple resolutions, so the browser can pick whichever fits best. One problem, however, is that the browser picks one to download before it draws the page. This means that before it has read your CSS and figured out where everything goes, it is already downoading all the images on the page. This is a good thing for user experience because it leads to faster page renders, but it means that we as the web developers need to explicitly tell the browser approximately how large an image will be on the screen! That's what the sizes attribute is for.

I'll show you an example from my portfolio site. Whip out your dev tools and check out the screenshots on this page:

https://robert-buchberger.com/projects

If you resize the window, you can see that when the viewport is greater than 900 pixels wide, the image is always 862 pixels wide. Below 900 pixels, the image is the width of the viewport minus 9 pixels of padding on each side. So the sizes attribute is (min-width: 901px) 862px, calc(100vw - 18px). (100vw means 100% of the viewport width). The relevant settings from my picture.yml file look like this:

media_presets:
  full_width: 'min-width: 901px'

markup_presets:
  default:
    formats: [webp, original]
    sizes: 
      full_width: 862px
    size: calc(100vw - 18px)

That's all there is to it. This doesn't have to be perfectly precise, it just helps the browser pick the best fitting image. You don't have to waste a ton of effort getting it perfect!

alexandre1985 commented 4 years ago

I understand now. I want to add the sizes attribute in each image individually (I do not want the sizes in presets). Some of the images will have lazyloading (so dont know if I will need data-size instead). How can I achieve individual sizes on JPT?

Enviado do meu Galaxy J3(2017) usando FastHub-Libre

rbuchberger commented 4 years ago

You know you can have as many presets as you want, right? I doubt every single image on your site will have a unique sizes attribute; you'll probably have 5 or 6 different ones that are reused. Instead of copy-pasting it between several images, you can set it once. Also, if your layout changes you can just change the preset, and it'll apply to every image which uses it.

If you really want to write them manually for every image, you can add --source sizes="(...)" to the picture tag. Something like {% picture my_image.jpg --source sizes="(max-width: 500px 80vw), 100vw" %}

alexandre1985 commented 4 years ago

Can I add media_presets to the individual image sizes, for example: --source sizes="mobile, 100vw" ?

rbuchberger commented 4 years ago

No, sorry.

alexandre1985 commented 4 years ago

Alright. Thank you for all the info :wink:

alexandre1985 commented 4 years ago

This is the root of my confusion: the media query is in relation to the width of the viewport, right? Not in relation to width of the image, right?

Enviado do meu Galaxy J3(2017) usando FastHub-Libre

rbuchberger commented 4 years ago

Yep! The sizes attribute is a way to say "When the viewport is width x, the image will be width y." The media query is how you give the viewport width.

Edit: think of it like an if statement. "If (media query) then (size), elsif (media query) then (size), else (size). You just drop the if, else, and then, and use commas instead.

alexandre1985 commented 4 years ago

Thank you for your help @rbuchberger . I can tell that now that it is working as intended. Could not have done this without your help :+1:. If you want, this issue may no longer be open.