移动优先CSS:是时候重新思考了吗?

本文探讨移动优先CSS开发方法的优缺点,分析覆盖样式声明带来的复杂性和低效问题,并提出使用封闭媒体查询范围和分离CSS文件的替代方案,以提升代码维护性和浏览器性能优化。

移动优先CSS:是时候重新思考了吗?

移动优先设计方法很棒——它专注于用户真正关心的内容,经过实践检验,并且多年来一直是通用的设计模式。因此,开发CSS时采用移动优先也应该很棒……对吗?

嗯,不一定。经典的移动优先CSS开发基于覆盖样式声明的原则:你从默认样式声明开始CSS,然后随着为更大视口添加min-width媒体查询断点,覆盖和/或添加新样式(详细概述请参见“什么是移动优先CSS及其优势?”)。但所有这些例外都会带来复杂性和低效性,进而可能导致测试工作量增加和代码库更难维护。承认吧——我们中有多少人愿意这样?

在你自己的项目中,移动优先CSS可能仍然是最合适的工具,但首先你需要根据正在处理的视觉设计和用户交互来评估它的适用性。为了帮助你入门,以下是我处理需要注意的因素的方法,并讨论一些如果移动优先似乎不适合你的项目时的替代解决方案。

移动优先的优势

移动优先CSS开发的一些优点——以及它为什么成为长期事实上的开发方法——很有道理:

  • 开发层次结构。移动优先无疑提供了一个良好的开发层次结构——你只需专注于移动视图并开始开发。
  • 经过验证。这是一种经过验证的方法,多年来一直有效是有原因的:它能很好地解决问题。
  • 优先考虑移动视图。移动视图是最简单的, arguably也是最重要的,因为它包含了所有关键用户旅程,并且通常占用户访问的较高比例(取决于项目)。
  • 防止以桌面为中心的开发。由于开发是使用台式计算机完成的,最初专注于桌面视图可能很诱人。但从一开始就考虑移动可以防止我们后来陷入困境;没有人愿意花时间将桌面为中心的网站改造为在移动设备上工作!

移动优先的缺点

设置样式声明然后在更高断点覆盖它们可能导致不良后果:

  • 更复杂。断点层次结构越高,你从较低断点继承的不必要代码就越多。
  • 更高的CSS特异性。在类名声明中已恢复为浏览器默认值的样式现在具有更高的特异性。在大型项目中,当你希望保持CSS选择器尽可能简单时,这可能是一个头疼的问题。
  • 需要更多回归测试。在较低视图更改CSS(如添加新样式)需要对所有较高断点进行回归测试。
  • 浏览器无法优先下载CSS。在更宽的断点,经典的移动优先min-width媒体查询无法利用浏览器按优先级顺序下载CSS文件的能力。

属性值覆盖的问题

覆盖值本身没有错;CSS就是为此设计的。然而,继承不正确的值是无益的,并且可能繁重且低效。当你必须覆盖样式以将其重置回默认值时,它还可能导致样式特异性增加,这可能会在以后引起问题,特别是如果你正在使用定制CSS和实用类的组合。对于已用更高特异性重置的样式,我们将无法使用实用类。

考虑到这一点,我现在更注重默认值来开发CSS。由于没有特定的顺序,也没有需要跟踪的特定值链,这使我能够同时开发断点。我专注于查找常见样式并将特定例外隔离在封闭的媒体查询范围内(即任何设置了max-width的范围)。

这种方法开辟了一些机会,因为你可以将每个断点视为一张白纸。如果一个组件的布局看起来应该在所有断点基于Flexbox,那很好,可以在默认样式表中编码。但如果Grid对大型屏幕更好而Flexbox对移动设备更好,当CSS放入封闭的媒体查询范围时,这两者都可以完全独立地完成。此外,同时开发要求你事先对任何给定组件在所有断点有很好的理解。这有助于在开发过程早期发现设计中的问题。我们不希望陷入为移动设备构建复杂组件的兔子洞,然后获得桌面设计并发现它们同样复杂且与我们为移动视图创建的HTML不兼容!

虽然这种方法不适合所有人,但我鼓励你尝试一下。有许多工具可以帮助并发开发,例如Responsively App、Blisk和许多其他工具。

话虽如此,我不觉得顺序本身特别相关。如果你习惯于专注于移动视图,对其他断点的要求有很好的理解,并且更喜欢一次处理一个设备,那么请坚持经典的开发顺序。重要的是识别常见样式和例外,以便将它们放入相关的样式表中——一种手动tree-shaking过程!就个人而言,我发现跨断点处理组件时这更容易一些,但这绝不是必须的。

实践中的封闭媒体查询范围

在经典的移动优先CSS中,我们覆盖样式,但我们可以通过使用媒体查询范围来避免这种情况。为了说明差异(我使用SCSS简洁起见),假设有三个视觉设计:

  • 小于768
  • 从768到低于1024
  • 1024及以上

举一个简单的例子,一个块级元素的默认padding为“20px”,在平板电脑上被覆盖为“40px”,在桌面上设置回“20px”。

经典min-width移动优先

1
2
3
4
5
6
7
8
9
.my-block {
  padding: 20px;
  @media (min-width: 768px) {
    padding: 40px;
  }
  @media (min-width: 1024px) {
    padding: 20px;
  }
}

封闭媒体查询范围

1
2
3
4
5
6
.my-block {
  padding: 20px;
  @media (min-width: 768px) and (max-width: 1023.98px) {
    padding: 40px;
  }
}

细微的差别在于,移动优先示例将默认padding设置为“20px”,然后在每个断点覆盖它,总共设置了三次。相比之下,第二个示例将默认padding设置为“20px”,仅在不默认值的相关断点覆盖它(在此实例中,平板电脑是例外)。

目标是:

  • 仅在需要时设置样式。
  • 不要设置它们并期望以后一次又一次地覆盖它们。

为此,封闭媒体查询范围是我们最好的朋友。如果我们需要对任何给定视图进行更改,我们在适用于特定断点的CSS媒体查询范围内进行更改。我们不太可能引入不需要的更改,并且我们的回归测试只需要专注于我们实际编辑的断点。

以上述示例为例,如果我们发现桌面上的.my-block间距已由该断点的marginaccounted for,并且由于我们想完全移除padding,我们可以通过将移动padding设置在封闭媒体查询范围内来实现。

1
2
3
4
5
6
7
8
.my-block {
  @media (max-width: 767.98px) {
    padding: 20px;
  }
  @media (min-width: 768px) and (max-width: 1023.98px) {
    padding: 40px;
  }
}

我们块的浏览器默认padding为“0”,因此不是添加桌面媒体查询并对padding值使用unset或“0”(移动优先需要这样做),我们可以将移动padding包装在封闭媒体查询中(因为现在它也是一个例外),因此它不会在更宽的断点被拾取。在桌面断点,我们不需要设置任何padding样式,因为我们想要浏览器默认值。

捆绑与分离CSS

过去,由于浏览器并发请求的限制(通常约为六个),将请求数量保持在最低限度非常重要。因此,使用图像精灵和CSS捆绑是常态,所有CSS都以最高优先级一次性下载,作为一个样式表。

随着HTTP/2和HTTP/3的出现,请求数量不再像以前那样重要。这使我们能够按媒体查询将CSS分成多个文件。这样做的明显好处是,浏览器现在可以以比不需要的CSS更高的优先级请求当前需要的CSS。这更高效,可以减少页面渲染被阻塞的总时间。

你使用哪个HTTP版本?

要确定你使用的HTTP版本,请访问你的网站并打开浏览器的开发工具。接下来,选择“网络”选项卡并确保“协议”列可见。如果“协议”下列出“h2”,则表示正在使用HTTP/2。

注意:要在浏览器的开发工具中查看协议,请转到“网络”选项卡,重新加载页面,右键单击任何列标题(例如,“名称”),并勾选“协议”列。

注意:有关摘要比较,请参见ImageKit的“HTTP/2 vs. HTTP/1”。

另外,如果你的网站仍在使用HTTP/1……为什么?!!你在等什么?HTTP/2有出色的用户支持。

拆分CSS

将CSS分成单独的文件是一项值得的任务。使用相关media属性链接单独的CSS文件允许浏览器识别哪些文件是立即需要的(因为它们是渲染阻塞的),哪些可以延迟。基于此,它为每个文件分配适当的优先级。

在以下移动断点访问网站的示例中,我们可以看到移动和默认CSS以“最高”优先级加载,因为它们当前是渲染页面所需的。剩余的CSS文件(打印、平板电脑和桌面)仍然被下载以备后用,但优先级为“最低”。

使用捆绑CSS,浏览器将不得不下载CSS文件并解析它,然后才能开始渲染。而如前所述,将CSS分成不同的文件并链接并使用相关media属性标记,浏览器可以优先处理当前需要的文件。使用封闭媒体查询范围允许浏览器在所有宽度下执行此操作,而不是经典的移动优先min-width查询,桌面浏览器将不得不以最高优先级下载所有CSS。我们不能假设桌面用户总是有快速连接。例如,在许多农村地区,互联网连接速度仍然很慢。

媒体查询和单独CSS文件的数量将因项目要求而异,但可能类似于以下示例。

捆绑CSS

1
<link href="site.css" rel="stylesheet">

这个单一文件包含所有CSS,包括所有媒体查询,它将以最高优先级下载。

分离CSS

1
2
3
4
5
<link href="default.css" rel="stylesheet">
<link href="mobile.css" media="screen and (max-width: 767.98px)" rel="stylesheet">
<link href="tablet.css" media="screen and (min-width: 768px) and (max-width: 1083.98px)" rel="stylesheet">
<link href="desktop.css" media="screen and (min-width: 1084px)" rel="stylesheet">
<link href="print.css" media="print" rel="stylesheet">

分离CSS并在每个链接标签上指定media属性值允许浏览器优先处理当前需要的内容。在上面列出的五个文件中,两个将以最高优先级下载:默认文件和匹配当前媒体查询的文件。其他将以最低优先级下载。

根据项目的部署策略,对一个文件(例如mobile.css)的更改只需要QA团队在该特定媒体查询范围内的设备上进行回归测试。相比之下,部署单个捆绑的site.css文件通常会触发完整的回归测试。

前进

移动优先CSS的采用是Web开发中一个非常重要的里程碑;它帮助前端开发人员专注于移动Web应用程序,而不是在桌面上开发网站然后尝试改造它们以在其他设备上工作。

我认为没有人想再回到那种开发模式,但重要的是我们不要忽视它强调的问题:如果我们优先考虑一个特定设备——任何设备——而不是其他设备,事情很容易变得复杂和低效。因此,专注于CSS本身,始终注意什么是默认设置,什么是例外,似乎是自然的下一步。我开始注意到我自己以及其他开发人员的CSS中的小简化,并且测试和维护工作也稍微简化且更高效。

总的来说,尽可能简化CSS规则创建最终是一种比绕圈子覆盖更清晰的方法。但无论你选择哪种方法,它都需要适合项目。移动优先可能——也可能不是——所涉及内容的最佳选择,但首先你需要扎实理解你正在步入的权衡。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计