关于预处理器的思考

Avatar of Chris Coyier
Chris Coyier

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

我最近几乎在所有工作中都使用 Sass。 这里有一些关于这段旅程的思考。 从阻碍到绊脚石,再到令人却步之处。 从应用和团队到工作流程和语法。

必须在本地工作

促使我加入这个潮流的最大因素是放弃了我的随心所欲的实时 FTP 编辑方式。是的,Coda很棒,但它容易养成坏习惯。它使得在实时环境下工作变得过于简单,而不是在本地工作1

本地工作有很多明显的优势。 具体来说,1)速度快 2)您可以随意编辑内容,而不用担心会搞砸网站,并且 3)它允许您通过版本控制有效地与团队合作(稍后将详细介绍)。

所以,就这么做吧。如果您只处理静态网站,您可以立即开始这样做。在您的机器上的某个文件夹中工作。如果您处理 PHP 网站(例如 WordPress、Joomla、PHP、Vanilla、CodeIgnitor、CakePHP 以及数百万个其他网站),那么使用 MAMP(我的截屏视频)是理想的选择。当然,所有平台都有 MAMP 的变体

如果您使用的是 Ruby 或 Python 之类的东西,那么很有可能您已经知道如何设置这些东西,所以您没问题。

现在,我主要在本地机器上运行的项目上工作,使用预处理器变得很容易。我使用了几个很棒的应用程序,稍后我会介绍。

命令行 等等

我是一个设计师!我不知道如何使用命令行,也不需要知道。

关于 SASS,这是很常见的。事情是这样的:我和你们的想法一样。我讨厌命令行。您不需要使用它。我几乎从不使用它,任何事情都不用2

其他令人却步之处

这可能听起来很幼稚,但另一个让我花了这么长时间才加入预处理器潮流的原因是这个群体。而且我并不是唯一一个这样的人。

很难对预处理器说任何话,更不用说稍微负面的评价了,否则就会遭到猛烈抨击。

很长一段时间,我一直认为:我每天都在编写 CSS。我对 CSS 非常了解。我的工作流程很好。我的工作效率很高。为什么需要改变任何东西?

真正的答案是,如果你不想改变,就没有必要改变。如果你对现在的工作状态感到满意:祝你好运。

我可以告诉你,在做出改变之后,我的工作效率实际上更高了。并且我编写了更好的 CSS。而且我参与的项目也因此变得更好、更易于维护。在某些情况下,速度也更快了3。我的建议是:不要让别人对你指指点点。只管做你需要做的事情。如果你有时间尝试一下,就去做。并且要在真实的项目中尝试。只是胡乱尝试是不够的。你必须真正尝试它,才能了解它如何适应你的日常工作。

应用程序

我只有使用 Mac 应用程序的经验。抱歉。我相信其他平台上也有一些非常不错的应用程序。

让我开始使用所有这些预处理器好处的应用程序是 LiveReload截屏视频)。我仍然是它的粉丝。它现在可以在 App Store 上以 9.99 美元的价格购买。它是一个菜单栏应用程序,点击菜单栏中的图标会打开一个选项窗口。

LiveReload:菜单栏图标、应用程序窗口以及安装了浏览器扩展的浏览器。

您可以告诉 LiveReload 监视特定文件夹。当该文件夹中的任何文件发生更改时,它会触发预处理。它可以处理大量预处理器。对于 CSS:LESSSASS(带 Compass)或 Stylus。对于 JavaScript:CoffeeScriptIcedCoffeeScript。对于 HTML:HAMLJadeSlimEco

预处理完成后,它会在您安装了 浏览器扩展 的任何浏览器中重新加载页面。如果您更改的只是 CSS,它会将样式注入到页面中,而无需刷新页面。这在您在特定状态下的页面上设置样式时特别有用。假设单击会触发打开一个对话框,并且您正在尝试设置该对话框的样式。使用 LiveReload,您可以保持该对话框打开状态,新注入的样式将影响它,这意味着不会浪费很多时间点击和重新点击。

但最近我切换到了 CodeKit。CodeKit 的 UI 更好,功能更多(例如图像优化、JS 连接)并且限制更少(您可以选择是否预处理文件以及文件放置的位置,而 LiveReload 则是在导入后无法对其进行编译)。我唯一怀念的是 LiveReload 在不重新加载页面的情况下注入 CSS 的能力,对于具有复杂状态的网站来说,这是一种方便的功能,这些状态需要多个步骤才能在重新加载后将页面恢复到该状态。 2012 年 4 月更新:CodeKit 现在可以实时注入 CSS 了

不过,我对 LiveReload 有几件事不太满意。其中一个是您告诉它已编译源的输出路径的屏幕

我讨厌这个屏幕

注意那些灰色的部分?它试图变得聪明一点,并注意到您已在其他地方包含了该文件。因此它不会进行编译。但是,如果您想出于其他一些原因对其进行编译呢?太糟糕了,无法做到。它只是一个糟糕的 UI,而且使用起来可能有点棘手。

因此,CodeKit 出现了。CodeKit 拥有一个漂亮的 UI。

嗯嗯。UI 爱好者。

更改文件路径到文件编译到的位置非常容易。而且我从未需要教它,它似乎能够识别目录结构并从一开始就正确设置。它也会将包含的文件也变灰,但您可以轻松地打开和关闭此功能。

CodeKit 仅限于 LESS、Sass、Stylus、CoffeeScript 和 HAML。我发现这有点限制,因为我在一些项目中使用了 Jade 来预处理 HTML。Jade 能够进行 HTML 包含,这非常有用。

CodeKit 的错误报告非常好。很清楚发生了什么,并且在解决问题时感觉很好。

将其与 LiveReload 进行对比,在 LiveReload 中,一个小窗口从屏幕右上方滑下,显示被截断的文本,没有关闭按钮,并且在您解决问题后会自行消失。

CodeKit 也无法执行 LiveReload 可以执行的样式注入。创建者对这一点的感受如下

更新:CodeKit 现在可以进行实时注入。

最终,我认为 CodeKit 现在是我的最爱。使其脱颖而出的原因是它拥有所有其他功能。它可以自动bless CSS。它可以连接和压缩 JavaScript。它可以告诉你哪些文件包含了任何其他特定文件。也许我最喜欢的是:它可以一键优化图像。

团队

另一个可能阻碍使用预处理器的因素:团队合作。特别是多个成员进出同一 CSS 文件的团队。如果是这种情况,所有这些成员都需要设置您正在使用的任何预处理应用程序(您可以使用不同的应用程序,这没问题。最好是它们都运行预处理器的相同核心版本)。您不能让一些成员编辑 .css 文件,而其他成员编辑 .scss 文件。下次有人编译并提交时,对 .css 文件的这些更改将被覆盖。预处理器在这方面是不可饶恕的。它们不会说“嘿,看起来这个 .css 文件与我上次编译时有一些不同的内容,你想先看看吗?”不,它们只会覆盖它。

尽管如此,这是可行的。在短时间内,我们将所有Wufoo迁移到了SASS。实际上,我们先将其中一部分迁移到了LESS,然后一部分迁移到了Stylus,最后全部迁移到了SASS。真是太麻烦了。感谢Kevin的贡献。我们还在SurveyMonkey的所有新开发中使用了一套大型的设计模式,这些模式都使用了SASS。

如果有人有任何关于预处理器的团队策略,分享出来将会很有价值!

Compass

我敢肯定,有些人会因为我没有使用Compass而感到沮丧。我知道,我知道。我应该用。但显然我对这些东西反应比较慢。我喜欢在继续之前尽可能深入地理解事物,而Compass对我来说仍然有点复杂。如果有人不知道Compass是什么,它其实是一套用于SASS的大型插件。从本质上讲,这意味着您不必编写那些可能需要在每个项目中都以相同方式编写的代码。CSS3混合宏、网格助手、精灵助手、文件路径助手等等。

我的问题是我还没有准备好放弃所有这些东西。我想自己编写。我相信总有一天我会放弃的,但现在还没有。

让我绊倒的小问题

这篇文章最初以这个标题开头,后来扩展成了现在这样。但是,不管怎样,我想我仍然会包含这些让我在学习过程中感到痛苦的小细节。

由于我编写自己的CSS3混合宏,我可能会有一个像这样的box-shadow混合宏

@mixin drop-shadow ($x: 1px, $y: 1px, $blur: 2px, $spread: 0, $alpha: 0.25) {
  -webkit-box-shadow: $x $y $blur $spread rgba(0, 0, 0, $alpha);
  -moz-box-shadow:    $x $y $blur $spread rgba(0, 0, 0, $alpha);
  box-shadow:         $x $y $blur $spread rgba(0, 0, 0, $alpha);
}

它充满了合理的默认值,因此最标准的用法可以是

.module {
  @include drop-shadow();
}

或者如果我想更具体一些,我可以指定每个部分

.module {
  @include drop-shadow(5px, 5px, 2px, -2px, 0.5);
}

但是如果我想使用多个box-shadow呢?这个混合宏还没有准备好处理这种情况。对于这种情况,我还准备了超级通用的混合宏,这些混合宏就是规范名称

@mixin box-shadow ($string) {
  -webkit-box-shadow: $string;
  -moz-box-shadow:    $string;
  box-shadow:         $string;
}

这个混合宏只接受一个参数,任何我想给它的东西。所以用法可以是

/* Bad! doesn't work! */
.stack {
   @include box-shadow(
        1px 1px   0 rgba(0,   0,   0,   0.100),
        3px 3px   0 rgba(255, 255, 255, 1.0),
        4px 4px   0 rgba(0,   0,   0,   0.125)
   );
}

但这不起作用。其中的所有逗号都会让SASS感到困惑。它会认为您试图向一个只设置了接收一个参数的混合宏传递多个参数。您也不能只在尝试传递的值周围加上引号,这样也不起作用。答案是使用双括号技术

@include box-shadow(( whatever, you, want, just, one, param ));

另一件让我感到困惑的事情是尝试在值中使用变量,其中变量只是值的一部分。最基本的是,变量超级简单

$red: #F00;

.red {
   color: $red;
}

但我试图做的是

$path: "/images/";

body {             /* Bad! No! */
   background: url($path + texture.jpg);
}

为了使它工作,您必须使用哈希/括号的方式

$path: "/images/";

body {
   background: url(#{$path}texture.jpg);
}

// or

body {
   background: url($path + "texture.jpg");
}

还有一件可能令人困惑的小事。在进行嵌套时,&字符具有特殊的含义。它等于到该点为止的选择器。例如

a {
  color: red;
  &:hover {
    color: pink;
  }
}

变成

a { 
  color: red;
}
a:hover {
  color: pink;
}

您可能以前见过这样的示例。使用像这样的简单示例并不能完全说明问题,但无论如何,嵌套很快就会变得自然,您会喜欢它。

但回到那个&字符。

您**不需要**这样做

.module {
   & h3 {
   }
   & p { 
   }
}

这仅仅是因为嵌套而隐含的,您不需要在那里使用&。只有当它不是后代选择器(空格)时,才需要它。当您稍后在选择器中使用&时,事情可能会变得非常性感。例如,如果您使用Modernizr检测多个背景

body {
  .multiplebgs & {
  }
  .no-multiplebgs & {
  }
}

这为您提供了一种非常干净的分支,用于处理支持和不支持的情况,同时将代码逻辑地嵌套在body { }语句中。

那个该死的FTP工作流程

即使我已说服您在本地工作,使用版本控制,并使用预处理器,但部署问题仍然存在。如果您的工作流程是从实时编辑到现在在本地工作,那么您的工作流程效率实际上可能会倒退一步,当您想上线时,您必须手动将更改的文件上传到服务器。恐怕我无法为您提供一个完美的解决方案。

Nettuts用“完美的工作流程”来处理这个问题,但这依赖于一个GitHub提交后钩子,该钩子会命中一个执行`git pull`的PHP文件,这在我访问的任何服务器上都不起作用,并且据我了解,共享主机很少允许这样做。

这就是基于应用程序的云托管真正闪耀的地方。像Heroku(用于Ruby)或PHPFog(用于PHP)这样的应用程序可以完美地融入您的基于Git的版本控制工作流程。您可以设置一个命令用于推送到存储库,另一个命令用于部署上线,或者设置当您推送到存储库时自动上线。

但是,这些云主机并不适合所有人。当我做代理工作时,绝大多数工作只是在一些通用的共享主机上的网站。您始终可以在这些服务器上安装Git,然后在将内容推送到存储库后,SSH到服务器并从那里执行git pull。这更好,但仍然有点笨拙,并且需要使用命令行。

理想情况下,像Git Tower这样的应用程序可以管理您的Git存储库,**并且**处理FTP,根据命令上传已过期的文件。

对于那些坚持使用FTP4工作流程并且不害怕命令行的人,这个看起来很有希望。

其他CSS预处理器

正如我所说,我目前选择了SASS作为我的首选CSS预处理器。但是LESS和Stylus呢?

LESS是我尝试的第一个,老实说我仍然喜欢它。我非常喜欢您编写的所有类如何自动可重用为混合宏。像

.screen-reader-text {
   position: absolute;
   top: -9999px;
   left: -9999px;
}
label {
  .screen-reader-text;
}

这非常有用,并且比SASS更简洁。但是我被告知将类和混合宏的概念混合在一起从根本上是有缺陷的。我不确定是怎么一回事,但事实就是这样。如果有人愿意解释一下,我非常乐意倾听。

我对LESS的一个主要缺点是,当我仅仅使用标准的@keyframe动画语法时,就会出现错误。因此,我最终不得不将这些内容拆分到另一个文件中,但这些文件必须是.css,以避免触发错误,然后我也不能@import它们(从字面上包含内容),因为文件扩展名的问题。也许他们已经修复了,我不确定。

Stylus也很好,主要是因为它的灵活性。它不会像其他预处理器那样对您吹毛求疵。花括号和分号是可选的,而不是强制要求的。虽然Stylus很好用、功能强大且健壮,但我最终认为它背后的开发不够强大,无法让我产生信心。它主要是一个人(TJ Holowaychuk)在维护。

SASS最终胜出,因为它是最成熟的,最容易找到相关信息和帮助的,似乎拥有最活跃和最强大的开发团队,并且错误最少。

此处的教程和结语

仅供记录,我不会开始在我的基础CSS教程中加入SASS。CSS很可能比SASS更长寿。此外,我认为理解CSS比某种特定的预处理器方法重要得多。事实上,如果一个CSS新手问我他们是否应该在学习CSS的同时学习SASS,我可能会说不要。先学习CSS的工作原理,然后再看看预处理器如何帮助你。这与我对JavaScript和jQuery的感觉相反,我认为先学习jQuery是可以的。奇怪。

从本质上讲,我认为您应该了解编写真正优秀的CSS是什么样的。最终的CSS文件是什么样的。浏览器读取和处理以设置网站样式的实际文件。然后使用预处理器使最终的、绝妙的CSS文件更容易编写和维护。


1 是的,它内置了Subversion,但感觉有点不自然。如果您喜欢Subversion(当然可以,它很容易),我认为您最好使用Versions

2 除了像这样的小事情或在工作中我需要启动运行Python等的本地服务器的地方。但即使那样,我也很勉强。

3 在Wufoo,我们从使用PHP动态组合和压缩脚本切换到通过预处理器组合和压缩,这减轻了服务器负载,并实现了更高效的CSS压缩。

4 显然,我所说的FTP是指SFTP。