天天看点

[译] 再谈 CSS 中的代码味道再谈 CSS 中的代码味道

<b>本文讲的是[译] 再谈 CSS 中的代码味道,</b>

代码味道,也被称作代码异味,在计算机编程领域,指程序源代码中的任何 有可能预示着更深层次问题 的征兆。按照 Martin Fowler 所说的,「代码味道是一种表面迹象,通常对应着系统中的深层次问题」。另外一种看待代码味道方式是关于准则和质量:「代码味道是代码中某种特定的结构表明了 违反了基本的设计准则 并且对设计质量产生负面影响」,代码味道通常不是 bug —— 它们不是技术性的错误 并且不会当时就对程序的功能产生阻碍。相反的,它们预示着可能拖慢开发的设计缺陷 或者增大未来出现 bug 或者故障的风险。代码异味是导致技术债的因素的指示器。Robert C. Martin 将一系列代码味道称作软件技艺的「价值体系」。

因此, 它们并不总是技术上的错误, (不过)它们可作为一个不错的检验方法。

希望我可以把这第一条讲得细致又简洁:我早就被告知 <code>@extend</code> 的副作用和陷阱,我也会积极地认为它是代码味道。它也并不绝对的不好,虽然通常是的。对它应该持怀疑态度。

<code>@extend</code>的问题是多方面的,可以概括如下:

它对性能的影响事实上比 mixins 更严重。 Gzip 偏爱重复性的内容,所以具有更高重复性 CSS 文件 (如 mixins) 取得更高的压缩量。

它移动你的代码库的顺序。 在 CSS 中原始的顺序至关重要,所以应该总是避免在你的项目中移动选择器的位置。

它使文件晦涩难懂。 <code>@extend</code> 在你的 Sass 中隐藏了很多复杂的东西,你需要逐步的拆开,然而在你审阅文件的过程中,这个复杂的 class 方法将所有的信息置于焦点。

扩展阅读:

<a href="https://link.juejin.im/?target=https%3A%2F%2Fcsswizardry.com%2F2016%2F02%2Fmixins-better-for-performance%2F" target="_blank">Mixins Better for Performance</a>

<a href="https://link.juejin.im/?target=https%3A%2F%2Fcsswizardry.com%2F2014%2F11%2Fwhen-to-use-extend-when-to-use-a-mixin%2F" target="_blank">When to Use <code>@extend</code>; When to Use a Mixin</a>

<a href="https://link.juejin.im/?target=https%3A%2F%2Fcsswizardry.com%2F2014%2F01%2Fextending-silent-classes-in-sass%2F" target="_blank">Extending Silent Classes in Sass</a>

另外一个 Sass 让人恼火的地方就是在你的类上使用 <code>&amp;</code> 连接字符串,例如:

编译成:

显而易见的好处是简洁:事实上我们只用写一次命名空间 <code>foo</code> 确实是很 DRY (Don't repeat yourself)。

一个不那么明显的缺点是,字符串 <code>foo-bar</code> 现在在源代码中不存在。搜索代码库查找 <code>foo-bar</code> 只会返回 HTML 中的结果(或者是编译过的 CSS 文件,如果你已经把它纳入到你的项目中)。想要在源代码中定位 <code>.foo-bar</code> 的样式变得非常困难。

我不仅仅是 CSS 全称写法的爱好者:总的来说,相比于重新为元素命名一个类,我更喜欢查找到它原有的类名,所以可查找性对我来说很重要。如果我加入一个项目大量使用 Sass 的字符串连接,追踪查找通常都会是非常艰难的。

…当你可能想要表达的意思是:

…这是另一种代码味道的实践。当我看到前者被使用的时候,很少是开发者实际上想要的:几乎任何时候他们真正的意思是后者。后者 仅仅 设置或者改变背景色,而前者将会也重置或者复原背景图、背景位置、背景链接等。

在 CSS 项目中看到这样的形式立即提醒我,我们终究会因为它遇到问题。

关键选择器是获得目标或者是被赋予样式的选择器。它通常在左花括号 (<code>{</code>) 前面的内容,但也并不总是。在下面的 CSS 中:

…关键选择器是:

<code>.foo</code>,

<code>.bar</code>,

<code>a</code>,

<code>.btn</code>.

除了很多普遍存在的相当糟糕的 CSS,我在这里想指出的问题是 <code>.btn</code> 被定义了很多次,这告诉我:

没有遵循 Single Source of Truth 告诉我按钮看起来是什么样的;

有很多变化 意思是 <code>.btn</code> 类有很多潜在的不同的样式,所有的这些都是通过 CSS 的可变性造成的。

一看到像这样的 CSS,我就意识到在按钮上做任何工作都将会有很大的影响,追踪按钮样式到底来自哪里将会非常困难,并且任何位置的改动都有可能对其他地方造成影响。这就是 CSS 可变性的关键性问题之一。

使用 BEM 的命名形式以便创建全新的类名称以应对这些改变,例如:

每个只有一个关键选择器。

在一个和上面相似但是稍微不同的场景里,类名出现在另一个组件的文件中预示着代码味道。

如果我们需要给某些因为它们的上下文的不同而加样式,我们应该把这些额外的样式加到哪呢?

要加样式的对象所在的文件里?

控制该对象上下文的文件里?

让我们假设我们有如下 CSS:

<code>.modal .btn {}</code> 应该放在哪?

它应该 在 <code>.btn</code> 所在的文件中。

我们应该尽量将我们的样式基于主题(例如:关键选择器)分组。在这个例子中,主题是<code>.btn</code>:这才是我们真正关心的。<code>.modal</code> 只不过是 <code>.btn</code> 的上下文,所以我们根本没给它添加样式。为此,我们不应该将 <code>.btn</code> 的样式移出到另外的文件中。

我们不这样做简单的因为它们是并列的:将所有按钮的上下文放在一处更方便。如果我想得到项目中所有按钮样式的概观,我仅仅需要打开 <code>_components.buttons.scss</code>,而不是一堆其他的文件。

这样做使得将所有按钮的样式移入另外一个新项目变得更容易,更重要的是这样做提前读懂变得容易。我相信你们都对这种感觉相当熟悉,就是文本编辑器中打开十余个文件,而仅仅试图修改很小的一处样式。这是我们能够避免的。

将你的样式基于主题的分组到文件中:如果是给按钮的样式,无论它是什么样的,我们应该让它在 <code>_components.buttons.scss</code> 文件中。

一个简单的经验法则就是,问问你自己这样的问题,我是在给 x 添加样式还是 y?如果答案是 x,那么你的 CSS 应该在 <code>x.css</code> 文件中;如果答案是 y,它应该在 <code>y.css</code> 中。

事实上很有趣的,我根本不会这样写 CSS —— 我使用 BEM mix —— 但是这是另一个不同问题的答案。不是像下面这样:

而是像这样:

第三,新的类名称将会应用于 HTML 上,像这样

这被叫做 BEM mix,我们介绍第三种新的类名称来指向属于 modal 的按钮。这样避免了它在哪里的问题,它通过避免嵌套,减少了名称唯一性的问题,同时通过重复 <code>.btn</code> 类避免可变性带来的问题。完美!

我会说 CSS <code>@import</code> 不仅仅是代码味道,它的的确确是坏的实践。它推迟 CSS 文件的加载(性能的决定性因素),比实际的需要加载的更晚,造成严重的性能下降。下载具有<code>@import</code> 的 CSS 文件的(简化的)工作流程看起来有点像:

获取 HTML 文件,这个 HTML 文件中请求 CSS 文件;

获取 CSS 文件,这个 CSS 文件请求另外一个 CSS 文件;

获取最后一个 CSS 文件;

开始渲染页面。

如果我们得到 <code>@import</code> 的内容,将其压入一个单独的文件,工作流程看起来将会是这样:

获取 CSS 文件;

如果我们不能将所有的 CSS 放入一个文件(例如我们链接了谷歌字体),那么我们应该在 HTML 中使用两个 <code>&lt;link /&gt;</code> 元素,而不是使用 <code>@import</code>。这可能让人感觉有点不那么压缩(但也是更好的方式处理所有 CSS 文件的依赖),它对于性能仍然是比较友好的:

获取所有的 CSS 文件;

所以我们在这里对我先前那篇关于代码味道的文章做了几点添加。这些是我已经看到的并且忍受着的几点:希望现在你也可以避开他们。

<b></b>

<b>原文发布时间为:2017年3月10日</b>

<b>本文来自云栖社区合作伙伴掘金,了解相关信息可以关注掘金网站。</b>