我在 Internet Explorer 8 上使用了一天的网络

已发表: 2022-03-10
快速总结↬ IE8 在十年前的今天发布。 克里斯·阿什顿(Chris Ashton)在现代网络上进行了尝试,并考虑了我们如何才能使我们的网站经久耐用。

这篇文章是我尝试在各种限制下使用网络的系列文章的一部分,代表给定的用户群体。 我希望提高真实人们面临的困难的形象,如果我们以一种同情他们需求的方式进行设计和开发,这些困难是可以避免的。

上次,我使用屏幕阅读器浏览了一天的网络。 这一次,我使用了 Internet Explorer 8,它于十年前的今天,即 2009 年 3 月 19 日发布。

世界上谁在使用 IE8?

在我们开始之前; 免责声明:我不会告诉你你需要开始支持 IE8。

完全有理由不支持 IE8。 微软三年多前正式停止支持 IE8、IE9 和 IE10,微软高管甚至告诉你停止使用 Internet Explorer 11。

但是,尽管我们开发人员希望它消失,但它只是。 惯于。 。 IE8 继续出现在浏览器统计数据中,尤其是在西方世界的泡沫之外。

浏览器统计数据必须谨慎对待,但目前对全球 IE8 使用量的估计约为桌面市场份额的 0.3% 至 0.4%。 估计的下限来自 w3counter:

IE8 使用情况随时间变化的图表
从 2010 年底近 30% 的峰值来看,W3Counter 现在认为 IE8 占全球使用量的 0.3%。 (大预览)

较高的估计来自 StatCounter(“我可以使用”使用表使用的相同数据源)。 它估计全球 IE8 桌面浏览器的比例在 0.37% 左右。

IE8 使用率与其他浏览器对比图
根据 StatCounter,IE8 的全球使用率为 0.37%。 (大预览)

我怀疑我们可能会在某些地理区域看到更高的 IE8 使用率,因此按大陆深入研究数据。

跳跃后更多! 继续往下看↓

按地区划分的 IE8 使用情况

这是每个大陆的 IE8 桌面比例(2018 年 2 月至 2019 年 1 月的数据):

1. 大洋洲0.09%
2. 欧洲0.25%
3. 南美洲0.30%
4. 北美0.35%
5. 非洲0.48%
6. 亚洲0.50%

亚洲人使用 IE8 的可能性是大洋洲人的五倍

我更仔细地查看了亚洲的统计数据,注意到每个国家/地区的 IE8 使用比例。 IE8 使用率排名前六位的国家非常明确,之后数字下降到与世界平均水平相当:

1. 伊朗3.99%
2. 中国1.99%
3. 北朝鲜1.38%
4. 土库曼斯坦1.31%
5. 阿富汗1.27%
6. 柬埔寨1.05%
7. 也门0.63%
8. 台湾0.62%
9. 巴基斯坦0.57%
10. 孟加拉国0.54%

这些数据总结在下面的地图中:

图表显示 IE8 在亚洲的细分
中东的伊朗、土库曼斯坦和阿富汗以及远东的中国、朝鲜和柬埔寨因其 IE8 的使用而脱颖而出。 (大预览)

令人难以置信的是,IE8 约占伊朗桌面用户的 4%——是大洋洲 IE8 用户比例的40 倍

接下来,我查看了非洲的国家统计数据,因为它的 IE8 总体使用率与亚洲大致相同。 有一个明显的赢家(厄立特里亚),其次是一些使用率高于或接近 1% 的国家:

1. 厄立特里亚3.24%
2. 博茨瓦纳1.37%
3. 苏丹和南苏丹1.33%
4. 尼日尔1.29%
5. 莫桑比克1.19%
6. 毛里塔尼亚1.18%
7. 几内亚1.12%
8. 刚果民主共和国1.07%
9. 赞比亚0.94%

这在下面的地图中进行了总结:

图表显示 IE8 在非洲的细分
厄立特里亚以其 IE8 的使用率 (3.24%) 脱颖而出。 许多其他国家的使用量也超过 1%。 (大预览)

亚洲的 IE8 使用率高于正常水平的国家在地理上大致分批在一起,而非洲似乎没有这种模式。 我能看到的唯一模式——除非是巧合——是一些世界上最大的 IE8 使用国家以审查互联网访问而闻名,因此可能不鼓励或允许更新到更安全的浏览器。

如果您的网站针对的是纯粹的西方受众,那么您不太可能关心 IE8。 但是,如果您有一个蓬勃发展的亚洲或非洲市场——特别是如果您关心中国、伊朗或厄立特里亚的用户——您可能会非常关心您网站的 IE8 体验。 是的——即使是在 2019 年!

谁还在使用 IE?

那么,这些人是谁? 他们真的走在我们中间吗?!

无论他们是谁,您都可以打赌他们使用旧浏览器并不是为了惹恼您。 没有人故意选择更糟糕的浏览体验。

由于以下原因,有人可能正在使用旧浏览器:

  • 缺乏认识
    他们根本不知道他们正在使用过时的技术。
  • 教育的缺失
    他们不知道向他们开放的升级选项和替代浏览器。
  • 缺乏规划
    忽略升级提示,因为它们很忙,但没有在安静时期升级的先见之明。
  • 厌恶改变
    上次他们升级软件时,他们不得不学习新的用户界面。 “如果它没有坏,就不要修理它。”
  • 厌恶风险
    他们最后一次升级时,他们的机器慢得像爬行,或者他们失去了他们最喜欢的功能。
  • 软件限制
    他们的操作系统太旧,无法升级,或者他们的管理员权限可能被锁定。
  • 硬件限制
    较新的浏览器通常对您的硬盘空间、内存和 CPU 要求更高。
  • 网络限制
    数据上限或连接速度较慢意味着他们不想下载 75MB 的软件。
  • 法律限制
    它们可能位于仅允许使用一种特定浏览器的公司机器上。

世界上还有人死守IE8,真的有这么大的惊喜吗?

我决定设身处地为其中一位匿名人士着想,并使用 IE8 浏览网页一天。 你可以在家一起玩! 从 Microsoft 网站下载“Windows 7 上的 IE8”虚拟机,然后在 VirtualBox 等虚拟机中运行它。

IE8 虚拟机:糟糕的开端

我启动了我的 IE8 虚拟机,期待地点击了 Internet Explorer 程序,这就是我所看到的:

IE8默认主页未加载截图
我看到的第一件事是 404。太好了。 (大预览)

嗯,好吧。 看起来 IE8 拉出的默认网页不再存在。 嗯,这个数字。 微软已经正式停止对 IE8 的支持,为什么还要确保 IE8 登陆页面仍然有效?

我决定切换到世界上使用最广泛的网站。

谷歌

Google.com 的屏幕截图
Google 主页在 IE8 中呈现良好。 (大预览)

这是一个简单的网站,因此很难出错 - 但公平地说,它看起来很棒! 我试着搜索一些东西:

不切实际的小丑的谷歌搜索结果截图
看过我之前文章的人可能会注意到这里反复出现的主题。 (大预览)

搜索工作正常,尽管布局看起来与我习惯的有点不同。 然后我想起来了——当我在互联网上使用了一天并且关闭了 JavaScript 时,我看到了相同的搜索结果布局。

作为参考,以下是启用 JavaScript 的现代浏览器中搜索结果的外观:

不切实际的小丑的谷歌浏览器搜索结果截图
更简洁的布局、额外的图像和元信息、Netflix/Twitter 集成。 (大预览)

因此,看起来 IE8 获得了无 JS 版本的 Google 搜索。 我认为这不一定是一个深思熟虑的设计决定——可能只是 JavaScript 出错了:

Google 搜索错误“对象不支持此属性或方法”的屏幕截图
该页面尝试运行 JavaScript,但未能成功。 (大预览)

尽管如此,最终结果对我来说还是不错的——我得到了我的搜索结果,这就是我想要的。

我点击观看了 YouTube 视频。

YouTube

有问题的 YouTube 视频页面的屏幕截图
时髦的标志,没有相关视频的图片,不出所料,没有视频。 (大预览)

这个页面有很多问题。 所有这些都与 IE 中的小怪癖有关。

例如,徽标被放大和裁剪。 这归结为 IE8 不支持 SVG,而我们实际看到的是 YouTube 提供的后备选项。 他们应用了background-image CSS 属性,以便在不支持 SVG 的情况下,您将尝试显示徽标。 只有他们似乎没有正确设置background-size ,所以放大了一点。

IE8 中 YouTube 徽标的屏幕截图和对其进行检查的开发者工具
YouTube 在 logo span上设置了一个background-img ,它会引入一个 sprite。 (大预览)

作为参考,这是 Chrome 中的同一页面(请参阅 Chrome 如何呈现 SVG):

Chrome DevTools 检查 YouTube 徽标的屏幕截图
(大预览)

那自动播放切换呢? 它呈现为一个看起来很奇怪的复选框:

自动播放切换的屏幕截图
看起来 IE8 默认为引擎盖下的复选框。 (大预览)

这似乎归结为使用了自定义元素(纸张切换按钮,这是一个 Material Design 元素),IE 不理解:

自动播放切换标记的屏幕截图
paper-toggle-button是一个自定义元素。 (屏幕截图来自 Chrome DevTools,以及自动播放切换应该如何呈现。)(大预览)

我并不惊讶这没有正确呈现; IE8 甚至无法处理我们这些天使用的基本语义标记。 尝试使用<aside><main> ,它基本上会将它们呈现为 div,但忽略您应用于它们的任何样式。

要启用 HTML5 标记,您必须明确告诉浏览器这些元素存在。 然后可以将它们设置为正常样式:

 <!--[if lt IE 9]> <script> document.createElement('header'); document.createElement('nav'); document.createElement('section'); document.createElement('article'); document.createElement('aside'); document.createElement('footer'); </script> <![endif]-->

顺便说一句,它包含在 IE 条件中。 <!--[if lt IE 9]>是大多数浏览器的 HTML 注释——因此会被跳过——但在 IE 中它是一个条件,它只传递“如果小于 IE 9”,它会在其中执行/呈现 DOM 节点在其中。

所以,视频页面是失败的。 直接访问 YouTube.com 也好不到哪里去:

IE8 YouTube 主页截图:“不再支持您的网络浏览器”
至少这次我有一个可见的错误消息! (大预览)

没有被吓倒,我忽略了警告并尝试在 YouTube 的搜索栏中搜索视频。

Google 的屏幕截图“抱歉,您的计算机可能正在发送自动查询。我们无法处理您的请求”
电脑说不行。 (大预览)

IE8 流量显然很可疑,以至于 YouTube 不相信我是真正的用户,因此决定不处理我的搜索请求!

注册 Gmail

如果我要花一天时间在 IE8 上,我将需要一个电子邮件地址。 所以我开始尝试建立一个新的。

首先,我尝试了 Gmail。

Gmail 主页屏幕截图
文字不会通过颜色对比标准! (大预览)

这里的图像和文字有点不对劲。 我认为这归结于 IE8 不支持媒体查询这一事实——所以它试图在桌面上向我展示移动图像。

解决这个问题的一种方法是使用 Sass 生成两个样式表; 一种用于现代浏览器,一种用于旧版 IE。 您可以通过使用 mixin 进行媒体查询来获得 IE 友好、移动优先的 CSS(请参阅 Jake Archibald 的教程)。 mixin 会“扁平化”你的旧版 IE CSS 以将 IE 视为总是一个特定的预定义宽度(例如 65em),只给出与该宽度相关的 CSS。 在这种情况下,我会看到我假设的屏幕尺寸的正确background-image ,并获得更好的体验。

无论如何,它并没有阻止我点击“创建帐户”。 它在 IE8 和现代浏览器中的外观有一些差异:

比较 Chrome 和 IE8 上的 Gmail 注册屏幕的屏幕截图
IE8 缺少紧凑的布局,并且文本重叠,但其他方面仍然有效。 (大预览)

虽然乍一看很有希望,但该表格填写起来却很麻烦。当您开始填写字段时,“标签”不会妨碍您,因此您的输入文本会被混淆:

错误标签的屏幕截图
标签与我正在写的文字重叠。 (大预览)

这个标签的标记实际上是一个<div> ,一些聪明的 JS 在输入焦点时将文本移开。 JS 在 IE8 上没有成功,所以文本固执地保持在原地。

gmail 表单标记的屏幕截图
“标签”是一个div ,它使用 CSS 覆盖在表单输入上。 (大预览)

填写完所有详细信息后,我点击“下一步”,然后等待。 没啥事儿。

然后我注意到我的 IE 窗口左下方的黄色小警告符号。 我点击它,看到它在抱怨 JS 错误:

Gmail 错误的屏幕截图
我走得很远,但是下一步按钮不起作用。 (大预览)

我放弃了 Gmail,转而使用 MSN。

注册 Hotmail

我开始担心电子邮件可能会成为使用了 10 年的浏览器的禁区。 但是当我访问 Hotmail 时,注册表单看起来还不错——到目前为止还不错:

MSN 注册页面截图
注册页面看起来不错。 猜想我们会更幸运地使用 Microsoft 产品! (大预览)

然后我注意到一个验证码。 我想,“我不可能熬过这个……”

注册状态验证码截图
我可以看到并完成验证码。 (大预览)

令我惊讶的是,验证码有效!

表单上唯一奇怪的是标签位置有些错误,但注册在其他方面是无缝的:

名字标签、姓氏标签的屏幕截图,然后是两个空输入字段,没有清晰的视觉层次
标签位置有点偏离,但我猜我的姓加姓就可以了。 (大预览)

你觉得那个截图还可以吗? 你能发现故意的错误吗?

最左边的输入应该是我名字,而不是我的姓氏。 当我稍后返回并检查此页面时,我单击“名字”标签并将焦点应用于最左侧的输入,这就是我可以检查我是否首先填写了正确的框。 这显示了可访问标记的重要性——即使没有 CSS 和视觉关联,我也可以准确地确定哪个输入框应用于哪个标签(尽管是第二次!)。

无论如何,我能够完成注册过程并被重定向到 MSN 主页,这非常棒。

看起来不错的 MSN 主页截图
如果有任何网站可以在 IE8 中运行,那么它将是 Microsoft 主页。 (大预览)

我什至可以阅读文章并忘记我使用的是 IE8:

MSN文章截图
文章工作正常。 没有狡猾的侧边栏或无聊的图像。 (大预览)

注册了我的电子邮件后,我已经准备好去看看互联网的其余部分了!

Facebook

我访问了 Facebook 网站并立即被重定向到移动网站:

脸书手机截图
“您正在使用 Facebook 不支持的浏览器,因此我们已将您重定向到更简单的版本,以便为您提供最佳体验。” (大预览)

这是一个聪明的后备策略,因为 Facebook 需要在低端移动设备上支持大量的全球受众,所以无论如何都需要提供 Facebook 的基本版本。 为什么不向旧的桌面浏览器提供相同的体验基准呢?

我尝试注册并能够创建一个帐户。 伟大的! 但是当我登录该帐户时,我受到了怀疑——就像我在 YouTube 上搜索东西时一样——并且面临着验证码。

只是这一次,可没那么容易。

验证码消息的屏幕截图,但验证码图像无法加载
“请输入下面的代码”。 是的,对。 (大预览)

我尝试了几次请求新代码并刷新页面,但验证码图像从未加载,因此我实际上被锁定在我的帐户之外。

那好吧。 让我们尝试更多的社交媒体。

推特

我访问了 Twitter 网站并获得了完全相同的移动重定向体验。

Twitter 移动视图的屏幕截图
Twitter 将 IE8 视为移动浏览器,就像 Facebook 一样。 (大预览)

但是这次我什至无法注册一个帐户:

Twitter注册屏幕截图
您的浏览器已不再受支持。 要注册,请更新它。 您仍然可以登录现有的用户帐户。 (大预览)

奇怪的是,Twitter 很乐意让你登录,但不是让你首先注册。 我不知道为什么——也许它的注册页面上有类似的 CAPTCHA 场景,这在旧版浏览器上不起作用。 无论哪种方式,我都无法创建新帐户。

使用我现有的 Twitter 帐户登录时,我感到很尴尬。 称我为偏执狂,但像 2013 年的 CFR Watering Hole Attack 之类的漏洞——在 IE8 中访问特定 URL 的行为就会将恶意软件安装到你的机器上——让我担心我可能会危及我的帐户。

但是,为了教育,我坚持了下来(用一个临时的新密码):

Twitter 提要的屏幕截图
成功登录。我可以看到推文了! (大预览)

我也可以发推文,尽管使用的是非常基本的<textarea>

我写推文的截图,感叹 IE8 推特视图中缺少表情符号
只有当他们离开时,你才会想念他们。 (大预览)

总之,Twitter 在 IE8 中基本上没问题——只要你已经有一个帐户!

我已经完成了这一天的社交媒体。 我们去看看一些新闻。

英国广播公司的新闻

弹出“安全警告”浏览器的 BBC 主页截图
BBC 似乎正在加载 HTTPS 和 HTTP 资产的混合。 (大预览)

新闻主页看起来非常基本且笨拙,但基本上可以正常工作——尽管有混合内容安全警告。

看看标志。 正如我们已经在 YouTube 上看到的,IE8 不支持 SVG,所以我们需要一个 PNG 后备。

BBC 使用<image>后备技术在 IE 上渲染 PNG:

打开 devtools 的 IE8 BBC 新闻徽标的屏幕截图
IE8 在 SVG 中找到 base64 图像并进行渲染。 (大预览)

…并在 SVG 可用时忽略 PNG:

已打开 devtools 的 Chrome BBC 新闻徽标的屏幕截图
image部分被忽略, svg渲染得很好。 (大预览)

这种技术利用了旧浏览器过去同时遵守<image><img>标签的事实,因此将忽略未知的<svg>标签并呈现回退,而现代浏览器在 SVG 中忽略呈现<image> 。 Chris Coyier 更详细地解释了这项技术。

我尝试查看一篇文章:

BBC 文章的屏幕截图,显示正常,但顶部有警告消息
本网站针对现代浏览器进行了优化,并不完全支持您的浏览器。 (大预览)

它是可读的。 我可以看到标题、导航、特色图片。 但是其余的文章图片都不见了:

BBC 文章的屏幕截图,其中引用了未显示的图像
(大预览)

这是意料之中的,并且是由于 BBC 延迟加载图像。 IE8 不是“受支持的浏览器”意味着它没有获得启用延迟加载的 JavaScript,因此图像根本不会加载。

出于兴趣,我想看看如果我尝试访问 BBC iPlayer 会发生什么:

BBC iPlayer 的屏幕截图 - 只是黑屏
...不是很多。 (大预览)

这让我想知道另一个流媒体服务。

网飞

当我在 IE8 中加载 Netflix 时,我有一半期待一个空白页面。 当我真正看到一个不错的目标网页时,我感到很惊喜:

Netflix 主页截图
“免费加入一个月”号召性用语,通过流行标题的合成图像。 (大预览)

我将此与现代 Chrome 版本进行了比较:

Netflix 主页截图
“免费观看 30 天”号召性用语,通过热门标题的合成图像。 (大预览)

号召性用语(按钮文本)略有不同——可能取决于多变量测试,而不是我使用的浏览器。

渲染的不同之处在于集中的文本和半透明的黑色覆盖。

缺少集中文本是因为 Netflix 使用 Flexbox 来对齐项目:

Netflix Flexbox 对齐项目
Netflix 使用 Flexbox 属性justify-content: center来对齐其文本。 (大预览)

此类上的text-align: center可能会修复 IE8(实际上是所有旧浏览器)的居中问题。 为了获得最大的浏览器支持,您可以使用旧的“安全”CSS 遵循 CSS 后备方法,然后为支持它的浏览器使用更现代的 CSS 来加强布局。

缺少背景是由于使用了rgba() ,IE8 及更低版本不支持。

rgba(0,0,0,.5) 的背景对旧版浏览器毫无意义
rgba(0,0,0,.5)背景对旧版浏览器毫无意义。 (大预览)

传统上提供这样的 CSS 回退是很好的,它为旧浏览器显示黑色背景,但为现代浏览器显示半透明背景:

 rgb(0, 0, 0); /* IE8 fallback */ rgba(0, 0, 0, 0.8);

这是一个非常特定于 IE 的修复程序,但是,基本上所有其他浏览器都支持rgba 。 此外,在这种情况下,你会完全失去花哨的 Netflix 磁贴,所以最好根本没有背景过滤器! 确保跨浏览器支持的可靠方法是将过滤器烘焙到背景图像本身中。 简单但有效。

无论如何,到目前为止,一切都很好——IE8 实际上很好地呈现了主页! 我今天真的要在 IE8 上观看《绝命毒师》吗?

当我查看登录页面时,我已经初步的乐观情绪立即被击落:

比较 Netflix 在 Chrome 和 IE8 上的登录页面的屏幕截图。 IE版颜色满天飞,文字难看
你能猜出哪一边是IE8,哪一边是Chrome吗? (大预览)

尽管如此,我还是能够登录,并看到一个精简的仪表板(没有花哨的自动扩展拖车):

已登录用户的 Netflix 仪表板屏幕截图
每个程序都有一个简单的悬停状态,带有播放图标和标题。 (大预览)

我带着模糊的期待点击了一个程序,当然,只看到一个黑屏。

亚马逊

好的,社交媒体和视频都出来了。 剩下的就是去购物了。

我查看了亚马逊,被震撼了——这与你在现代浏览器中获得的体验几乎没有区别:

亚马逊主页截图
亚马逊主页在 IE8 上看起来几乎和在任何其他浏览器上一样好。 (大预览)

我以前被一个好的主页吸引。 所以让我们点击一​​个产品页面,看看这是否只是侥幸。

Ferrero Rocher 巧克力的亚马逊产品页面截图
产品页面看起来也很棒(让我很饿)。 (大预览)

不! 产品页面看起来也不错!

亚马逊并不是唯一一个让我在向后兼容性方面感到惊讶的网站。 维基百科和 Gov.UK 政府网站看起来都很棒。 在 IE8 中拥有一个看起来不像完全车祸的网站并不容易。 我的大部分经历显然都没有那么完美……!

sky.com在IE8上的屏幕截图,布局到处都是,放在图像上时文字难以阅读
在 IE8 上阅读或浏览 sky.com 很困难。 (大预览)

但是,过时的警告通知或时髦的布局并不是我今天看到的最糟糕的事情。

完全破碎的网站

有些网站太坏了,我什至无法连接到它们!

截图:Internet Explorer 无法显示网页
访问 GitHub 时没有骰子。 (大预览)

我想知道这是否可能是临时的 VM 网络问题,但每次我刷新页面时都会发生这种情况,即使当天晚些时候回到同一个站点也是如此。

这一天发生在几个不同的站点上,我最终得出结论,这从未影响 HTTP 上的站点——在 HTTPS 上(但不是所有HTTPS 站点)。 那么,问题出在哪里?

使用 Wireshark 分析网络流量,我尝试再次连接到 GitHub。 我们可以看到由于致命错误“描述:协议版本”而无法建立连接。

Wireshark 输出截图
TLSv1 警报(级别:致命,描述:协议版本)(大预览)

查看 IE8 中的默认设置,仅启用了 TLS 1.0——但 GitHub 在 2018 年 2 月放弃了对 TLSv1 和 TLSv1.1 的支持。

设置面板截图
IE8 的默认高级设置:选中 TLS 1.0,未选中 TLS 1.1 和 1.2。 (大预览)

我检查了 TLS 1.1 和 TLS 1.2 的复选框,重新加载了页面,然后——瞧! — 我可以查看 GitHub!

GitHub 主页截图,上面有“不再支持 Internet Explorer”的消息
它看起来不漂亮,但至少我现在可以看到它! (大预览)

非常感谢我非常有才华的朋友 Aidan Fewster 帮助我调试了这个问题。

我完全支持向后兼容,但这提出了一个有趣的困境。 根据 PCI 安全标准委员会,TLS 1.0 不安全,不应再使用。 但是通过强制使用 TLS 1.1 或更高版本,一些用户总是会被锁定(并且并非所有用户都可能精通技术以在其高级设置中启用 TLS 1.2)。

通过允许旧的、不安全的标准并让用户继续连接到我们的网站,我们并没有帮助他们——我们正在伤害他们,因为我们没有给他们一个转向更安全技术的理由。 那么在支持旧版浏览器方面应该走多远呢?

如何开始支持旧版浏览器?

当一些人想到“支持旧浏览器”时,他们可能会想到那些针对 IE 的专有旧 hack,就像当时 BBC 不得不做一些令人难以置信的粗糙的事情来支持 IE7 中的 iframed 内容。

或者他们可能正在考虑让事情在 Internet Explorer“怪癖模式”中运行; 一种特定于 IE 的操作模式,它使事物与标准非常不同。

但“支持旧浏览器”与“为 IE 破解”有很大不同。 我不提倡后者,但我们应该务实地尝试做前者。 作为一名 Web 开发人员,我试图遵循的口头禅是:

“为大多数人优化,为少数人努力,从不牺牲安全。”

我现在要离开 IE8 的世界,谈谈对旧版浏览器支持的一般、可持续的解决方案。

支持旧版浏览器有两种广泛的策略,均以 P 开头:

  1. 填充
    通过填写缺少的浏览器功能,争取所有人的功能平等。
  2. 渐进增强
    从核心体验开始,然后使用特征检测对功能进行分层。

这些策略并不相互排斥。 它们可以串联使用。 在这两种方法中都有许多实现决策,每个决策都有自己的细微差别,我将在下面更详细地介绍。

填充

对于某些网站或网页,JavaScript 对功能非常重要,您只想将有效的 JavaScript 提供给尽可能多的浏览器。

有很多方法可以做到这一点,但首先是历史课。

ECMAScript 简史

ECMAScript 是一个标准,而 JavaScript 是该标准的实现。 这意味着 ES5 是“ECMAScript 版本 5”,而 ES6 是“ECMAScript 版本 6”。 令人困惑的是,ES2015 与 ES6 相同。

ES6 是该版本发布前的通俗名称,但 ES2015 是官方名称,后续的 ECMAScript 版本都与发布年份相关联。

注意Brandon Morelli 在一篇很棒的博客文章中对这一切进行了有益的解释,该文章解释了 JavaScript 版本的完整历史。

在撰写本文时,最新标准是 ES2018 (ES9)。 大多数现代浏览器至少支持 ES2015。 几乎所有浏览器都支持 ES5。

从技术上讲,IE8 不是 ES5。 它甚至不是 ES4(它不存在——项目被放弃了)。 IE8 使用 Microsoft 实现的 ECMAScript 3,称为 JScript。 IE8 确实有一些 ES5 支持,但在 ES5 标准发布前几个月发布,因此支持不匹配。

转译与 Polyfilling

你可以编写 ES5 JavaScript,它几乎可以在所有古老的浏览器中运行:

 var foo = function () { return 'this is ES5!'; };

你也可以继续这样编写所有的 JavaScript —— 以实现永远的向后兼容性。 但是你会错过在不断发展的 JavaScript 版本中可用的新特性和语法糖,允许你编写如下内容:

 const foo = () => { return 'this is ES6!'; };

尝试在较旧的浏览器中运行该 JavaScript,它会出错。 我们需要将代码转换成浏览器能够理解的早期版本的 JavaScript(即使用自动化工具将我们的ES6代码转换成 ES5)。

现在假设我们的代码使用标准的 ES5 方法,例如Array.indexOf 。 大多数浏览器都有本机实现并且可以正常工作,但 IE8 会中断。 还记得 IE8 是在 ES5 标准发布前几个月发布的,所以支持不匹配吗? 一个例子是indexOf函数,它是为String实现的,但不是为Array实现的。

如果我们尝试在 IE8 中运行Array.indexOf方法,它将失败。 但是如果我们已经在用 ES5 编写代码,我们还能做什么呢?

我们可以polyfill缺失方法的行为。 开发人员传统上通过复制和粘贴代码或通过引入外部第三方 polyfill 库来填充他们需要的每个功能。 许多 JavaScript 特性在它们各自的 Mozilla MDN 页面上都有很好的 polyfill 实现,但值得指出的是,有多种方法可以填充相同的特性。

例如,为了确保您可以在 IE8 中使用Array.indexOf方法,您可以像这样复制并粘贴一个 polyfill:

 if (!Array.prototype.indexOf) { Array.prototype.indexOf = (function (Object, max, min) { // big chunk of code that replicates the behaviour in JavaScript goes here! // for full implementation, visit: // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexof#Polyfill })(Object, Math.max, Math.min); }

只要您在引入任何自己的 JS 之前调用 polyfill,并且不使用除Array.indexOf之外的任何 ES5 JavaScript 功能,您的页面就可以在 IE8 中运行。

Polyfills 可用于填补各种缺失的功能。 例如,有用于启用 CSS3 选择器的 polyfill,例如:last-child (IE8 不支持)或placeholder属性(IE9 不支持)。

Polyfill 的大小和有效性各不相同,有时还依赖于外部库,例如 jQuery。

您可能还听说过“垫片”而不是“polyfills”。 不要太拘泥于命名——人们可以互换使用这两个术语。 但从技术上讲,shim 是拦截 API 调用并提供抽象层的代码。 polyfill 是浏览器中的一种填充程序。 它专门使用 JavaScript 来改进旧浏览器中的新 HTML/CSS/JS 功能。

“手动导入 polyfills”策略总结:

  • 完全控制 polyfills 的选择;
  • 适用于基础网站;
  • ️ 没有额外的工具,你不得不用原生 ES5 JavaScript 编写;
  • ️ 难以对所有的 polyfill 进行微观管理;
  • ️ 开箱即用,您的所有用户都将获得 polyfill,无论他们是否需要。

Babel Polyfill

我已经讨论过将 ES6 代码转换为 ES5。 您可以使用转译器来执行此操作,其中最流行的是 Babel。

Babel 可以通过项目根目录中的.babelrc文件进行配置。 在其中,您指向各种 Babel 插件和预设。 您需要的每个语法转换和浏览器 polyfill 通常都有一个。

对这些进行微观管理并使其与浏览器支持列表保持同步可能会很痛苦,因此现在的标准设置是将微观管理委托给 @babel/preset-env 模块。 通过这个设置,你只需给 Babel 一个你想要支持的浏览器版本列表,它就会为你完成艰苦的工作:

 { "presets": [ [ "@babel/preset-env", { "useBuiltIns": "usage", "targets": { "chrome": "58", "ie": "11" } } ] ] }

@babel/preset-envuseBuiltIns配置选项是魔术发生的地方,结合应用程序入口点中的import "@babel/polyfill" (另一个模块)。

  • 省略时, useBuiltIns什么也不做。 @babel/polyfill的全部内容都包含在您的应用程序中,这非常重。
  • 当设置为"entry"时,它将@babel/polyfill导入转换为多个更小的导入,导入最小的 polyfill 来填充您在.babelrc中列出的目标浏览器(在本例中,Chrome 58 和 IE 11) .
  • 设置为"usage"通过进行代码分析并仅导入实际正在使用的功能的 polyfill 来更进一步。 它被归类为“实验性”,但在“polyfill 太多”而不是“太少”方面犯了错误。 无论如何,我看不出它怎么可能创建比"entry"false更大的捆绑包,所以这是一个不错的选择(也是我们在 BBC 的方式)。

使用 Babel,您可以在部署到生产环境之前编译和填充您的 JavaScript,并在特定的最低浏览器基线中提供支持。 注意,另一个流行的工具是 TypeScript,它有自己的转译器,可以转译为 ES3,理论上支持 IE8 开箱即用。

使用@babel/preset-env进行 polyfill 的总结:

  • 将 polyfill 的微观管理委托给工具;
  • 自动化工具有助于防止包含您不需要的 polyfill;
  • 扩展到更大、更复杂的站点;
  • ️ 开箱即用,您的所有用户都将获得 polyfill,无论他们是否需要它们;
  • ️ 很难准确地看到被拉入应用程序包的内容。

使用 Webpack 和动态导入延迟加载 Polyfill

可以利用新的import()提议在初始化应用程序之前进行功能检测和动态下载 polyfill。 在实践中看起来像这样:

 import app from './app.js'; const polyfills = []; if (!window.fetch) { polyfills.push(import(/* webpackChunkName: "polyfill-fetch" */ 'whatwg-fetch')); } Promise.all(polyfills) .then(app) .catch((error) => { console.error('Failed fetching polyfills', error); });

这个示例代码无耻地复制自非常好的文章“使用 Webpack 和动态导入延迟加载 Polyfills”,该文章更详细地研究了该技术。

概括:

  • 不会用不必要的 polyfill 使现代浏览器膨胀;
  • ️ 需要手动管理每个 polyfill。

polyfill.io

polyfill.io 是由金融时报构建的 polyfill 即服务。 它通过您的页面向 polyfill.io 发出单个脚本请求来工作,可选择列出您需要 polyfill 的特定功能。 然后他们的服务器分析用户代理字符串并相应地填充脚本。 这使您不必手动提供自己的 polyfill 解决方案。

这是 polyfill.io 为从 IE8 发出的请求返回的 JavaScript:

IE8 的 polyfill.io 服务响应的屏幕截图
在 IE8 中填充标准 ES5 方法的大量 JS 代码。 (大预览)

这是相同的 polyfill.io 请求,但请求来自现代 Chrome:

来自 Chrome 的 polyfill.io 服务响应的屏幕截图 - 不需要 polyfill
没有 JS 代码,只有 JS 注释。 (大预览)

您的站点所需要的只是一个脚本调用。

概括:

  • 易于包含到您的网络应用程序中;
  • 将 polyfill 知识的责任委托给第三方;
  • ️ 另一方面,您现在依赖第三方服务;
  • ️ 进行阻塞<script>调用,即使对于不需要任何 polyfill 的现代浏览器也是如此。

渐进增强

Polyfilling 是一种非常有用的支持旧版浏览器的技术,但可能会导致网页膨胀并且范围有限。

另一方面,渐进增强技术是保证所有浏览器的基本体验的好方法,同时在现代浏览器上为用户保留全部功能。 它应该在大多数网站上都可以实现。

原则是这样的:从 HTML 的基线(和样式,可选)开始,并使用 JavaScript 功能“逐步增强”页面。 这样做的好处是,如果浏览器是旧版浏览器,或者 JavaScript 在交付过程中的任何时候出现故障,您的网站应该仍然可以正常运行。

术语“渐进式增强”通常与“不显眼的 JavaScript”互换使用。 它们的意思本质上是一样的,但后者更进一步,因为你不应该在你的 HTML 中乱扔很多只被 JavaScript 使用的属性、ID 和类。

切芥末

BBC 的“切芥末”(CTM) 技术是一种经过验证的渐进增强实施。 原则是编写可靠的 HTML 基线体验,并在下载任何增强的 JavaScript 之前,检查最低级别的支持。 原始实现检查是否存在标准 HTML5 功能:

 if ('querySelector' in document && 'localStorage' in window && 'addEventListener' in window) { // Enhance for HTML5 browsers }

随着新功能的出现和旧版浏览器变得越来越过时,我们的芥末底线将会改变。 例如,新的 JavaScript 语法(如 ES6 箭头函数)意味着这种内联 CTM 检查甚至无法在旧版浏览器中解析——甚至无法安全地执行和 CTM 检查失败——因此可能会产生意想不到的副作用,例如破坏其他第三方 JavaScript (例如谷歌分析)。

为了避免尝试解析未编译的现代 JS,我们可以将这种“现代方式”应用于 CTM 技术,取自 @snugug 的博客,其中我们利用了旧浏览器不理解type="module"的事实type="module"声明并将安全地跳过它。 相反,现代浏览器将忽略<script nomodule>声明。

 <script type="module" src="./mustard.js"></script> <script nomodule src="./no-mustard.js"></script> <!-- Can be done inline too --> <script type="module"> import mustard from './mustard.js'; </script> <script nomodule type="text/javascript"> console.log('No Mustard!'); </script>

如果您乐于将 ES6 浏览器作为新的最低功能基线(在撰写本文时大约 92% 的全球浏览器),这种方法是一种很好的方法。

然而,正如 JavaScript 的世界在不断发展一样,CSS 的世界也在不断发展。 现在我们有了 Grid、Flexbox、CSS 变量等(每个都有不同的回退效果),不知道旧浏览器可能有哪些 CSS 支持组合可能导致“现代”和“遗留”的混杂样式,其结果看起来很糟糕。 因此,越来越多的网站选择 CTM 他们的样式,所以现在 HTML 是核心基线,CSS 和 JS 都被视为增强。

如果您使用 JavaScript 的存在以任何方式应用 CSS,我们目前看到的基于 JavaScript 的 CTM 技术有几个缺点:

  1. 内联 JavaScript 被阻塞。 在你获得任何样式之前,浏览器必须下载、解析和执行你的 JavaScript。 因此,用户可能会看到一闪而过的无样式文本。
  2. 一些用户可能拥有现代浏览器,但选择禁用 JavaScript。 基于 JavaScript 的 CTM 会阻止他们获得样式化的网站,即使他们完全有能力获得它。

“终极”方法是使用 CSS 媒体查询作为您的切入点试金石。 这种“CSSCTM”技术在 Springer Nature 等网站上得到了积极使用。

 <head> <!-- CSS-based cuts-the-mustard --> <!-- IMPORTANT: the JS depends on having this rule somewhere in the CSS: `body { clear: both }` --> <link rel="stylesheet" href="mq-test.css" media="only screen and (min-resolution: 0.1dpcm), only screen and (-webkit-min-device-pixel-ratio:0) and (min-color-index:0)"> </head> <body> <!-- content here... --> <script> (function () { // wrap in an IIFE to prevent global scope pollution function isSupported () { var val = ''; if (window.getComputedStyle) { val = window.getComputedStyle(document.body, null).getPropertyValue('clear'); } else if (document.body.currentStyle) { val = document.body.currentStyle.clear; } if (val === 'both') { // references the `body { clear: both; }` in the CSS return true; } return false; } if (isSupported()) { // Load or run JavaScript for supported browsers here. } })(); </script> </body>

这种方法很脆弱——不小心覆盖了你的body选择器上的clear属性会“破坏”你的网站——但它确实提供了最好的性能。 这个特定的实现使用了至少在 IE 9、iOS 7 和 Android 4.4 中才支持的媒体查询,这是一个非常明智的现代基线。

“切芥末”,以各种形式,实现了两个主要原则:

  1. 广泛的用户支持;
  2. 有效地应用开发工作。

站点根本不可能容纳每个浏览器/操作系统/网络连接/用户配置组合。 根据Yahoo!的分级浏览器支持模型,诸如减少芥末酱之类的技术有助于将浏览器合理化为 C 级和 A 级浏览器! .

Cuts-The-Mustard:一种反模式?

有一种观点认为,应用“核心”与“高级”的全局二元决策对于我们的用户来说并不是最好的体验。 它为原本令人生畏的技术问题提供了理智,但是如果浏览器支持全球 CTM 测试中 90% 的功能,而这个特定页面甚至没有利用它失败的 10% 功能怎么办? 在这种情况下,用户将获得核心体验,因为 CTM 检查将失败。 但我们本可以给他们完整的经验。

给定页面确实使用了浏览器不支持的功能的情况呢? 好吧,在向组件化迈进的过程中,我们可以有一个特定于功能的回退(或错误边界),而不是页面级的回退。

我们每天在 Web 开发中都这样做。 考虑引入网络字体; 不同的浏览器有不同级别的字体支持。 我们做什么? 我们提供了一些字体文件变体,让浏览器决定下载哪个:

 @font-face { font-family: FontName; src: url('path/filename.eot'); src: url('path/filename.eot?#iefix') format('embedded-opentype'), url('path/filename.woff2') format('woff2'), url('path/filename.woff') format('woff'), url('path/filename.ttf') format('truetype'); }

我们对 HTML5 视频有类似的回退。 现代浏览器将选择他们想要使用的视频格式,而不了解<video>元素是什么的旧版浏览器将简单地呈现后备文本:

 <video width="400" controls> <source src="mov_bbb.mp4" type="video/mp4"> <source src="mov_bbb.ogg" type="video/ogg"> Your browser does not support HTML5 video. </video>

我们之前看到的 BBC 用于 SVG 的 PNG 后备的嵌套方法是<picture>响应式图像元素的基础。 现代浏览器将根据提供的media属性呈现最合适的图像,而不了解<picture>元素是什么的旧版浏览器将呈现<img>后备。

 <picture> <source media="(min-width: 650px)"> <source media="(min-width: 465px)"> <img src="img_orange_flowers.jpg" alt="Flowers"> </picture>

HTML 规范多年来经过精心发展,为所有浏览器提供基本的回退机制,同时允许理解它们的现代浏览器的功能和优化。

我们可以将类似的原则应用于我们的 JavaScript 代码。 想象一个这样的 Feature,其中foo方法包含一些复杂的 JS:

 class Feature { browserSupported() { return ('querySelector' in document); // internal cuts-the-mustard goes here } foo() { // etc } } export default new Feature();

在调用foo之前,我们通过调用它的browserSupported方法来检查该浏览器是否支持该功能。 如果它不受支持,我们甚至不会尝试调用否则会导致我们的页面出错的代码。

 import Feature from './feature'; if (Feature.browserSupported()) { Feature.foo(); }

这种技术意味着我们可以避免引入 polyfill,只使用每个浏览器原生支持的内容,如果不支持,可以优雅地降低单个功能。

请注意,在上面的示例中,我假设代码被转换为 ES5,以便所有浏览器都能理解语法,但我不假设任何代码都是polyfill 。 如果我们想避免转译代码,我们可以应用相同的原则,但使用type="module"采取削减-the-mustard,但需要注意的是它已经具有最低 ES6 浏览器要求,因此只有可能会在几年内开始成为一个很好的解决方案:

 <script type="module"> import Feature from './feature.js'; if (Feature.browserSupported()) { Feature.foo(); } </script>

我们已经介绍了 HTML,也介绍了 JavaScript。 我们也可以在 CSS 中应用本地化后备; CSS 中有一个@supports关键字,它允许您根据是否支持 CSS 功能有条件地应用 CSS。 然而,具有讽刺意味的是,它并未得到普遍支持。 它只需要仔细应用; 有一篇很棒的 Mozilla 博客文章介绍了如何在 CSS 中使用功能查询。

在一个理想的世界里,我们不应该需要一个全球性的简单检查。 相反,每个单独的 HTML、JS 或 CSS 功能都应该是自包含的,并且有自己的错误边界。 在 Web 组件、影子 DOM 和自定义元素的世界中,我希望我们会看到更多地转向这种方法。 但这确实使预测和测试整个站点变得更加困难,并且如果一个组件的样式影响另一个组件的布局,则可能会产生意想不到的副作用。

两种主要的向后兼容性策略

作为一种策略的 polyfilling总结:

  • 可以为大多数用户提供客户端 JS 功能。
  • 将向后兼容性问题委托给 polyfill 时,可以更容易地编写代码。
  • ️ 根据实施情况,可能不利于不需要 polyfill 的用户的性能。
  • ️ 根据应用程序的复杂性和浏览器的年龄,可能需要大量的 polyfill,因此运行效果很差。 我们冒着向最不准备接受它的浏览器发送数兆字节的 polyfill 的风险。

渐进式增强策略总结:

  • 传统的 CTM 使您的代码分段和手动测试变得容易。
  • 保证所有用户的体验基线。
  • ️ 可能不必要地向可以处理高级体验的用户提供核心体验。
  • ️ 不太适合需要客户端 JS 功能的网站。
  • ️ 有时很难在稳健的渐进增强策略和高性能的首次渲染之间取得平衡。 存在过度优先考虑“核心”体验的风险,这会损害 90% 获得“完整”体验的用户(例如,为 noJS 提供小图像,然后在延迟加载时用高分辨率图像替换意味着我们'已经在甚至从未查看过的资产上浪费了很多下载容量)。

结论

IE8 曾经是最前沿的浏览器。 (不,说真的。)今天的 Chrome 和 Firefox 也是如此。

如果今天的网站在 IE8 中完全无法使用,那么十年后的网站可能在今天的现代浏览器中也无法使用——尽管它们是基于 HTML、CSS 和 JavaScript 的开放技术构建的。

停下来想一想。 是不是有点吓人? (也就是说,如果你不能在十年后放弃浏览器并且在构建它的公司已经弃用它之后,你什么时候可以?)

IE8 是今天的替罪羊。 明天是 IE9,明年是 Safari,一年后可能是 Chrome。 您可以将 IE8 换成“首选的旧浏览器”。 关键是,开发人员构建的浏览器与人们使用的浏览器之间总会存在一些分歧。 我们应该停止对此嗤之以鼻,并开始投资于强大、包容的工程解决方案。 这些策略的副作用往往会在可访问性、性能和网络弹性方面产生红利,因此这里有更大的前景。

我们倾向于不考虑屏幕阅读器的数量。 我们只是理所当然地认为,尽我们最大的努力支持没有其他方式消费我们内容的用户在道德上是正确的,这不是我们自己的过错。 同样的原则也适用于使用旧版浏览器的人。

我们已经介绍了一些构建健壮网站的高级策略,这些网站应该在一定程度上可以在广泛的传统和现代浏览器中继续工作。

再次声明:不要为 IE 破解东西。 那将失去重点。 但是请注意,各种各样的人出于各种原因使用各种浏览器,并且我们可以采取一些可靠的工程方法来使每个人都可以访问网络。

为多数人优化,为少数人努力,从不牺牲安全。

关于 SmashingMag 的进一步阅读

  • 网络标准:什么、为什么和如何
  • 智能捆绑:如何仅向旧版浏览器提供旧版代码
  • 不要使用占位符属性
  • 为无浏览器 Web 设计