HTML和CSS技术可减少JavaScript

2021-01-20 11:47:10

安东尼·里考(Anthony Ricaud)(@anthony_ricaud)是一位网络工程师,帮助团队以可持续的速度发布高效的产品。对Web协议和浏览器有广泛的了解,他喜欢设计简单但快速的Web体系结构。

越来越多的网站依靠JavaScript进行交互。它不仅带来令人愉悦的体验,而且还带来不良影响:

在JavaScript加载之前,页面无法使用,如果加载成功,则没有任何错误

没有团队和能力来关注这些问题,可能缺乏可用性,反应性和可访问性。

鉴于这些缺点,依靠浏览器本机提供的解决方案使您可以低成本地受益于创建Web标准的社区的专业知识。这些解决方案通常具有使用较少代码的优势,从而减少了开发团队的维护工作(例如,无需更新所使用的库)。

在本文中,我们将探索大多数用户都可以使用的一些本机解决方案。我们将看到一些示例,但是我们不会深入探讨所有细微之处,因为其他资源也能很好地做到这一点。相反,目标是让您了解这些技术的存在。

在介绍每种技术之前,请先快速提醒一下使用JavaScript的一个重大缺点:浏览器只有一个线程来控制页面的呈现。运行JavaScript时,浏览器会延迟用户交互事件和界面更新。这可能会很烦人,因为您会觉得页面没有对您的操作做出响应,或者动画令人讨厌。 Philip Walton详细介绍了此问题,并提供了一个演示。

开发团队倾向于每天使用功能强大的设备进行工作。这通常隐藏了我们JavaScript的负面影响。不要忘记定期在更多受限设备上进行测试。

(可以通过Web Workers在另一个线程中运行JavaScript,但对接口代码很少有用。)

限制显示的字符数。这非常脆弱,因为除等宽字体外,字符的宽度是可变的。您可能最终得到的行数超出了您想要的行数,或者文本被截断得太早。

通过反复尝试截断元素的内容,直到元素占据所需的行数。这非常昂贵,因为每次尝试时,都必须要求浏览器进行渲染,以查看是否获得所需的尺寸。而且,仅当在使用所需字体渲染后使用此技术时,此技术才是准确的,这可能会导致较大的版式偏移。

在包含大量要截断文本的页面中,这会延迟正确显示。另外,这两种解决方案完全截断了文本,这可能对搜索引擎或辅助技术的归还产生影响。字体的大小或元素的宽度也可以在页面的生命周期内更改(用户自愿,通过更改设备的方向自愿)。考虑到所有这些情况是很烦人的。

-webkit-line-clamp是一个CSS属性,可以原生执行此操作。该属性是十年前在Safari中引入的,已经被广泛使用,以至于其他浏览器出于兼容性原因也采用了此属性,并且已成为标准。 (是的,带前缀。)您需要其他一些带前缀的属性才能实现所需的行为。必须使用带前缀的属性有点烦人,但前缀已在标准中详细说明,因此我们不承担任何风险。

除版本68之前的Internet Explorer和Firefox外,所有浏览器均支持此属性。以下示例将其作为备用解决方案进行说明。

该解决方案没有性能或令人讨厌的内容转移问题,并且不会影响搜索引擎或辅助技术。但是,它不适用于有多个子项的项目。

您可能希望在页面的一部分中保持标题,工具栏或购物车可见。我经常遇到这种行为,但很少能正确实施。

从历史上看,要做到这一点,有必要聆听经常触发的滚动事件。很多时候,大多数解决方案都通过节流或反跳技术丢弃了大多数事件。如今,我们可以使用IntersectionObserver仅在元素进入或离开视口时接收事件。这样更有效。

一旦检测到元素进入或离开视口,就需要从position:相对于position:fixed切换。这需要浏览器重新计算许多元素的大小和位置(我们称为布局或重排),这很昂贵。而且重要的是要确保周围的元素不会四处移动并引起内容的跳跃。 Le Monde的实施不完善。

如果在元素进入或退出视口时阻止渲染(这很可能是当前动画与滚动协调的趋势),那么切换将在更晚的时候进行。

CSS现在具有位置:坚守这一行为。没有性能,响应速度或内容跳跃的问题:只要浏览器可以滚动,它将使项目保持在声明位置的正确位置。要选择其位置,请使用顶部,底部,左侧或右侧。

除Internet Explorer和较旧版本的Chrome或Firefox以外的所有浏览器均支持粘性。对于这些较旧的浏览器,这些元素位于适当位置:static,这是默认值,并且不会考虑top,bottom,left和right的值。如果您需要支持这些浏览器,请记住这一点。较旧版本的Safari需要-webkit-sticky前缀。

但是,存在一个局限性:无论元素是否被卡住,都无法更改其外观,例如使用伪类:stuck。这是CSS的一般限制。在这种情况下,我建议结合位置的好处:粘性以使元素与IntersectionObserver保持粘性以更改其外观(同时注意不要更改其尺寸,以防止内容跳跃)。

要在JavaScript中实现此功能,您需要定期执行将更改滚动位置的JavaScript。为了使动画顺利运行,在整个动画过程中,其他JavaScript都不应阻止渲染。

您还需要选择一个计时功能。为了看起来自然,每个操作系统可能需要不同以适应其约定。

多亏了scroll-behavior:在CSS中流畅且{behavior:' smooth'}作为JavaScript中的scroll,scrollTo和scrollIntoView的选项,您可以委派所有计时功能决策。这使您的行为更符合所使用的设备。

Safari尚不支持此功能(除非您启用隐藏的首选项),但是在大多数情况下,这并不重要:这是渐进增强的经典示例。

对于JavaScript版本和本机版本,都需要注意两个可访问性方面:尊重使动画和运动最小化的偏好,并确保焦点正确移动。

这使您可以创建幻灯片放映,捕捉到每个项目的水平列表或占据所有视口的部分。

对于所有类型的指针(鼠标或手指),当指针离开该区域时,处理得很好。一旦正确处理了这些事件,我们就会根据移动来移动元素。每次举动都可能触发昂贵的重排,从而产生残酷并破坏了用户的幻想。

对于占据所有视口或水平列表的部分,我们必须侦听所有滚动事件,将其取消,然后将其替换为所需的滚动移动。取得令人愉悦的行为是非常困难的:当我们遇到劫持本机滚动的网站时,我们所有人都在尖叫。

对于这两种用例,您都需要根据原始移动的速度和距离来决定何时继续进行下一个项目。如果您的选择与系统行为不符,则会使用户感到困惑。

CSS具有滚动捕捉来处理此问题。在滚动容器上,我们定义了scroll-snap-type来指示想要捕捉的方向,以及它们是强制性的还是仅在捕捉点附近才发生。然后,在容器的子级上,我们将定义scroll-snap-align来指示捕捉点。

下面的演示完全不需要JavaScript。它还使用滚动行为来暗示用户可以使用常规滚动机制。

勾选该复选框,您将激活一小部分IntersectionObserver以突出显示当前可见图像的缩略图。

所有现代浏览器都支持此行为。有另一种语法,但我建议不要使用它。这只会增加测试方案,您可以依靠正常降级。在不支持的浏览器中,它将是常规滚动。

由于此功能使用浏览器的滚动功能,因此与JavaScript解决方案相比,无论使用哪种指针类型,我们都能获得令人难以置信的流畅性。而且,如果您尝试改善“首次输入延迟”,则滚动不会算作输入,因此此交互将不是第一次输入。

为了使用JavaScript实现此目的,我们通常使用< img data-src ="…" data-srcset ="…" alt ="…">。当图像靠近视口时,JavaScript将更改属性以获取并显示它们。

该技术的主要缺点是,只有关联的JavaScript启动后,这些图像才可见。而且,发生的次数超出了您的想象。搜索引擎也很难找到您的图片,因为它们实际上并不存在,并且漫游器无法滚动。

选择何时触发下载非常微妙。您应该根据可用带宽将其触发距视口多远的距离?您应该考虑滚动速度吗?

去年,除Safari之外,所有浏览器都实现了属性loading =" lazy"。在< img>上元素。如果您的网站当前加载了所有图像,则可以添加此属性。您只需花费很少的精力,就可以为大多数访问提供一个更轻松的网站。

如果您已经使用了延迟加载解决方案,则在Safari支持此属性之前,您必须根据具体情况做出决定。为了简化代码,是否值得在Safari中加载所有图像?

目前,触发下载的规则特定于每个浏览器,可能并不理想。可以肯定的是,随着时间的推移,启发式方法会变得更好,而您不必更改任何代码!

我没有为此准备演示,因为它有点看不见,但是您可以阅读Google对此的解释。 如果您想在野外看到这些示例,那么我在上一个项目中使用了所有这些技术(不过该网站是法语的): 在产品详细信息页面上(延迟加载的图像,平滑滚动和图像库的滚动对齐) 并在购物篮上(如果购物篮中有产品,则订购按钮为粘滞式)。 我邀请您先后在狭窄和较宽的视口中进行测试。 我希望这个简短的概述能激发您更新维护的网站。 下次您要寻找某种性能的JavaScript库时,请记住以下几种技巧。 还要问问自己,是否还有其他我没有讲过的HTML或CSS技术(可能是带有