Skip to content
This repository was archived by the owner on Jan 16, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion Imager.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
this.scrollDelay = opts.scrollDelay || 250;
this.onResize = opts.hasOwnProperty('onResize') ? opts.onResize : true;
this.lazyload = opts.hasOwnProperty('lazyload') ? opts.lazyload : false;
this.loadHidden = opts.hasOwnProperty('loadHidden') ? opts.loadHidden : true;
this.scrolled = false;
this.availablePixelRatios = opts.availablePixelRatios || [1, 2];
this.availableWidths = opts.availableWidths || defaultWidths;
Expand Down Expand Up @@ -308,7 +309,7 @@
this.refreshPixelRatio();

applyEach(images, function (image) {
if (filterFn(image)) {
if (self.isImageEligibleForReplacing(image) && filterFn(image)) {
self.replaceImagesBasedOnScreenDimensions(image);
}
});
Expand All @@ -318,6 +319,10 @@
}
};

Imager.prototype.isImageEligibleForReplacing = function (image) {
return this.loadHidden || Imager.isElementVisible(image);
};

/**
* Upgrades an image from an empty placeholder to a fully sourced image element
*
Expand Down Expand Up @@ -457,6 +462,19 @@
}
};

/**
* Elements are considered visible if they consume space in the document.
* Visible elements have a width or height that is greater than zero.
* Elements with visibility: hidden or opacity: 0 are considered visible,
* since they still consume space in the layout.
*
* @param {HTMLElement} el
* @returns {boolean} Whether or not the element is visible
*/
Imager.isElementVisible = function (el) {
return el.offsetWidth > 0 || el.offsetHeight > 0;
};

/**
* Returns the naturalWidth of an image element.
*
Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/hidden.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<style>
div { height: 10px; }
#hidden-element-implicit { height: 0; width: 0; }
</style>

<div id="visible-element" class="delayed-image-load" data-src="base/test/fixtures/media/A-320.jpg"></div>

<div id="main" style="display: none;">
<div id="hidden-child" class="delayed-image-load" data-src="base/test/fixtures/media/B-320.jpg"></div>
<div class="child">
<div id="hidden-sub-child" class="delayed-image-load" data-src="base/test/fixtures/media/B-640.jpg"></div>
</div>
</div>

<div id="hidden-element" style="display: none;" class="delayed-image-load" data-src="base/test/fixtures/media/C-320.jpg"></div>
<div id="hidden-element-visibility" style="visibility: hidden;" class="delayed-image-load" data-src="base/test/fixtures/media/C-320.jpg"></div>
<div id="hidden-element-implicit" class="delayed-image-load" data-src="base/test/fixtures/media/C-320.jpg">
<!-- no height -->
</div>
73 changes: 73 additions & 0 deletions test/unit/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,4 +276,77 @@ describe('Imager.js', function () {
expect(imgr.isThisElementOnScreen(element)).to.equal(true);
});
});

describe('checkImagesNeedReplacing', function () {

it('ignores images which are hidden when loadHidden is set to false', function () {
var imager = new Imager({
loadHidden: false
}),
imageVisibilities = [true, false, true];

sandbox.stub(imager, 'refreshPixelRatio');
sandbox.stub(Imager, 'isElementVisible').returnsArg(0);
sandbox.stub(imager, 'replaceImagesBasedOnScreenDimensions');

imager.checkImagesNeedReplacing(imageVisibilities);

// Only the first and third image should be replaced
expect(imager.replaceImagesBasedOnScreenDimensions.callCount).to.equal(2);
expect(imager.replaceImagesBasedOnScreenDimensions.getCall(0).args[0]).to.equal(true);
expect(imager.replaceImagesBasedOnScreenDimensions.getCall(1).args[0]).to.equal(true);
});

it('replaces all images if loadHidden is set to true (default)', function () {
var imager = new Imager(),
imageVisibilities = [true, false, true];

sandbox.stub(imager, 'refreshPixelRatio');
sandbox.stub(Imager, 'isElementVisible').returnsArg(0);
sandbox.stub(imager, 'replaceImagesBasedOnScreenDimensions');

imager.checkImagesNeedReplacing(imageVisibilities);

// All images should be loaded
expect(imager.replaceImagesBasedOnScreenDimensions.callCount).to.equal(3);
expect(imager.replaceImagesBasedOnScreenDimensions.getCall(0).args[0]).to.equal(true);
expect(imager.replaceImagesBasedOnScreenDimensions.getCall(1).args[0]).to.equal(false);
expect(imager.replaceImagesBasedOnScreenDimensions.getCall(2).args[0]).to.equal(true);
});
});

describe('isElementVisible', function () {

it('should return true if element is visible', function () {
fixtures = loadFixtures('hidden');
expect(Imager.isElementVisible(fixtures.querySelector('#visible-element'))).to.equal(true);
expect(Imager.isElementVisible(fixtures.querySelector('#visible-element'))).to.equal(true);
});

it('should return true if the element is set to visiblity: hidden', function () {
fixtures = loadFixtures('hidden');
expect(Imager.isElementVisible(fixtures.querySelector('#hidden-element-visibility'))).to.equal(true);
});

it('should return false if the element itself is display: none', function () {
fixtures = loadFixtures('hidden');
expect(Imager.isElementVisible(fixtures.querySelector('#hidden-element'))).to.equal(false);
});

it('should return false if the element has no height or width', function () {
fixtures = loadFixtures('hidden');
expect(Imager.isElementVisible(fixtures.querySelector('#hidden-element-implicit'))).to.equal(false);
});


it('should return false if the element is within a display: none element', function () {
fixtures = loadFixtures('hidden');
expect(Imager.isElementVisible(fixtures.querySelector('#hidden-child'))).to.equal(false);
});

it('should return false if the element is within a child of a display: none element', function () {
fixtures = loadFixtures('hidden');
expect(Imager.isElementVisible(fixtures.querySelector('#hidden-sub-child'))).to.equal(false);
});
});
});