8

开始写 CSS 吧

 3 years ago
source link: https://yanhaijing.com/css/2014/03/26/starting-to-write-css/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

你是否觉得 CSS 不再跟以前一样了呢?最近几年成了热门话题,许多聪明的人也在谈论它。CSS 远不止是前端开发者应该用来美化网页的小玩意儿。我们关心性能,想要创作出更好的网站。

在这篇文章里,我会分享最近几个月学习 CSS 相关的知识和我个人对编写 CSS 代码确切的看法。作为程序员,我真的对每样东西的结构部分很感兴趣。我觉得编写 CSS 的方式应该改变并对此深入研究。我寻找好的处理方式,最佳准则(best principles)和新的工作流程(workflows)。

这篇文章就像是在 CSS 世界里旅行的总结。很多人说编写 CSS 不是真正的编程。我并不认同,它同样充满乐趣和挑战性。

CSS 预处理器(CSS Preprocessors)

94.jpg

当一个程序员开始写 CSS 时发生了什么 当一个程序员开始写 CSS 时发生了什么:你 -> 编写代码 -> 预处理器 -> CSS 代码 -> 网页

好吧,让我们面对它。这世上编写纯的 CSS 不是件有趣的事情。预处理器使用一些类似 CSS 语法,神奇地生成有效的 CSS 代码。在你和最终发送给浏览器的样式之间,它添加了一个中间层。这没有听起来那么坏,因为预处理器提供了一些真正实用的特性。

合并(Concatenation)

我认为能使你的文件合并在一起是最有价值的事情之一。我确信,你了解当在你的 .css 文件用 @import时,实际上告诉浏览器“麻烦你顺便也捎带这个文件”。 确实如此,发送新的请求,这有点不好,因为你可能会有非常多的文件。发送额外的请求会降低应用的性能。如果你使用 CSS 预处理器,这个问题将会解决。它们会很容易地把你所有的样式编译到单一的 .css 文件。

扩展 (Extending)

主要有两个 CSS 预处理器 —— LESSSASS。它们都支持扩展。没错,工作方式略有不同,不过想法(idea)是一样的。你写一个有一串属性的基本类(通常称作 mixin),之后把这些属性导入到另一个选择器。例如:

// less
.bordered(@color: #000) {
    border: dotted 2px @color;
}
.header { .bordered; }
.footer { .bordered(#BADA55); }

// compiles to
.header {
    border: dotted 2px #000000;
}
.footer {
    border: dotted 2px #bada55;
}

这里有个问题,如果你定义了一个没有参数的 mixin,也就是说像这样:

.bordered {
    border: dotted 2px #000;
}

它会原样编译到 CSS 文件里,不管你是否使用到。就像这样,因为这是有效的选择器。在 SASS 里,我们会多一点点灵活性。分别是 mixinsextendsplaceholders (如果你想了解它们准确的不同之处,我强烈推荐这篇文章。让我们看下 SASS 及其编译后的结果:

// sass
@mixin bordered($color: #000) {
    border: dotted 2px $color;
}
.header { @include bordered; }
.footer { @include bordered(#BADA55); }

// compiles to
.header {
    border: dotted 2px black; 
}
.footer {
    border: dotted 2px #bada55; 
}

看起来几乎和 LESS 相同,但如果我们看下第二个用例,定义一个占位符(a place holder):

// sass
%bordered {
    border: dotted 2px #000;
}
.header { 
    @extend %bordered; 
}
.footer { 
    @extend %bordered; 
}

// compiles to
.header, .footer {
    border: dotted 2px #000; 
}

有两个很好的事情发生。首先,这里不会编译 .bordered 类(there is no .bordered class compiled)。第二,SASS 合并了选择器,这让我们的 CSS 更短一些。

配置 (Configuration)

LESS 和 SASS 都支持定义变量。你可以稍后再访问这些变量,使用它们作为属性的值。

// sass
$brand-color: #009f0A;
...
h1 {
    color: $brand-color;
}

这是个好的特性,因为你可能会在同一个地方,存储一些像公司的颜色或网格宽度之类重要的东西。如果你想要修改,可以不用检查一边所有的代码。

另一个方便的用法是插入变量。下面的例子演示这种方法:

// sass
@mixin border($side) {
    border-#{$side}: solid 1px #000;
}
.header {
    @include border("left");
}

// compiles to
.header {
    border-left: solid 1px #000; 
}

反对预处理器 (Against the preprocessors)

  • 预处理器是一个工具,也就是说,你必须多做一件事,把它添加到把你的开发环境中。你可能想要把它整合进你的应用里,当然这需要额外编写代码。

  • 如果你不想让你的代码跟预处理器的弄乱,那么你很有可能需要一个监听工具。另一个用来监听你文件的工具,一旦文件有更新就会生成编译后的版本。如果是这样的话,那么每次当你开始开发项目的时候都要运行这个监听工具。也许你会优化这个过程所需的时间,但它还是需要你多留一份心。

  • 许多开发者总是只盯着他们的 .less 或者 .sass 文件。但编译后的文件才是重要的。你的 SASS 代码可能很优雅并优化过的,但这并不意味着你最后得到同样优美的 CSS 代码。你可能会有真正需要关心的特定问题。因此,定期地检查编译后的版本。

95.jpg

BEM 代表块 Block 元素 Element 修饰符 Modifier BEM代表块(Block),元素(Element),修饰符(Modifier)。

好吧,我找到一个可以玩的新工具。预处理器也许能够节省大量的时间,但是单独使用它们不能写出好的结构。我开始思考的第一件事是命名规范。让我们看下面 HTML 代码:

<header class="site-header">
    <div class="logo"></div>
    <div class="navigation"></div>
</header>

样式可能跟这个类似:

.site-header { ... }
.logo { ... }
.navigation { ... }

当然,这会奏效。但有个问题,阅读这个 CSS 你不能理解它,例如, logo 属于 header。你也许有另一个小的 logo 图片用在 footer。下一个逻辑步骤是写一个后代选择器。

.site-header .logo { ... }

然而使用这种选择器不是个好主意,因为这把样式紧绑到特定的标记层次(it tights styles to specific tags hierarchy)。如果我把 logo 移到 header 标签外面会怎样呢?这样式会失效。另一个你能做的是把 site-header 添加到 logo 类的名字中:

.site-header-logo { ... }

这很好,不言自明(self explanatory)。但这不是在所有的情况下都奏效。以后,在十二月份可能想要使用圣诞节版的 logo。那么,我不能写成:

.site-header-logo-xmas { ... }

因为我的逻辑是写一个选择器能够匹配嵌套在 HTML 里的标记。

BEM 是这种情况的解决方案。它意思是块(Block),元素(Element),修饰符(Modifier)和创建一些你可以遵循的规则。使用 BEM,我们小小的例子会变成这样:

.site-header { ... } /* block */
.site-header__logo { ... } /* element */
.site-header__logo--xmas { ... } /* modifier */
.site-header__navigation { ... } /* element */

也就是说,.site-header 是我们的块(our block)。logo 和 导航(navigation)这个块的元素(elements),logo 的 xmas 版本是修饰符(modifier)。也许这看起来简单,但这真的强大。一旦你开始使用它会发现让你更好的结构化。反对的理由主要是 BEM 的语法。没错,这看来确实有点难看,但我准备好对这个好系统的命名妥协。

(值得阅读:这里这里 )

OOCSS

96.jpg

面向对象的 CSS 面向对象的 CSS

我找到了 BEM 就能准确地命名我的类,然后就开始思考构造(composition)。也许我第一次阅读的文章是关于面向对象的 CSS。面向对象编程有时是关于添加抽象并且 CSS 能够支持它。是否使用预处理器,你都应该了解 OOCSS 。作为码农(coder),我发现这个理念真的跟平时编程很接近,例如 JavaScript 。这是两个主要原则(principles):

结构和表层分开 (Separate structure and skin)

让我们用下面的例子:

.header {
    background: #BADA55;
    color: #000;
    width: 960px;
    margin: 0 auto;
}
.footer {
    background: #BADA55;
    text-align: center;
    color: #000;
    padding-top: 20px;
}

这里有些样式是重复的。我们可以把它们提取到另一个类,如下:

.colors-skin {
    background: #BADA55;
    color: #000;
}
.header {
    width: 960px;
    margin: 0 auto;
}
.footer {
    text-align: center;
    padding-top: 20px;
}

这样,我们就有了可扩展的 colors-skin 对象。HTML 代码也许跟下面的类似:

<div class="header colors-skin"> ... </div>
<div class="colors-skin"> ... </div>
<div class="footer colors-skin"> ... </div>

这种改变有几个好处:

  • 我们有一个可以使用多次的类。
  • 如果我们需要修改,只需修改一处。
  • 我们移除了 CSS 文件里的重复项,这让文件更小。

容器和内容分开 (Separate container and content)

这里的理念是,不管每个元素放在哪里,都应该被应用同一种样式。因此,你应该避免跟下面类似的选择器用法:

.header .social-widget {
    width: 250px;
}

这是因为如果你把 .social-widget 移到 .header 容器(container)外面,宽度(width)就会不相同。一般来说这不是好的做法,尤其是给整个页面到处都使用的部分添加样式。这个原则鼓励使 CSS 模块化,我强烈建议利用充足的时间尝试下。就我个人而言,遵守这个原则意味着能够编写出更好的 CSS。

框架 (The framework)

如果你在 GitHub 打开 OOCSS repository 会看到一个框架。是的,这个框架用到面向对象的 CSS 理念,并且有一堆很酷的组件可以立即使用(ready-to-use)。某些时候我并不喜欢框架。如果你思考一下的话会发现,framework 这个单词有部分 frame 和 work,你确实在条条框框(frame)里工作(work)。你确实要对框架妥协并且必须遵守它的规则。我更愿意使用微框架(micro-frameworks)或者只提供最基本特性的工具。当然我不是打算重新发明轮子,但我总是试着在两者之间取得平衡。经常这样,现成可用(ready-to-use)的解决方案会带来混乱复杂的系统。我的建议是,干一件事只为了一个特定的目的。如果你可能多地包含方方面面,你的下场将会是……你懂的,一个框架。

但是,我强烈推荐你查看下 OOCSS 框架。这是一个独特的知识(It’s an unique piece of knowledge),也许会满足你的需求。Nicole Sullivan 托管这个 repository (仓库)。她是 OOCSS 的创始人(She is a pioneer in OOCSS),如果你有空的话我建议你查看下这个 presentations/talks

SMACSS

97.jpg

可量化和模块化 CSS 架构 Scalable and Modular Architecture for CSS 可量化和模块化的 CSS 架构

另一个流行的理念是 SMACSS。SMACSS 表示可量化(Scalable)和模块化(Modular)的 CSS 架构。Jonathan Snook 为 CSS 开发者介绍了风格指南(introduces something like style guide for the CSS developers)。这个想法是把你的应用分成以下几种类型:

  • 基本(Base)—— 为一些简单的选择器设置默认的基本样式。例如 clearfix (清除浮动)。
  • 布局(Layout)—— 定义网格(grids)。
  • 模块(Module)—— 一组元素组合成模块。例如 header 和 sidebar。
  • 状态(State)—— 包括了元素不同的状态。如果特定的对象是隐藏的,点击的(pressed),扩展的(expanded)等等……则定义相应的规则。
  • 主题(Theme)—— 更多地面向视觉部分。跟状态类型相似。 我没有使用 SMACSS 的经验,但它非常受欢迎,并确实提倡了好的想法。它更像是一个理念而不是框架,这非常好。因此,你不会受严格的规则,类或者是组件( components)束缚。

原子设计 (Atomic design)

98.jpg

原子设计 原子(Atoms) -> 分子(molecules) -> 组织(organisms) -> 模板(Templates) -> 网页(Pages)

了解 OOCSS 和 SMACSS 之后我寻找一个恰当的象征(metaphor),很快我看到了 Atomic Design 这篇文章,很好地展示 原子设计( Atomic Design) 这个好的理念。作者是 Brad Frost,是个知名的 Web 开发者,主要从事自适应式(responsive)和移动终端方面的工作。

这个理念真的很有趣。效仿一些化学技术,物质的基本单位是原子。Brad 把这移到 CSS,我们的网页是由原子构成的。一个原子是这样的:

<label>Search the site</label>
<input type="text" placeholder="enter keyword" />

也就是说,原子包含 DOM 元素一些基本的样式。例如调配颜色(color palette),字体大小或者转换(transitions)。稍后这些部分会合并成一个分子(molecules)。例如:

<form>
    <label>Search the site</label>
    <input type="text" placeholder="enter keyword" />
    <input type="submit" value="search" />
</form>

这样 form 元素包含了几个原子。像这样的抽象化带来灵活性,因为我们也许会用同样的原子构建另一个分子。这样(Together with that),我们能在不同的地方(contexts)重复使用同样的 form

Brad 并没有止步于此。分子构成了组织(organisms)。按照同样的方法,我们可以写成如下,把它称作组织(organisms):

<header>
    <div class="logo">
    <nav>
        <ul>
            <li><a href="#">Home</a></li>
            <li><a href="#">About</a></li>
            <li><a href="#">Contacts</a></li>
        </ul>
    </nav>
    <form>
        <label>Search the site</label>
        <input type="text" placeholder="enter keyword" />
        <input type="submit" value="search" />
    </form>
</header>

这个理念的下一个是模板(templates)。这没有跟化学直接相关,而是放到 Web 环境中(web context)。一旦我们开始合并不同的组织,就是在构造模板。之后这些模板形成了最终的网页。

你可能已经使用相似的方法开发你的应用软件。然而,以合理的方式命名会带来好的架构。你和所有你的团队队员在开发中会明白一些事情。把一件东西分成原子和分子是挺重要的一部分,因为这会改善 Web 应用程序的开发过程和维护。

OrganicCSS

99.jpg

原子设计 有机的 CSS Organic CSS

几个月前我写了一篇关于 Organic 的文章。这是一个很小的 JavaScript 应用程序框架。它更像是设计模式,我个人很喜欢它。我甚至在几个项目里使用了 Organic 并且它干得非常好。如果你对它感兴趣,我强烈建议你阅读这篇博文

当我看 Brad Frost 的文章时,我已经对相似的理念非常熟悉,因为我了解 Organic 。Brad 的 Atomic Design 十分出色,但我决定更进一步,基于原子设计(Atomic Design)理念试着写自己的微框架。我选择 SASS 作为预处理器并在 Github 创建了仓库

原子 (Atoms)

让我们从框架最小的部分开始 —— 原子。在维基百科的定义是 *原子是一种元素能保持其化学性质的最小单位。*。在 CSS 的环境(context)中,我认为是一个属性和它的值。例如:

margin-top: 24px;

添加原子只是直接在类里面写样式,这种方式不是我想要的。因此如果写成下面这样:

body {
    margin-top: 24px;
}
header {
    margin-top: 24px;   
}

预处理器就会保持这个样子。我想要的最后结果是:

body, header {
    margin-top: 24px;
}

SASS 使用占位符(place holders)实现这个效果。也就是说:

%margin-top-24 {
    margin-top: 24px;
}
body {
    @extend %margin-top-24; 
}
header {
    @extend %margin-top-24; 
}

因此,我必须使用占位符(placeholders)。这也就意味着我必须有大量预定义的并且我能使用的占位符(placeholders)。就在那时,我决定这个框架将只包含原子。也许还有一些类似通常的 reset.css,网格定义等等。我想要为 CSS 开发写一些基本的东西(I wanted to write something which acts as a base for the CSS development)。也许一个又一个项目之后我将会看到一些可以放进核心的模式,但刚开始我想保持 repo(仓库)整洁简单。为了使一些东西始终如一的,我为定义原子创建 mixin。如下:

@include define-atom("block") {
    display: block;
}
@include define-atom("font-family") {
    font-family: Georgia;
}

使用这种方式我创建了一堆容易应用到每个项目的原子。你可以在这里查阅。我从别的框架里使用了一些最佳做法,所以并不是全归功于我。这里是个在分子里混合原子的 mixin:

@mixin header { /* <- molecule called 'header' 称作 `header` 的分子*/
    @include atoms((
        block,
        clearfix,
        font-family
    ));
}

分子 (Molecules)

分子是需要样式的 DOM 元素,但是没有子代。或者是没有直接联系的子代。例如 <img src="logo.jpg" /> 可以是分子。如果你觉得在网页里识别出分子,只需思考下什么是有原子构成的。如果一些元素是由其他分子构成的,那么很可能是一个(细胞器)。下面几行展示的是如何定义一个分子:

@mixin login-box { 
    @include atoms((
        block,
        font-size-20,
        margin-top-23,
        bold
    ));
}

我面前有些有趣的东西。让我们看下 body 标记。这是什么?是一个分子或者其他东西吗?没错,它通过原子需要一些样式,但通常包含了其他分子。它应该是其他东西。我做出决定,CSS 应该是主角。也就是说,如果 body 标记需要一些原子提供样式,那就是分子,理论上,我不该给它附加上任何其他的分子。这看起来有点不切实际,但在大多数情况下,这会阻止你使用后代选择器,这个好兆头。

细胞器 (Organelles)

一旦你能够识别出哪个 DOM 元素是分子,你将会知道什么细胞器。例如,典型的 form 元素是一个细胞器的好例子。它包含了分子像 labelinput 或者 textarea

.login-form {
    @include label;
    @include input;
    @include textarea;
}

这个框架中,细胞器(Organelles)是第一个跟当前应用紧密相关的 。原子和分子在不同项目中会有所改变,而细胞器却不会。

更多的抽象 (More abstractions)

你也许经常想要在其他地方合并几个细胞器。如果是这种情况,添加其他抽象:

Atom → Molecule → Organelle → Cell → Tissue → Organ → Sys → Organism

你选择什么来让你的 CSS 结构化,这是个问题。目前为止,我只在一个项目里使用过 OrganicCSS,但我能说,它使项目变清晰了。我把不同的元素放在它们各自的目录(文件夹)里并像这样命名类,例如,分子在一个“molecules”目录(文件夹),里面的文件命名为“header_molecule.scss”我才能容易地找到正在编写的是哪一个。例如,如果有一个叫 header 的细胞器,我简单地改成 o-header。然后,当我看 HTML 代码时可以是了解到,这个元素的 CSS 样式文件在 organelles 文件夹。

这个一个有趣的旅行。我不知道是否会在将来使用 OrganicCSS,但这不是重点。我学到的东西才是重要的。我知道必须改变我的 CSS 开发过程,我做到了。我确信我们应该谈论更多 CSS 的结构。如你所见,在文章里我们有很多好的资源。我们只是必须找到它们,学习它们干了什么和如何运行的。只有我们能决定是否使用它们。更好的是,当你了解了整个项目才能创作出能更好满足需求的东西。

  • 原文:http://funwo.tk/2013-09-08-starting-to-write-css-cn.html
  • 英文:http://davidwalsh.name/starting-css

原文网址:http://yanhaijing.com/css/2014/03/26/starting-to-write-css/

微信公众号:颜海镜关注微信公众号 颜海镜微信支付二维码赞赏支持 微信扫一扫

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK