我正在寻找一种适当的方法来实现图像的延迟加载,而又不损害可打印性和可访问性,并且不引入布局偏移(内容跳转),最好使用 native loading=lazy
和对旧版浏览器的后备功能。对How lazy loading images using JavaScript works?
问题的答案包括各种解决方案,但都不能完全满足所有这些要求。
一个优雅的解决方案应该基于有效且完整的html标记,即使用<img src
,srcset
,sizes
,width
,height
和loading
属性,而不是像流行的javascript库lazysizes和vanilla-lazyload那样将数据放入data-
属性。也不应该使用<noscript>
元素。
由于bug in chrome,这是第一个支持 native 延迟加载的浏览器,因此尚未加载的图像将在打印页面中丢失。
上面提到的两个JavaScript库都要求完全没有任何src
属性的无效标记,或者需要一个空的或低质量的占位符(LQIP),而将src
数据放入data-src
中,而将srcset
数据放入data-srcset
中,所有这些都只能工作使用javascript。这是否被认为是2020年可接受甚至最佳的做法,这是否不会损害网站的可访问性,跨设备兼容性或搜索引擎优化?
更新:
我仅使用HTML和CSS @media print
背景图像in this codepen尝试了一种解决打印错误的方法。即使这按预期工作了,每个图像都将有一个必要的css指令,这既不是优雅的也不是通用的。不幸的是,在<picture>
元素内也无法使用媒体查询。
Houssein Djirdeh在lazy-load-with-print-ctl1l4wu1.now.sh处还有另一种解决方法,当单击“打印”按钮时,使用JavaScript将loading=lazy
更改为loading=eager
。相同的函数也可以使用onbeforeprint。
我做了一个codepen using lazysizes。
我又做了一个codepen using vanilla-lazyload。
我曾想过要派一个JavaScript解决方案,使其能够使用src
和srcset
进行工作,但这可能必须在以前就已经尝试过了,权衡是一旦惰性加载脚本开始作用于图像元素,浏览器可能已经开始下载该脚本了。源文件。
最佳答案
只是给我看一下您的丑陋代码,我不想读!
如果您不想阅读我的文章,最后一节“Demo”中将包含一个 fiddle ,您可以使用说明进行研究(在代码中进行了很好的注释)。
或者,如果您想使用link to the demo on a domain I control here that is easier to test against,请输入version that nearly works in IE here。
还有一个https://placehold.it,由于某些原因,“准备打印”屏幕在打印之前不会消失,但是所有其他功能都起作用(令人惊讶)!
尝试的事情:
FILE > PRINT
查看我们如何处理在这种情况下尚未加载的图像。 版本0.1,概念证明
因此,还有很长的路要走,但是我想到目前为止我将分享我的解决方案。
它很复杂(并且有缺陷),但是它大约是您要求的90%,并且比当前的图像延迟加载可能是更好的解决方案。
同样,当我在制作一个原型(prototype)原型(prototype)时,我会写干净的JS。在此阶段,我只能向任何敢于尝试并理解我的代码的人致歉!
仅在chrome 中进行了测试-因此,您可以想象它可能在其他浏览器中不起作用,尤其是因为众所周知,获取
<noscript>
标签的内容不一致。但是最终我希望这将是一个可立即投入生产的解决方案。最终,在此阶段构建API的工作量很大,因此对于图像大小调整,我使用了taken from the example OP gave by Houssein Djirdeh-因此,这里需要删除几行冗余代码。
主要功能/优点
没有浪费的图像字节
此解决方案计算要请求的图像的实际大小。因此,实际上不是说在
<picture>
元素中添加断点,而是说我们想要的是427px宽的图像。显然,这需要服务器端图像大小调整解决方案(这超出了堆栈溢出答案的范围),但是好处是巨大的。
首先,如果您更改站点上的所有断点都没有关系,那么就不必在任何地方更新图片元素。
其次,以kb表示的320px和400px宽图像之间的差异是的40%以上,因此选择“大小相似”的图像并不理想(这基本上就是
<picture>
元素所做的事情)。第三,如果人们(像我一样)拥有庞大的4K监视器和不错的连接速度,则实际上可以为他们提供4K图像(尽管连接速度检测是我需要在0.2版中进行的改进)。
第四,如果图像在一个屏幕尺寸下是其父容器的50%宽度,在另一屏幕尺寸下是其父容器的25%宽度,但是在一个屏幕尺寸下该容器是60%的屏幕宽度而在另一个屏幕尺寸下是80%的屏幕宽度。
试图在
<picture>
元素中做到这一点充其量只能令人沮丧。如果您随后决定更改布局,则更糟,因为您必须重新计算所有宽度百分比等。最后,这可以节省制作页面的时间/可以与CMS很好地协作,因为您无需教别人如何在图像上设置断点(因为我还没有看到CMS可以比设置断点好得多,图像在屏幕上为全 Angular )。
最小标记(和语义正确的标记)
尽管您不想使用
<noscript>
并避免使用data
属性,但我需要同时使用这两个属性。但是,您编写/生成的标记实际上是一个
<img>
元素,该元素按照通常的方式包装在<noscript>
标记中。图像完全加载后,所有杂物都将被删除,因此您的DOM仅带有
<img>
元素。如果您想替换该解决方案(如果浏览器技术有所改善等),那么对
<noscripts>
进行简单替换将使您获得准备进行改进的标准HTML标记。WebP
当然,如果支持,此解决方案将请求WebP图像(这全部与性能有关!)。在服务器端,您需要相应地进行处理(例如,如果图像是具有透明性的PNG,则即使请求WebP图像,也要将其发送回去)。
打印
哦,这很有趣!
如果我们发送文档进行打印并且尚未加载图像,我们将无能为力,我尝试了各种黑客手段(例如设置背景图像),但那是不可能的(或者我不够聪明,无法工作)出来....更有可能!)
因此,我要做的是考虑现实世界中的场景,并尽可能优雅地覆盖它们。
FILE > PRINT
打印,则我们为尚未加载的图像显示一个占位符,说明他们需要滚动页面才能显示图像。 (占位符的大小与图片的大小大致相同)。 这是我现在可能想到的最好的折衷方案。
没有布局移位(假设要延迟加载的内容在页面加载时不在屏幕上)。
这不是一个100%完美的解决方案,但由于“首屈一指”的内容不应该被延迟加载,而且95%的页面访问从页面顶部开始,因此这是一个合理的折衷方案。
我们使用空白的SVG(以“即时”正确比例创建),并使用
data
URI作为图像的占位符,然后在需要加载图像时交换src
。这样可以避免网络请求,并确保在加载图像时不会出现布局偏移。这也意味着该页面在任何时候在语义上都是正确的,没有空的
hrefs
等。如果用户已经滚动页面然后重新加载,则布局会发生变化。这是因为
<img>
元素是通过JavaScript创建的(除非禁用了JavaScript,在这种情况下,图像是从图像的<noscript>
版本显示的)。因此,它们在解析时不存在于DOM中。这是可以避免的,但是需要在其他地方做出折衷,所以我目前认为这是可以接受的。
无需JavaScript和干净标记即可工作
原始标记只是
<noscript>
标记内的图像。没有自定义标记或data-attributes
等。我使用的标记是:
<noscript class="lazy">
<img src="https://placehold.it/1500x500" alt="an image" width="1500px" height="500px"/>
</noscript>
它并没有变得更加标准和干净,如果您在其他地方不使用class="lazy"
标记,它甚至不需要<noscript>
,它纯粹是为了冲突。如果您不关心布局移位,甚至可以忽略
width
和height
属性,但是由于累积布局移位(CLS)是version that nearly works in IE11 here,因此我不建议这样做。辅助功能
这些图像只是标准图像,并且
alt
属性被保留。我什至还添加了一个额外的检查,即如果
alt
属性为空/缺少大红色边框,则会通过CSS类将其添加到图像中。问题/妥协
如果页面已经滚动,则布局移位
如前所述,如果已经滚动了页面,则将发生大量的布局转换,类似于将标准图像添加到不具有
width
和height
属性的页面上的情况。辅助功能
尽管可以访问图像解决方案本身,但是按CTRL + P时不会出现该屏幕。我这纯粹是懒惰,一旦存在更多最终解决方案,就很容易解决。
但是,缺少Internet Explorer支持(请参阅下文)是一个重大的可访问性问题。
IE
更新
有一个https://jsfiddle.net/9d5qs6ba/。我正在研究是否可以使它一直运行到IE9。
还在Firefox,Edge和Safari(移动版)中进行了测试,似乎可以在其中运行。
原始
尽管未在Firefox,Safari等中对此进行过测试,但是如果出现问题,可以很容易地在那里开始工作。
但是,在IE和其他较旧的浏览器中,访问
<noscript>
标记的内容非常困难(在某些版本中是不可能的),因此,此解决方案可能永远无法在IE中使用。当涉及到可访问性时,这一点很重要,因为许多屏幕阅读器用户都依赖IE,因为它与JAWS很好地兼容。
我想到的解决方案是在服务器上使用用户代理嗅探,并提供不同的标记和JavaScript,但这很复杂且非常小众,因此我不会在此答案内进行。
检查延迟
我正在使用一种相当粗糙的方式来检查等待时间(以尝试猜测某人是否处于3G/4G连接中)两次下载一个微小的镜像并测量加载时间。
2个不需要的网络请求在尝试获得最佳性能时并不理想(不是由于我下载了100个字节的,而是由于初始化事物之前高延迟连接的延迟)。
这需要彻底的重新思考,但是在我从事其他工作时,它现在仍会执行。
演示版
由于字符数限制为30,000个字符,因此无法使用嵌入式 fiddle !
这是当前的JS Fiddle-https://inhu.co/so/image-concept.php。
或者,如前所述,可以在ojit_a上我控制的域上更轻松地查看和测试该演示。
我知道这不是链接到您自己的域的“完成的事情”,但是很难在jsfiddle等上测试打印。
关于javascript - 具有辅助功能和打印机支持的延迟加载图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65378621/