带有<noscript>后备的DRY延迟加载图像

Nev*_*kes 5 javascript lazy-loading

我知道(少数几个)非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" />
Run Code Online (Sandbox Code Playgroud)

主要是出于好奇,我想知道是否有可能从<noscript>标签中取出后退并使用JavaScript以编程方式将其添加到DOM中,以便不必在两个图像标签中复制图像源我只是:

<noscript>
    <img src="image.jpg" class="lazyload" width="600" height="400"/>
</noscript>
Run Code Online (Sandbox Code Playgroud)

这是我一起敲的东西:

(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
Run Code Online (Sandbox Code Playgroud)

这似乎无处不在(Chrome,Safari,Opera,Firefox),除了Internet Explorer(自然).我知道在.textContentIE9之前不可用,但IE9 +似乎都在最后的障碍中失败了 - .outerHTML.我注定要失败,不得不在我的标记中重复自己吗?

更新:为了澄清,我理想地希望能够在图像标记中使用任意属性(alt,title等),甚至使用响应式标记:

<noscript>
    <picture>
        <source ... />
        <source ... />
        <img src="image.jpg" />
    </picture>
</noscript>
Run Code Online (Sandbox Code Playgroud)

gij*_*ijs 8

自 2019 年起,该img标签有了一个新属性:loading。您可以指定loading="lazy"延迟加载图像,直到图像达到浏览器定义的距视口的计算距离。

它具有广泛的浏览器支持(Edge、Firefox、Chrome、Safari 和 Opera): 浏览器支持图像延迟加载

如果使用较旧的浏览器或禁用 Javascript,则默认为急切/正常加载。后者是一种反跟踪措施,因为如果用户代理在禁用脚本时支持延迟加载,则站点仍然可以通过策略性地将图像放置在页面的标记中来跟踪用户的大致滚动位置。(来源:https ://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading )


ale*_*kas 7

我是lazySizes的创造者.这种方法有多个问题:

  1. noscript元件从不renderend,这意味着它是不可检测的,它阉是可见或不可见(或更好的表示,它是不可见的总是)
  2. 您不能使用有状态类lazyloading并向lazyload用户提供反馈
  3. 您不能预先占用懒惰嵌入内容的空间(这对于用户体验(无内容跳转)和b)性能(无重排)都很重要
  4. (在旧版浏览器中存在问题)
  5. 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>
Run Code Online (Sandbox Code Playgroud)

而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]);
        }
    });
})();
Run Code Online (Sandbox Code Playgroud)

如果你喜欢这个,我可能会为此制作一个官方插件.这是插件:https://github.com/aFarkas/lazysizes/tree/master/plugins/noscript


ade*_*neo 4

这是我的做法,使用所有浏览器都可用的方法

(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");
Run Code Online (Sandbox Code Playgroud)