dinbror / blazy

Hey, be lazy! bLazy.JS is a lightweight pure JavaScript script for lazy loading and multi-serving images. It's working in all modern browsers including IE7+.
http://dinbror.dk/blazy
MIT License
2.63k stars 356 forks source link

blazy issue in safari - Mac OS, iOS - not loading images in viewport for the first time #125

Open smanikandan7 opened 7 years ago

smanikandan7 commented 7 years ago

I am facing issue in loading the images for the first time in Safari - Mac OS and in iOS using blazy.

When you load the page for the first time - the images in the view port are not rendering, when scrolled down the other images are rendering properly. This issue occurs only in Safari browser on Mac OS and in iOS and works fine in Chrome, Mozilla.

When we refresh the page, all the images are loaded properly.

How to resolve the above issue ??

Bcld-net commented 7 years ago

Hi, I have the same issue !

But for background images, it's ok !

dinbror commented 7 years ago

Hey @smanikandan7 and @Bcld-net.

Do you have a live example? Do you see the same behavior on my examples page (http://dinbror.dk/blazy/examples/)?

Bcld-net commented 7 years ago

Hi @dinbror,

An example in this site: http://gitelevaldesfees.fr/Location-de-velos-a-assistance-electrique

In your examples page, I don't have the issue...

Thanks

dinbror commented 7 years ago

@Bcld-net

Try 1) move you script to the bottom of your body. (so it wont block rendering). 2) Since your're using jquery initialize blazy on dom.ready

Bcld-net commented 7 years ago

Hi @dinbror,

  1. I have try to move script at the bottom of the body but without success !
  2. I already initialized blazy on DOM.ready !

For the moment, I use a poor solution and it's ok in Safari (MacOS and iOS): setTimeout(function() { bLazy.revalidate(); }, 1000);

Thanks

dgorges commented 7 years ago

Unfortunately, this fix won´t work. When I am changing the window width until the image dimension is reached the image is shown. Until that bLazy is not triggered. I am using srcsets in a

philspbr commented 7 years ago

I have the same issue, just updated to the most recent version of the plugin but the problem persists. It seems it only affects Safari when using preloading / loading images out of the viewport. On initial load the images in the viewport do not display, when scrolling down, the other images are loaded correctly. The first images only show after reloading the page.

dinbror commented 7 years ago

Hey @dgorges, @philspbr

Do you have a live example? Do you see the same issue on my example page: http://dinbror.dk/blazy/examples/

dgorges commented 7 years ago

Hey @dinbror , unfortunately this is a .htaccess protected page. I use modernizr to load my js. <script> Modernizr.load([ { load : ['[/Resources/Public/JavaScript/lib/jquery.min.js', '[/Resources/Public/JavaScript/lib/jquery.plugins.min.js', 'ielt9![/Resources/Public/JavaScript/lib/selectivizr.min.js'] }, { test : Modernizr.mq('only all'), nope : '[/Resources/Public/JavaScript/lib/respond.min.js' }, '[/Resources/Public/JavaScript/lib/blazy.min.js','[/Resources/Public/JavaScript/main.min.js','[/Resources/Public/JavaScript/global.min.js']); </script>

In my main.min.js I have the bLazy plugin

`var B = B || {}; (function($) { // main init function is called on document ready B.initialize = function() { B.lazy.initialize(); }; /**

In the global.min.js I have some plugins (i.e. flexslider) where I revalidate the lazy images

` $('.JM_obj-slider').flexslider({ animation: 'slide', controlNav: true, directionNav: false, pauseOnAction: true, // pauseOnHover: true, start: function(slider){

    B.lazyimage.revalidate();
},
before: function (slider) { // fires asynchronously with each slider animation

    B.lazyimage.revalidate();
}

});`

Thank you in advance for your help.

dinbror commented 7 years ago

@dgorges Looks ok to me. Do you see the same issue on my example page: http://dinbror.dk/blazy/examples/

yswang0927 commented 7 years ago

@dinbror @smanikandan7 @Bcld-net I solved the issue. This is a bug in the new version of Safari.

I tracked the source code(v1.8.2) and found the problem at 205 line(in function loadElment) : The value of ele.offsetHeight is zero in Safari (but it is not zero in Chrome, IE etc. ), so the condition of (ele.offsetWidth > 0 && ele.offsetHeight > 0) is false and the image can never be loaded.

How to solve it ? We just need to set the css property min-height: 1px to these lazy images, and the issue will be solved.

Hope to help you!

smanikandan7 commented 7 years ago

Hi yswang0927,

That's great!!

Bcld-net commented 7 years ago

Hi @yswang0927

For me, it's OK !

Thanks

mxhCodes commented 6 years ago

I'm using this library in combination with the Drupal integration (drupal.org/project/blazy) and can confirm this problem. I tracked down the source problem to this part of the blazy.js code:

// start lazy load setTimeout(function() { initialize(scope); }); // "dom ready" fix

We need a proper trigger here. Something like DOMContentLoaded. I'm trying it out and report back here.

Update: I tried with the help of domready (https://github.com/ded/domready) and replaced above code with:

        setTimeout(function() {
            domready(function () {
              initialize(scope);
            });
        }); // "dom ready" fix

Now the problem is gone away. Hint: Drupal core already includes domready via the core/domready library. I'm considering to create a fork which makes use of Drupal's core/domready library.

Update 2: Instead of creating the fork, I decided to write a custom Blazy loader which revalidates on the load event of the window object.

fabianmarz commented 5 years ago

@mxhaupt, I'm encountering the same issue. Could you please provide your custom loader and how you implemented this? Thanks in advance 👍

mxhCodes commented 5 years ago

@fabianmarz This is my current implementation, a modification of blazy.load.js of the Drupal blazy module:

/**
 * @file
 * Provides bLazy loader. Modified for lighter loading and to be compatible with Safari browsers.
 */

(function (Drupal, drupalSettings, _db, window) {

  'use strict';

  /**
   * Blazy public methods.
   *
   * @namespace
   */
  Drupal.blazy = Drupal.blazy || {
    init: null,
    windowWidth: 0,
    done: false,
    globals: function () {
      var me = this;
      var settings = drupalSettings.blazy || {};
      var commons = {
        success: me.clearing,
        error: me.clearing
      };

      return _db.extend(settings, commons);
    },

    clearing: function (el) {
      var ie = _db.hasClass(el, 'b-responsive') && el.hasAttribute('data-pfsrc');

      // The .b-lazy element can be attached to IMG, or DIV as CSS background.
      el.className = el.className.replace(/(\S+)loading/, '');

      // The .is-loading can be .grid, .slide__content, .box__content, etc.
      var loaders = [
        _db.closest(el, '.is-loading'),
        _db.closest(el, '[class*="loading"]')
      ];

      // Also cleans up closest containers containing loading class.
      _db.forEach(loaders, function (wrapEl) {
        if (wrapEl !== null) {
          wrapEl.className = wrapEl.className.replace(/(\S+)loading/, '');
        }
      });

      // @todo: Remove when Blazy library fixes this.
      // @see http://scottjehl.github.io/picturefill/
      if (window.picturefill && ie) {
        window.picturefill({
          reevaluate: true,
          elements: [el]
        });
      }
    },

    loadGlobally: function () {
      if (this.init == null) {
        this.init = new Blazy(this.globals());
      }
      else {
        this.init.revalidate();
      }
    }
  };

  /**
   * Add an extra listener to the window load event and perform revalidation.
   * This makes sure that Safari also loads images on initial requests.
   */
  window.addEventListener('load', function () {
    Drupal.blazy.loadGlobally();
  });

  /**
   * Attaches blazy behavior to HTML element identified by [data-blazy].
   *
   * @type {Drupal~behavior}
   */
  Drupal.behaviors.blazy = {
    attach: function (context, settings) {
      Drupal.blazy.loadGlobally();
    }
  };

}(Drupal, drupalSettings, dBlazy, window));

I'm overriding the library definition this way:

/**
 * Implements hook_library_info_alter().
 */
function mymodule_library_info_alter(&$libraries, $extension) {
  if ($extension === 'blazy') {
    $libraries['load']['js'] = ['/' . drupal_get_path('module', 'mymodule') . '/js/blazy.load.js' => ['weight' => -1, 'minified' => FALSE]];
  }
}
fabianmarz commented 5 years ago

Thanks for providing the code. It seems to work now. 🎉