处理常见的 HTML 和 CSS 问题

在建立了基础之后,我们将专门关注在 HTML 和 CSS 代码中经常遇到的跨浏览器问题,以及可以使用哪些工具来防止问题发生或修复已经发生的问题。 这包括代码 linting、处理 CSS 前缀、使用浏览器开发者工具追踪问题、使用 polyfills 向浏览器添加支持、解决响应式设计问题等等。

先决条件 熟悉核心 HTMLCSSJavaScript 语言;了解 跨浏览器测试原则 的高级概念。
目标 能够诊断常见的 HTML 和 CSS 跨浏览器问题,并使用适当的工具和技术来修复它们。

HTML 和 CSS 的问题

HTML 和 CSS 的一些问题在于这两种语言都比较简单,开发人员往往不会认真对待它们,没有确保代码编写良好、高效,以及语义上描述页面功能的意图。 在最糟糕的情况下,JavaScript 用于生成整个网页内容和样式,这会导致页面不可访问,性能降低(生成 DOM 元素开销很大)。 在其他情况下,新生功能在不同浏览器中的支持并不一致,这会导致某些功能和样式无法在某些用户中使用。 响应式设计问题也很常见——一个在桌面浏览器中看起来很好的网站可能在移动设备上提供糟糕的体验,因为内容太小而无法阅读,或者可能是因为动画开销大导致网站速度慢。

让我们继续研究如何减少由 HTML/CSS 引起的跨浏览器错误。

首先:修复一般问题

我们在 本系列的第一篇文章 中提到,一个好的策略是首先在桌面/移动设备上的一些现代浏览器中进行测试,以确保您的代码总体上能够正常运行,然后再继续关注跨浏览器问题。

在我们的 调试 HTML调试 CSS 文章中,我们提供了一些关于调试 HTML/CSS 的基本指导——如果您不熟悉这些基础知识,您应该在继续之前仔细研究这些文章。

基本上,这只是检查您的 HTML 和 CSS 代码是否格式正确,不包含任何语法错误。

注意:CSS 和 HTML 中的一个常见问题是不同的 CSS 规则开始相互冲突。 当您使用第三方代码时,这尤其成问题。 例如,您可能使用了一个 CSS 框架,并发现它使用的类名之一与您已经为其他目的使用的类名冲突。 或者您可能会发现由某种第三方 API 生成的 HTML(例如生成广告横幅)包含您已经为其他目的使用的类名或 ID。 为了确保这种情况不会发生,您需要首先研究您正在使用的工具,并根据它们设计您的代码。 还值得对 CSS 进行“命名空间”,例如,如果您有一个小部件,请确保它具有一个独特的类名,然后从这个类名开始选择小部件内部元素的选择器,这样冲突的可能性就会降低。 例如 .audio-player ul a

验证

对于 HTML,验证涉及确保所有标记都正确关闭和嵌套,您正在使用 DOCTYPE,并且您正在将标记用于其正确目的。 一个好策略是定期验证您的代码。 可以执行此操作的一项服务是 W3C 标记验证服务,它允许您指向您的代码,并返回错误列表。

The HTML validator homepage

CSS 也有类似的情况——您需要检查您的属性名称拼写是否正确,属性值拼写是否正确,并且对它们使用的属性有效,您没有缺少任何花括号等等。 W3C 也为这个目的提供了一个 CSS 验证器

代码检查工具

另一个不错的选择是所谓的代码检查工具应用程序,它不仅会指出错误,还会标记 CSS 中不良实践的警告,以及其他一些问题。 代码检查工具通常可以自定义,使其在错误/警告报告中更加严格或更加宽松。

有很多在线代码检查工具应用程序,例如 Dirty Markup,用于 HTML、CSS 和 JavaScript。 这些应用程序允许您将代码粘贴到一个窗口中,它会用十字标记标记任何错误,然后可以通过悬停来获取错误消息,告知您问题是什么。 Dirty Markup 还允许您使用“清理”按钮修复您的标记。

Dirty Markup application displaying the message "Unexpected character in unquoted attribute" over the following incorrect HTML markup: <div id=combinators">

但是,每次都要将代码复制粘贴到网页上以检查其有效性并不方便。 您真正想要的是一个代码检查工具,它可以以最小的麻烦融入您的标准工作流程中。

许多代码编辑器都有代码检查工具插件。 例如,请参见

浏览器开发者工具

大多数浏览器内置的开发者工具还提供了用于查找错误的实用工具,主要用于 CSS。

注意:HTML 错误通常不会在开发者工具中很容易地显示出来,因为浏览器会尝试自动更正格式错误的标记;W3C 验证器是查找 HTML 错误的最佳方法——请参阅上面的 验证

例如,在 Firefox 中,CSS 检查器将显示未应用的 CSS 声明,并带有一个警告三角形。 将鼠标悬停在警告三角形上将提供描述性错误消息

The developer tools cross out invalid CSS and add a hoverable warning icon

其他浏览器开发者工具具有类似的功能。

常见的跨浏览器问题

现在让我们继续了解一些最常见的跨浏览器 HTML 和 CSS 问题。 我们将重点关注的主要领域是缺乏对现代功能的支持和布局问题。

浏览器不支持现代功能

这是一个常见问题,尤其是在您需要支持旧浏览器或使用某些浏览器中已实现但在所有浏览器中尚未实现的功能时。 通常,大多数核心 HTML 和 CSS 功能(例如基本 HTML 元素、CSS 基本颜色和文本样式)在您想要支持的所有浏览器中都能正常工作;更多的问题会在您开始想要使用更新的 HTML、CSS 和 API 时发现。 MDN 为每个记录的功能显示浏览器兼容性数据;例如,请参阅 :has() 伪类的浏览器支持表

确定了您将使用的并非普遍支持的技术列表后,最好研究一下哪些浏览器支持它们,以及哪些相关技术有用。 请参阅下面的 寻求帮助

HTML 回退行为

有些问题可以通过利用 HTML/CSS 的自然工作方式来解决。

浏览器将无法识别的 HTML 元素视为匿名内联元素(实际上是没有任何语义值的内联元素,类似于 <span> 元素)。 您仍然可以通过它们的名字引用它们,并使用 CSS 对它们进行样式设置,例如——您只需要确保它们按照您的预期进行操作。 对它们进行样式设置就像对任何其他元素一样,包括在需要时将 display 属性设置为 inline 以外的值。

更复杂的元素,如 HTML <video><audio><picture><object><canvas>(以及其他功能)具有自然的机制,用于在链接到的资源不支持的情况下添加回退。 您可以在开始和结束标记之间添加回退内容,不支持的浏览器将有效地忽略外部元素并运行嵌套内容。

例如

html
<video id="video" controls preload="metadata" poster="img/poster.jpg">
  <source
    src="video/tears-of-steel-battle-clip-medium.webm"
    type="video/webm" />
  <!-- Offer download -->
  <p>
    Your browser does not support WebM video; here is a link to
    <a href="video/tears-of-steel-battle-clip-medium.mp4"
      >view the video directly</a
    >
  </p>
</video>

此示例包含一个简单的链接,允许您下载视频,即使 HTML 视频播放器无法正常工作,这样至少用户仍然可以访问视频。

另一个例子是表单元素。 当为将特定信息输入表单引入新的 <input> 类型时,例如时间、日期、颜色、数字等,如果浏览器不支持新功能,浏览器将使用 type="text" 的默认值。 添加了输入类型,它们非常有用,尤其是在移动平台上,为用户提供一种轻松输入数据的方式对于用户体验非常重要。 平台根据输入类型提供不同的 UI 小部件,例如用于输入日期的日历小部件。 如果浏览器不支持输入类型,用户仍然可以输入所需数据。

以下示例显示了日期和时间输入

html
<form>
  <div>
    <label for="date">Enter a date:</label>
    <input id="date" type="date" />
  </div>
  <div>
    <label for="time">Enter a time:</label>
    <input id="time" type="time" />
  </div>
</form>

此代码的输出如下

注意:您也可以在 GitHub 上将其作为 forms-test.html 在线查看(也请参阅 源代码)。

如果您查看该示例,您将在尝试输入数据时看到 UI 功能的实际运行情况。 在具有动态键盘的设备上,将显示特定于类型的键盘。 在不支持的浏览器中,输入将只默认设置为普通文本输入,这意味着用户仍然可以输入正确的信息。

CSS 回退行为

可以说 CSS 比 HTML 更擅长回退。 如果浏览器遇到它不理解的声明或规则,它只会完全跳过它,既不应用它也不抛出错误。 如果这种错误在生产代码中漏掉了,这对您和您的用户来说可能很令人沮丧,但至少这意味着整个网站不会因为一个错误而崩溃,如果您巧妙地使用它,您就可以利用它来发挥优势。

让我们看一个例子——一个用 CSS 样式化的简单框,它具有一些由各种 CSS 功能提供的样式

A red pill button with rounded corners, inset shadow, and drop shadow

注意:您也可以在 GitHub 上将其作为 button-with-fallback.html 在线查看(也请参阅 源代码)。

该按钮具有许多样式声明,但我们最感兴趣的两个是:

css
button {
  /* … */

  background-color: #ff0000;
  background-color: rgb(255 0 0 / 100%);
  box-shadow:
    inset 1px 1px 3px rgb(255 255 255 / 40%),
    inset -1px -1px 3px rgb(0 0 0 / 40%);
}

button:hover {
  background-color: rgb(255 0 0 / 50%);
}

button:active {
  box-shadow:
    inset 1px 1px 3px rgb(0 0 0 / 40%),
    inset -1px -1px 3px rgb(255 255 255 / 40%);
}

这里我们提供了一个RGB background-color,它在悬停时会改变不透明度,从而向用户提示按钮是可交互的,还有一些半透明的内嵌box-shadow阴影,为按钮提供一些纹理和深度。虽然现在得到了完全的支持,但 RGB 颜色和盒子阴影并不总是存在的;从 IE9 开始。不支持 RGB 颜色的浏览器会忽略该声明,这意味着在旧浏览器中,背景根本不会显示,文本将无法读取,这完全不好!

Hard to see pill button with white text on an almost white background

为了解决这个问题,我们添加了第二个background-color声明,它只指定一个十六进制颜色 - 这种颜色在非常旧的浏览器中得到了支持,并且在现代闪亮的功能无法正常工作时充当备用。发生的事情是,访问此页面的浏览器首先应用第一个background-color值;当它到达第二个background-color声明时,如果它支持 RGB 颜色,它将用此值覆盖初始值。否则,它会忽略整个声明并继续执行。

注意:对于其他 CSS 功能(如媒体查询@font-face@supports块)也是如此 - 如果不支持,浏览器会直接忽略它们。

选择器支持

当然,如果你没有使用正确的选择器来选择要设置样式的元素,那么所有 CSS 功能都将不会应用!

在用逗号分隔的选择器列表中,如果你只是错误地编写了一个选择器,它可能不会匹配任何元素。但是,如果选择器无效,则整个选择器列表将被忽略,以及整个样式块。因此,只在宽容选择器列表中包含:-moz-前缀的伪类或伪元素,例如:where(::-moz-thumb)。不要在逗号分隔的选择器组中包含:-moz-前缀的伪类或伪元素,除非是在:is():where()宽容选择器列表中,因为除 Firefox 之外的所有浏览器都会忽略整个块。请注意,:is():where()都可以作为参数传递给其他选择器列表,包括:has():not()

我们发现,使用浏览器的开发工具检查要设置样式的元素很有帮助,然后查看 DOM 检查器通常提供的 DOM 树面包屑跟踪,以查看选择器与之相比是否合理。

例如,在 Firefox 开发工具中,你会在 DOM 检查器底部看到这种类型的输出

The breadcrumb of elements is html > body > form > div.form > input#date

例如,如果你试图使用这个选择器,你将能够看到它不会像预期的那样选择输入元素

css
form > #date

date 表单输入不是<form>的直接子元素;你最好使用通用后代选择器而不是子选择器)。

处理 CSS 前缀

另一组问题与 CSS 前缀有关 - 这些前缀最初是一种机制,允许浏览器供应商在 CSS(或 JavaScript)功能处于实验状态时实现自己的版本,这样他们就可以玩弄它并使其正确,而不会与其他浏览器的实现或最终的非前缀实现冲突。

例如,Firefox 使用-moz-,Chrome/Edge/Opera/Safari 使用-webkit-。你可能在旧代码中遇到的其他可以安全删除的前缀包括-ms-,它被 Internet Explorer 和早期版本的 Edge 使用,以及-o,它在最初版本的 Opera 中使用。

前缀功能原本不打算在生产网站中使用 - 它们可能会在没有警告的情况下发生更改或删除,可能会在需要它们的旧浏览器版本中造成性能问题,并且一直是跨浏览器问题的原因。这尤其是一个问题,例如,当开发人员决定只使用属性的-webkit-版本时,这意味着该网站在其他浏览器中将无法正常工作。这种情况实际上发生的太多了,以至于其他浏览器供应商实现了几个 CSS 属性的-webkit-前缀版本。虽然浏览器仍然支持一些前缀属性名称、属性值和伪类,但现在实验性功能被放置在标志后面,以便 Web 开发人员可以在开发期间测试它们。

如果使用前缀,请确保它是必要的;该属性是少数几个剩余的前缀功能之一。你可以在 MDN 参考页面上查找哪些浏览器需要前缀,以及像caniuse.com这样的网站。如果你不确定,你也可以通过直接在浏览器中进行一些测试来找到答案。在带前缀的样式声明之后包含标准的非前缀版本;如果该版本不受支持,则会忽略它,如果该版本受支持,则会使用它。

css
.masked {
  -webkit-mask-image: url(MDN.svg);
  mask-image: url(MDN.svg);
  -webkit-mask-size: 50%;
  mask-size: 50%;
}

尝试这个简单的例子

  1. 使用此页面,或其他具有突出标题或其他块级元素的网站。
  2. 右键/Command + 点击要检查的元素,然后选择检查/检查元素(或你浏览器中的任何选项)- 这应该会打开浏览器中的开发工具,突出显示 DOM 检查器中的元素。
  3. 查找可以用来选择该元素的功能。例如,在撰写本文时,MDN 上的此页面有一个 ID 为mdn-docs-logo的徽标。
  4. 将对该元素的引用存储在一个变量中,例如
    js
    const test = document.getElementById("mdn-docs-logo");
    
  5. 现在尝试为该元素上感兴趣的 CSS 属性设置新值;你可以使用元素的style属性来执行此操作,例如,尝试在 JavaScript 控制台中键入以下内容
    js
    test.style.transform = "rotate(90deg)";
    

当你开始在第二个点之后键入属性名称表示形式时(请注意,在 JavaScript 中,CSS 属性名称以骆驼式编写,而不是短横线分隔式),JavaScript 控制台应该开始自动完成浏览器中存在且与你到目前为止所写内容匹配的属性的名称。这对于找出哪些属性在该浏览器中实现很有用。

如果你确实需要包含现代功能,请使用@supports测试功能支持,它允许你实现本机功能检测测试,并将前缀或新功能嵌套在@supports块中。

响应式设计问题

响应式设计是指创建能够适应不同设备外形尺寸的 Web 布局的做法 - 例如,不同的屏幕宽度、方向(纵向或横向)或分辨率。例如,桌面布局在移动设备上查看时会看起来很糟糕,因此你需要使用媒体查询提供合适的移动布局,并确保使用视窗正确应用它。你可以在响应式设计指南中找到有关此类做法的详细说明。

分辨率也是一个大问题 - 例如,移动设备不太可能像台式机一样需要大型、重量级的图像,而且移动设备更有可能拥有速度较慢的互联网连接,甚至可能拥有昂贵的数据计划,这会使浪费的带宽成为更大的问题。此外,不同的设备可以具有各种不同的分辨率,这意味着较小的图像可能会出现像素化。有很多技术可以让你解决这些问题,从媒体查询到更复杂的响应式图像技术,包括<picture><img>元素的srcsetsizes属性。

寻求帮助

你会遇到 HTML 和 CSS 的许多其他问题,因此了解如何在网上找到答案非常宝贵。

最好的支持信息来源包括 Mozilla 开发者网络(你现在就在这里!)、stackoverflow.comcaniuse.com

为了使用 Mozilla 开发者网络 (MDN),大多数人会在搜索引擎中搜索他们想要查找信息的科技,加上“mdn”一词,例如“mdn HTML 视频”。MDN 包含几种有用的内容类型

caniuse.com提供支持信息,以及一些有用的外部资源链接。例如,请参见https://caniuse.cn/#search=video(你只需将要搜索的功能输入文本框中)。

stackoverflow.com (SO) 是一个论坛网站,你可以在其中提问并让其他开发人员分享他们的解决方案,查找以前的帖子并帮助其他开发人员。建议你在发布新问题之前查看是否有问题的答案。例如,我们在 SO 上搜索了“禁用 HTML 对话框的自动聚焦”,并且很快找到了使用 HTML 属性禁用 showModal 自动聚焦

除此之外,尝试使用你最喜欢的搜索引擎搜索问题的答案。如果你有错误信息,搜索特定错误信息通常很有用 - 其他开发人员可能遇到过与你相同的问题。

摘要

现在你应该熟悉在 Web 开发中会遇到的主要跨浏览器 HTML 和 CSS 问题类型以及如何解决这些问题。