Best practice for responsive images?



  • Hello all

    I was wondering if there are accepted best practices for responsive images?

    I have a custom component like so:

    Vue.component('responsive-image', {
      template: '<img :srcset="imgsrc" />',
      props: {
        src: {
          type: String,
          required: true
        },
        w: {
          type: Number,
          required: true
        }
      },
      computed: {
        imgsrc: function () {
          return `~assets/img/lg/${this.src}.jpg w${this.w}, ~assets/img/md/${this.src}.jpg w${this.w * 0.5}, ~assets/img/sm/${this.src}.jpg w${this.w * 0.25}`
        }
      }
    })
    

    Which is used like so:

    <div>
      <responsive-image src="my-image" w="800" />
    </div>
    

    I have a grunt task to generate the 50% and 25% images automatically

    Any better ideas? Thanks!



  • looks cool to me.
    a few rough ideas to improve on it:

    • what about making it a vue single file component ?
    • what about high-dpi displays ?
    • what about sizing by height instead of width? (as an alternative)

    I could very well see a polished version of this getting into quasar as q-img



  • @spectrolite Having it like this makes it available globally, but at the moment I am using it as a single file component

    Regarding Hight dpi and sizing by height: this uses the srcset property, not src
    That means that I simply tell the browser what image widths are available and where, the browser figures out the best one and gets that one. So at no point am I deciding witch image width a client gets

    Cheers



  • The problem with srcset is that it is not supported by IE and (current) Edge versions (http://caniuse.com/#feat=srcset). So we would need a polyfill for these.
    https://github.com/scottjehl/picturefill/blob/master/dist/picturefill.min.js

    And without having used it, but shouldn’t the template be:

    <picture>
     <source :srcset="imgsrc">
     <img :src="fallbackSrc">
    </picture>
    

    Also, did you test if webpack inserts the correct path if you return the string?

    But a q-img components seems like a great idea. Maybe we could even extend the webpack config to automatically generate smaller versions of images and insert these instead on relying on another build system. 🙂
    I found this loader which looks promising: https://github.com/herrstucki/responsive-loader



  • @rstoenescu please consider this for 0.15. Do you need it to be a github issue?


  • Admin

    Yes, make it a github ticket pls. Accepting a PR if someone is willing. Thanks!



  • Here is the link to the issue on Github: https://github.com/quasarframework/quasar/issues/777
    At the moment I do not have time for a PR, but maybe I will experiment with it later on. 🙂



  • Here is a proposal. Also posted this on #777

    <template lang="html">
      <img
      :src="`/img/md/${src}`"
      :alt="alt"
      :srcset="imgsrc"
      :sizes="imgsize"
      >
    </template>
    
    <script>
    const xsBreakpoint = '576px',
      smBreakpoint = '768px',
      mdBreakpoint = '992px',
      lgBreakpoint = '1200px'
    
    export default {
      props: {
        src: {
          required: true,
          type: String
        },
        w: { // Width, in pixels, of our original image.
          required: true,
          type: Number
        },
        alt: {
          type: String
        },
        size: {
          type: Number
        },
        xsSize: {
          type: Number
        },
        smSize: {
          type: Number
        },
        mdSize: {
          type: Number
        },
        lgSize: {
          type: Number
        }
      },
      computed: {
        imgsrc () {
          let imgsrc = ''
    
          imgsrc += `/img/lg/${this.src}.jpg ${this.w}w, `
          imgsrc += `/img/md/${this.src}.jpg ${this.w * 0.5}w, `
          imgsrc += `/img/sm/${this.src}.jpg ${this.w * 0.25}w`
    
          return imgsrc
        },
        imgsize () {
          let imgsize = ''
    
          if (this.xsSize !== undefined) imgsize += `(max-width: ${xsBreakpoint}) ${this.xsSize}vw, `
          if (this.smSize !== undefined) imgsize += `(max-width: ${smBreakpoint}) ${this.smSize}vw, `
          if (this.mdSize !== undefined) imgsize += `(max-width: ${mdBreakpoint}) ${this.mdSize}vw, `
          if (this.lgSize !== undefined) imgsize += `(max-width: ${lgBreakpoint}) ${this.lgSize}vw, `
          imgsize += `${this.size}vw`
    
          return imgsize
        }
      }
    }
    </script>
    


  • Thank you @benoitranque for specifying this! 🙂
    The only change I would make is to let webpack generate the imgsrc strings during the build and also actually build the smaller images.