基于未来规范的预处理问题

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 价值 200 美元的免费积分!

假设从深处(阅读:潜在未来网络技术规范的早期编辑草案)传来一些声音,表明了一些潜在的未来代码语法。 假设该语法看起来非常棒,我们希望现在就能使用它。 这就是如今一些预处理背后的理念。

由于这种预处理方式具有“编写未来代码并将其转换为今天的代码”的感觉,因此人们通常将其称为**后**处理。 我认为这充其量是愚蠢的,最坏的情况是令人困惑。 我将继续称其为预处理。 该过程与预处理完全相同:您使用特殊语法编写代码,它在构建步骤中被处理成常规 CSS,常规 CSS 是网站使用的。 **预**处理。 我认为“后处理”更适合诸如 -prefix-free 或其他客户端 polyfill 之类的东西。

CSS 中关于未来语法预处理的讨论与关于 PostCSS 的讨论相关。 但 PostCSS 本身并没有做太多 CSS 转换。 David Clark 这样解释

[PostCSS] 不会改变您的 CSS。 插件可能会这样做。 也许不会。 *PostCSS 插件可以对解析后的 CSS 做几乎任何他们想做的事情。* 一个插件可以启用变量,或其他一些有用的语言扩展。 另一个可以将所有 as 更改为 ks。 另一个可以在您使用 ID 选择器时发出警告。 另一个可以在您的样式表顶部添加共济会 ASCII 艺术。 另一个可以计算您使用 float 声明的次数。

因此,未来语法预处理并非直接来自 PostCSS,而是来自 PostCSS 插件。 其中有一个插件特别关注这一点:cssnext。 cssnext 实际上是一组 PostCSS 插件,它们都专注于未来语法预处理。 但 cssnext 并非孤军奋战。 还有其他预处理器和插件以类似的方式运行。 在 JavaScript 方面,像 Babel 这样的预处理器处于同一位置。

我认为关于未来语法预处理的想法存在一些问题。

**但为了在开始之前澄清:**您做您想做的。 如果您使用并喜欢这种预处理方式,那很好。 欢迎在评论中谈论它。 而且,如果您参与了这些预处理项目的开发,那太好了。 您可能比我更能帮助网络,因为您允许人们尽早使用未来语法。

我们在 CodePen 上 支持 PostCSS(包括 cssnext)。 我们在 CodePen 上 支持 Babel。 我最不想做的事情就是阻碍想法。

我只是认为这里有一些值得考虑的事情,这些事情可能会给那些选择将它们用于真实、长期、生产产品的人带来麻烦。 至少,这是一个值得讨论的话题。

一个微小的例子

冒着陷入一个样本的风险,这里有一个关于未来语法预处理如何在 CSS 中工作的例子。 这就是 CSS 变量 现在的样子,处于**编辑草案**阶段。

:root {
  --brandColor: #F06D06;
}
.main-header {
  background: var(--brandColor);
}

有很多 CSS 预处理器™ 可以为您处理它。 结果可能是

.main-header {
  background: #F06D06;
}

问题 #1:未来语法更改

Firefox 实际上正在发布支持上述原生 CSS 变量示例的功能。 但他们必须 进行一些编织。 它首先在 v29 中使用 var- 前缀而不是 -- 出现。 **但随后规范发生了变化。** 因此他们不得不更改实现。

这意味着支持此功能的 CSS 预处理也必须进行一些编织。 这意味着预处理器作者需要进行一些艰难的更改和分叉。

预处理器开发者可以选择什么

  • 您是否支持新的语法更改?
    • = 保持作为未来语法预处理器的精神。
    • = 现在您只是一个基于孤立语法的预处理器。
  • 您是否也支持旧语法?
    • = 存在令人困惑的语法的风险,以及必须以多种方式处理事物的臃肿代码库。
    • = 您将破坏人们的代码。

并非都是好选择。 当 cssnext 面临变化时,他们 首先输出警告,然后在下一个版本中弃用旧语法。

cssnext:以前 @custom-selector 在有和没有伪语法 ':' 的情况下都可以工作。 现在您必须使用 '@custom-selector :–{name}' 语法而不是 '@custom-selector –{name}'。 在下一个主要版本中将删除对没有 ':' 的语法的支持和此警告。

预处理器用户可以选择什么

如果您是未来语法预处理器的用户,您必须接受您将面临随机出现的破坏性更改。 这与大多数其他预处理器的运作方式相矛盾,在其他预处理器中,语法是人为制造的,并且*故意与*原生 CSS 语法(未来或现在)*不同*。

  • 您是否将代码更新到新的语法? 如果预处理器开发人员弃用旧语法,您要么必须更新代码,要么永远不更新版本。
  • 您有选择吗? 如果预处理器开发人员坚持使用旧语法或支持两个版本,您可以保留代码不变。 您必须决定您对新语法的投入程度。 如果开发人员只使用新语法,您必须决定是更新代码还是放弃并停止使用该特定预处理部分。

问题 #2:某些功能无法复制

我们一开始提到的 CSS 变量示例也可以说明这一点。 原生 CSS 变量在浏览器中的工作方式与在最终 CSS 中简单地用值替换变量名不同。 使用原生 CSS 变量,如果您使用 JavaScript 更改变量的值,则引用该变量的所有内容都会相应更新。 它以一种用静态代码替换这些值无法实现的方式保持动态性。

CSS calc() 是另一个例子。 您不能简单地将所有 calc() 实例替换为处理后的值。 预处理器无法知道 100% - 20px 的计算结果。 浏览器需要评估它,并在环境发生变化时不断评估它。 如果您只需要进行一些静态计算,您可能应该直接进行计算,而不是将它放在 calc() 中。

用于 calc() 的 PostCSS 插件 很聪明,因为它“在可能的情况下减少 calc() 引用。” – 这意味着,如果您写的内容*可以*是静态的,它就会将其设为静态的。 这说明了虽然我们在这里进行了一次范围广泛的讨论,但关于特定项目上使用情况的讨论范围会更窄,重点是特定插件如何解决您遇到的特定需求。

用于 分离转换属性 的插件特别说明

一旦这些新属性在本地得到支持,您也可以使用它们对多个规则的转换进行样式设置,而不会覆盖先前规则的转换。 不幸的是,我无法在不知道您的 DOM 的情况下预测您的 CSS 规则将如何继承。 因此,目前无法模拟此特别有用的功能。

因此,如果您现在开始使用它,您将无法获得该语法存在的首要好处。 而且,当您删除插件时,代码的功能将完全不同。

并不是说该插件不好。 它确实做了一些好事。 它使创作更直观。 它使版本控制差异更有用。 它向浏览器功能实现者发出信号,表明人们对此很感兴趣。 它修改代码以使用最有效的技术。

只是感觉有点危险,而且如果您走这条路,最好知道自己在做什么。

问题 #3:切换

如果您使用未来语法处理器的理由是您认为总有一天您可以放弃预处理器并拥有完全有效的 CSS,那么这将很困难。 它实际上可能会延迟那一刻。 假设您想开始实际发布一些未来语法代码,因为一些浏览器开始支持它。 但是您的预处理器仍在处理它,而且您无法删除预处理器,因为很多浏览器还不支持它。

也许预处理器可以开始输出既包含未来语法又包含回退的代码?也许这不可能?也许是因为开发人员没有响应或不感兴趣?

如果未来语法永远不会出现怎么办?那么切换可能永远不会发生。

我个人对永远不切换感到满意。我认为一定程度的 CSS 抽象(预处理步骤)总是很有意义的。无论如何都需要构建步骤(连接、压缩和其他部署准备),所以最好也进行预处理。

此外,我认为有些概念应该属于语言的抽象,而不是语言本身。变量可以再次作为示例。预处理器变量和原生变量可以共存,并在各自的方式下发挥作用。如果原生 CSS 可以实现预处理器中梦想的一切,它会很慢、很复杂,而且可能不会像 CSS 作为语言那样取得成功。

问题 #4:代码可移植性

我听说过未来语法代码更“安全”的表达方式,因为它“只是 CSS”,因此更便携。这意味着你可以与其他人共享它,在项目之间共享它,更轻松地写下它等等。

如果我们谈论的是当前的原生 CSS,那是正确的。但请记住,PostCSS 是一个庞大的插件生态系统,你通过将你感兴趣的插件拼凑起来来使用它。这意味着任何给定项目都使用不同的插件配置。任何给定的代码块可能在使用不同插件的不同项目中不起作用。或者它可能起作用,如果它只依赖于另一个项目碰巧也拥有的插件。或者它可能会以不同的方式工作,如果另一个项目有不同的插件,但恰好接受相同的作者语法。

与在使用与原生 CSS 不同的通用抽象的系统中编写的代码相比,在这种系统中编写的代码实际上“可移植性更差”。似乎深入参与 Sass 和 CSS 的人都同意这一点。

所以

你怎么认为?我完全错了,这里没有什么可担心的吗?你有任何个人经验可以分享吗?