我知道(少数几个)非JavaScript用户在那里,我想照顾他们,而不是因为他们的偏好(因为隐私原因或其他原因)给他们较差的体验。
大多数延迟加载的JS库似乎都以同样的方式解决了这个问题,例如见lazysizes:
<style>
.no-js img.lazyload {
display: none;
}
</style>
<noscript>
<img src="image.jpg" />
</noscript>
<img src="grey.jpg" data-src="image.jpg" class="lazyload" />
主要是出于好奇,我想知道是否可以从<noscript>
标签中取出后退并使用JavaScript以编程方式将其添加到DOM中,以便图像源不具备要复制在两个图像标签中,这将只留下:
<noscript>
<img src="image.jpg" class="lazyload" width="600" height="400"/>
</noscript>
这是我一起敲的东西:
(function(attribute) {
Array.prototype.forEach.call(document.getElementsByTagName("noscript"), function(node) {
var parser = new DOMParser,
el = parser.parseFromString(node.textContent, "text/xml").documentElement, // XML => <img/> required
img = ("img" == el.tagName) ? el : el.getElementsByTagName("img")[0]; // allow for <img/> in <picture>
img.setAttribute(attribute, img.getAttribute("src"));
img.setAttribute("src", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC");
node.insertAdjacentHTML("beforebegin", el.outerHTML);
});
})("data-src"); // different libraries use different data attribute names
这似乎无处不在(Chrome,Safari,Opera,Firefox),除了Internet Explorer(自然)。我知道IE9之前.textContent
不可用,但IE9 +似乎都在最后的障碍中失败 - .outerHTML
。我注定要失败,不得不在我的标记中重复自己吗?
更新:为了澄清,我非常希望能够在图片代码中使用任意属性(alt,title等),甚至可以使用自适应标记:
<noscript>
<picture>
<source ... />
<source ... />
<img src="image.jpg" />
</picture>
</noscript>
答案 0 :(得分:7)
我是lazySizes的创建者。这种方法有多个问题:
noscript
元素永远不会是渲染,这意味着它是不可检测的,是否可见(或更好地说它总是不可见的)lazyloading
和lazyload
向用户提供反馈data-sizes="auto"
功能但是,如果4.和5.对您来说不是问题,则可以将noscript
子元素与lazyload
父元素结合使用来实现此目的。
标记看起来像这样:
<div class="lazyload" data-noscript="">
<noscript>
<p>any kind of content you want to be unveiled</p>
</noscript>
</div>
lazySizes插件代码看起来像这样:
(function(){
'use strict';
var supportPicture = !!window.HTMLPictureElement;
addEventListener('lazybeforeunveil', function(e){
if(e.defaultPrevented || e.target.getAttribute('data-noscript') == null){return;}
var imgs, i;
var noScript = e.target.getElementsByTagName('noscript')[0] || {};
var content = noScript.textContent || noScript.innerText || '';
e.target.innerHTML = content;
if(supportPicture){return;}
imgs = e.target.querySelectorAll('img[srcset], picture > img');
for(i = 0; i < imgs.length; i++){
lazySizes.uP(imgs[i]);
}
});
})();
如果您喜欢这个,我可能会为此制作一个官方插件。这是插件:https://github.com/aFarkas/lazysizes/tree/master/plugins/noscript
答案 1 :(得分:3)
以下是我如何使用应在所有浏览器中提供的方法
(function(attribute) {
Array.prototype.forEach.call(document.getElementsByTagName("noscript"), function(node) {
var content = node.childNodes[0].nodeValue,
parser = new DOMParser(),
doc = parser.parseFromString(content, "text/html"),
images = doc.getElementsByTagName('img');
for (var i=images.length; i--;) {
var img = document.createElement('img');
img.src = 'data:image/png;base64,iVBOR ....';
img.height = images[i].getAttribute('height');
img.width = images[i].getAttribute('width');
img.setAttribute(attribute, images[i].getAttribute('src'));
node.parentNode.insertBefore(img, node.nextSibling);
}
});
})("data-src");
答案 2 :(得分:2)
这是我使用的技巧:
(function() {
"use strict";
var config = {
// If the image gets within 50px in the Y axis, start the download.
rootMargin: "50px 0px",
threshold: 0.01
};
var observer;
//If we're using a browser without the IntersectionObserver (IE11, Safari 11), skip the lazy part and just load the resources
if ("IntersectionObserver" in window) {observer = new IntersectionObserver(onIntersection, config);}
//If we're using a browser without requestAnimationFrame (IE9, Opera Mini), just run the passed function
var rAF;
if ("requestAnimationFrame" in window) rAF = window.requestAnimationFrame;
else rAF = function(func) { func(); };
var tempImg = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
/**
* Temporarily replace a expensive resource load with a cheap one
*/
function storeSourceForLater(lazyItem, tempData) {
//Store our ACTUAL source for later
lazyItem.setAttribute("data-lazy-src", lazyItem.getAttribute("src"));
//Set the item to point to a temporary replacement (like a data URI)
lazyItem.setAttribute("src", tempData);
//Now observe the item so that we can start loading when it gets close to the viewport
observer.observe(lazyItem);
}
/**
* Temporarily prevent expensive resource loading by inserting a <source> tag pointing to a cheap one (like a data URI)
*/
function jamSourceLoading(lazyItem, tempData) {
var newSource = document.createElement("source");
newSource.setAttribute("srcset", tempData);
newSource.setAttribute("data-lazy-remove", "true");
//adding this source tag at the start of the picture tag means the browser will load it first
lazyItem.insertBefore(newSource, lazyItem.firstChild);
var baseImage = lazyItem.getElementsByTagName("img")[0];
if (baseImage) {
//this is a picture tag, so we need to watch the image (as the picture tag is smaller than the image usually)
observer.observe(baseImage);
}
}
/**
* Set up the lazy items so that they won't try to load when we add them to the document, but will once the user is close to seeing them
*/
function prepareLazyContents(lazyArea) {
var lazyImgs = lazyArea.getElementsByTagName("img");
for(var i = lazyImgs.length; i--;){
storeSourceForLater(lazyImgs[i], tempImg);
}
var lazyPictures = lazyArea.getElementsByTagName("picture");
for(var i3 = lazyPictures.length; i3--;) {
jamSourceLoading(lazyPictures[i3], tempImg);
}
}
/**
* Put the source back where we found it - now that the element is attached to the document, it will load now
*/
function restoreSource(lazyItem) {
lazyItem.setAttribute("src", lazyItem.getAttribute("data-lazy-src"));
lazyItem.removeAttribute("data-lazy-src");
}
/**
* Remove the source tag preventing the loading of picture/audio/video
*/
function removeJammingSource(lazyItem) {
var jammingSource = lazyItem.querySelector("source[data-lazy-remove]");
if (jammingSource) lazyItem.removeChild(jammingSource);
}
/**
* Handle the intersection postback
*/
function onIntersection(entries, obsvr) {
entries.forEach(function(entry) {
if(entry.intersectionRatio === 0) return;
//if the item is now visible, load it and stop watching it
var lazyItem = entry.target;
obsvr.unobserve(lazyItem);
//Just in case the img is the decendent of a picture element, check for source tags
removeJammingSource(lazyItem.parentNode);
restoreSource(lazyItem);
});
}
/**
* Retrieve the elements from the 'lazy load' no script tags and prepare them for display
*/
function setUp() {
//Get all the noscript tags on the page
var lazyLoadAreas = document.getElementsByTagName("noscript");
for(var i = lazyLoadAreas.length; i--;) {
var noScriptTag = lazyLoadAreas[i];
//only process the ones marked for lazy loading
if (!noScriptTag.hasAttribute("data-lazy-load")) continue;
// The contents of a noscript tag are treated as text to JavaScript
var lazyAreaHtml = noScriptTag.textContent||noScriptTag.innerHTML;
// So we stick them in the innerHTML of a new div tag to 'load' them
var lazyArea = document.createElement("div");
lazyArea.innerHTML = lazyAreaHtml;
//Only delay loading if we can use the IntersectionObserver to check for visibility
if(!observer) {
noScriptTag.parentNode.replaceChild(lazyArea, noScriptTag);
} else {
prepareLazyContents(lazyArea);
noScriptTag.parentNode.replaceChild(lazyArea, noScriptTag);
}
}
}
//If the page has loaded already, run setup - if it hasn't, run as soon as it has.
//Use requestAnimationFrame as this will propably cause repaints
if (/comp|inter/.test(document.readyState)) {
rAF(setUp);
} else if ("addEventListener" in document) {
document.addEventListener("DOMContentLoaded",
function(){rAF(setUp);});
} else {
document.attachEvent("onreadystatechange", function() {
if (document.readyState=="complete") {
setUp();
}
});
}
})();
<p>Scroll down to see lazy loading in action!</p>
<noscript><p>Even with JavaScript turned off, the images should still load.</p></noscript>
<p>Why are the assets in noscript tags? So that they will load for people who have turned JavaScript off!</p>
<p>(The conditional comments are becuase there is no way to fetch the contents of a noscript tag in IE8 and below.)</p>
<hr/>
<div style="height: 600px;"></div>
<hr/>
<!--[if (gt IE 8)|!(IE)]><!--><noscript data-lazy-load><!--<![endif]-->
<img src="//upload.wikimedia.org/wikipedia/commons/2/27/F-16_Plan_Black_on_Circle_Light_Blue.svg?c=25" alt="This is an image used to demonstrate a lazy-loading trick." width="250" height="250">
Here is some text on the outside to demonstrate the lack of reflows!
<!--[if (gt IE 8)|!(IE)]><!--></noscript><!--<![endif]-->
<hr/>
<!--[if (gt IE 8)|!(IE)]><!--><noscript data-lazy-load><!--<![endif]-->
<picture>
<img src="//upload.wikimedia.org/wikipedia/commons/2/27/F-16_Plan_Black_on_Circle_Light_Blue.svg?c=25" alt="This is an image used to demonstrate a lazy-loading trick." width="250" height="250">
</picture>
This one is a reponsive picture element!
<!--[if (gt IE 8)|!(IE)]><!--></noscript><!--<![endif]-->
只有支持Intersection Observer的浏览器上的延迟加载(因此不支持IE,但在撰写本文时约为87% of the world),但是图像将在所有浏览器中显示。