Image with declared width and height renders square before load

后端 未结 6 2351
不思量自难忘°
不思量自难忘° 2021-02-13 11:15

I have images with declared widths and heights, e.g.:

\"bar\"

They are within

相关标签:
6条回答
  • 2021-02-13 11:38

    You can achieve the desired effect with the following solution.

    HTML:

    <img src="blank.gif" class="lazy" data-src="foo.png" width="1500" height="1800" alt="bar">  
                 ▲                ▲  
                 ║                ╚═══ The class will be used for the lazy loader below  
                 ║  
                 ╚═══ Use faulty gif here to hide it from showing before loaded
    

    Hint: If you want the placeholder rectangle to be visible and in one color, consider using a 1x1 px image for blank.gif. It will load very fast and will stretch nicely to your proportions, filling it with the color of your choosing.

    JavaScript:

    /* lazyload.js (c) Lorenzo Giuliani
     * MIT License (http://www.opensource.org/licenses/mit-license.html)
     *
     * expects a list of:  
     * `<img src="blank.gif" data-src="my_image.png" width="600" height="400" class="lazy">`
     */
    
    !function(window){
      var $q = function(q, res){
            if (document.querySelectorAll) {
              res = document.querySelectorAll(q);
            } else {
              var d=document
                , a=d.styleSheets[0] || d.createStyleSheet();
              a.addRule(q,'f:b');
              for(var l=d.all,b=0,c=[],f=l.length;b<f;b++)
                l[b].currentStyle.f && c.push(l[b]);
    
              a.removeRule(0);
              res = c;
            }
            return res;
          }
        , addEventListener = function(evt, fn){
            window.addEventListener
              ? this.addEventListener(evt, fn, false)
              : (window.attachEvent)
                ? this.attachEvent('on' + evt, fn)
                : this['on' + evt] = fn;
          }
        , _has = function(obj, key) {
            return Object.prototype.hasOwnProperty.call(obj, key);
          }
        ;
    
      function loadImage (el, fn) {
        var img = new Image()
          , src = el.getAttribute('data-src');
        img.onload = function() {
          if (!! el.parent)
            el.parent.replaceChild(img, el)
          else
            el.src = src;
    
          fn? fn() : null;
        }
        img.src = src;
      }
    
      function elementInViewport(el) {
        var rect = el.getBoundingClientRect()
    
        return (
           rect.top    >= 0
        && rect.left   >= 0
        && rect.top <= (window.innerHeight || document.documentElement.clientHeight)
        )
      }
    
        var images = new Array()
          , query = $q('img.lazy')
          , processScroll = function(){
              for (var i = 0; i < images.length; i++) {
                if (elementInViewport(images[i])) {
                  loadImage(images[i], function () {
                    images.splice(i, i);
                  });
                }
              };
            }
          ;
        // Array.prototype.slice.call is not callable under our lovely IE8 
        for (var i = 0; i < query.length; i++) {
          images.push(query[i]);
        };
    
        processScroll();
        addEventListener('scroll',processScroll);
    
    }(this);
    

    Sources: The Lazyload script can be found here.

    0 讨论(0)
  • 2021-02-13 11:40

    Right off the bat I notice that you are using px instead of % for width and height. Responsive HTML 5 DOCType. you should use percentage. There to many phones and tablets out there visiting your website.

    Use meta tag viewport in your headers. Try something like this

     <meta name="viewport" content="initial-scale=1, maximum-scale=1">
    

    For further information on how to correctly re-size your web page for any device go here https://developer.mozilla.org/en-US/docs/Mozilla/Mobile/Viewport_meta_tag

    I recon-mind that you use CSS to control the height and width of the image try to stay away from attributes if possible. Use min and max along with your width and height sectors for width and height in you CSS code. You don't need JavaScript to solve your issues

    0 讨论(0)
  • 2021-02-13 11:43

    Could you please add required max-height for the image in css. I think this would solve your problem.

    0 讨论(0)
  • 2021-02-13 11:43

    The following is the only solution that worked 100% of the time, and is much simpler: https://css-tricks.com/preventing-content-reflow-from-lazy-loaded-images/

    In short you can use an SVG placeholder image that contains the dimenions:

    <img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 2'%3E%3C/svg%3E" data-src="//picsum.photos/900/600" alt="Lazy loading test image" />
    

    Here is an React example:

    const placeholderSrc = (width, height) => `data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${width} ${height}"%3E%3C/svg%3E`
    
    const lazyImage = ({url, width, height, alt}) => {
      return (
        <img
          src={placeholderSrc(width, height)}
          data-src={url}
          alt={alt} />
      )
    }
    
    0 讨论(0)
  • 2021-02-13 11:44

    At time of writing none of the answers explain why this happens or how to overcome it. I found another question which is the same as this one that explains an interesting "hack" to get around this.

    0 讨论(0)
  • 2021-02-13 11:52

    Here i made a FIDDLE for you

    The Main thing is to generate a div around it and setting the height and the width according to what it should be after it loads. then you can load it inside that container and even with a smooth effect ;)

    HTML

    <div class="site-wrapper">
        <div class="lazyload" data-src="http://tinyurl.com/py2nunk" data-width="1920" data-height="1200"></div>
    </div>
    

    CSS

    .site-wrapper {
        width:960px;
    }
    .lazyload {
        max-width: 100%;
        border: 1px solid #000;
    }
    .lazyload img {
        max-width: 100%;
    }
    

    JAVASCRIPT

    $(document).ready(function() {
        $('.lazyload').each(function() {
            var parentwidth = $(this).parent().width();
            var width  = $(this).attr('data-width');    
            var height = $(this).attr('data-height');
    
            if(parentwidth < width) {
                height = (parentwidth/width*height);
                width = parentwidth;
            }
    
            $(this).css({ width: width+'px', height: height+'px'});
    
        });
    
        // simulating lazyload
        setTimeout(function() {
            $('.lazyload').each(function() {
                img = $('<img>', { 'class': 'lazyloaded' }).css({display: 'none'});
                original = $(this);
                $(img).load( function(){
                    original.append(img);
                    $(this).fadeIn(200);
                }).attr('src', $(this).attr('data-src'));
            });
        }, 5000);
    });
    

    Let me know if this is what you need or not so i can change according to what you need.

    0 讨论(0)
提交回复
热议问题