javascript - 具有辅助功能和打印机支持的延迟加载图像

标签 javascript html accessibility lazy-loading web-performance

我正在寻找一种适当的方法来实现图像的延迟加载,而又不损害可打印性和可访问性,并且不引入布局偏移(内容跳转),最好使用 native loading=lazy和对旧版浏览器的后备功能。对How lazy loading images using JavaScript works? 问题的答案包括各种解决方案,但都不能完全满足所有这些要求。
一个优雅的解决方案应该基于有效且完整的html标记,即使用<img srcsrcsetsizeswidthheightloading属性,而不是像流行的javascript库lazysizesvanilla-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解决方案,使其能够使用srcsrcset进行工作,但这可能必须在以前就已经尝试过了,权衡是一旦惰性加载脚本开始作用于图像元素,浏览器可能已经开始下载该脚本了。源文件。

最佳答案

只是给我看一下您的丑陋代码,我不想读!
如果您不想阅读我的文章,最后一节“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,由于某些原因,“准备打印”屏幕在打印之前不会消失,但是所有其他功能都起作用(令人惊讶)!
尝试的事情:

  • 在不同的浏览器大小下尝试一下,以查看请求
  • 的动态图像
  • 在较慢的连接上尝试使用它,然后检查“网络”选项卡以查看正在执行的延迟加载以及取决于连接速度的延迟加载方式的动态变化。
  • 尝试在网络连接较慢时(不滚动页面)按CTRL + P,以查看我们如何在打印
  • 之前加载尚未在DOM中的图像
  • 尝试通过缓慢的网络连接加载页面,然后使用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图像,也要将其发送回去)。
    打印
    哦,这很有趣!
    如果我们发送文档进行打印并且尚未加载图像,我们将无能为力,我尝试了各种黑客手段(例如设置背景图像),但那是不可能的(或者我不够聪明,无法工作)出来....更有可能!)
    因此,我要做的是考虑现实世界中的场景,并尽可能优雅地覆盖它们。
  • 如果用户连接速度很快,我们会延迟加载图像,但是我们不必等待滚动来完成此操作。这可能意味着我们服务器上的负载会更多一些,但我的行为就像打印非常重要(仅次于速度)。
  • 如果用户连接速度较慢,则我们使用传统的延迟加载。
  • 如果他们按CTRL + P,我们将拦截打印命令并在加载图像时显示一条消息。这个概念是Core Web Vital,但是使用了我们的延迟加载机制。
  • 如果用户使用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>,它纯粹是为了冲突。
    如果您不关心布局移位,甚至可以忽略widthheight属性,但是由于累积布局移位(CLS)是version that nearly works in IE11 here,因此我不建议这样做。
    辅助功能
    这些图像只是标准图像,并且alt属性被保留。
    我什至还添加了一个额外的检查,即如果alt属性为空/缺少大红色边框,则会通过CSS类将其添加到图像中。
    问题/妥协
    如果页面已经滚动,则布局移位
    如前所述,如果已经滚动了页面,则将发生大量的布局转换,类似于将标准图像添加到不具有widthheight属性的页面上的情况。
    辅助功能
    尽管可以访问图像解决方案本身,但是按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/

    相关文章:

    javascript - 如何为我附加的 div 定义方法和属性?

    javascript - 如何使用 jquery 更改模式内的文本?

    javascript - Extjs 6-过滤网格

    javascript - 如何在jquery中检查父级

    html - 我在 CSS 中的媒体查询没有切换容器

    html - 如果 child 溢出,对象就会消失

    ios - 选择 UIButton 的可访问性标签?

    android - 如何使用 Android 中的辅助功能服务访问 WebView 元素的 AccessibilityNodeInfo 的 html 内容?

    html - CSS 定位边距问题

    html - 使用 HTML + 辅助功能,是否有显示 "audio is available for this content"的标准?