阅读 764

【译】如何更好的编写CSS

原文:How to get better at writing CSS

作者:Thomas Lombart

译者:JeLewine

废话不多说,咱们就开门见山吧:想写出优质的CSS代码将会是非常痛苦的。很多开发者都不想做CSS开发。我可以做你想做的一切,但是,除了CSS

当我在构建应用时,CSS是我挺讨厌的部分。但你无法摆脱它,对吧?我的意思是,正是因为我们如此的专注于用户体验和设计,所以现在我们才不能跳过这一部分。

在开始一个项目时,一切都很正常。你有一些CSS选择器:.title input #app,这看起来非常的简单。

但是当你的应用变得越来越大时,它就开始变的越来越糟糕了。你对CSS选择器感到困惑。你发现你写的像div#app .list li.item a诸如此类的东西,自己在一遍又一遍地在重复相同的代码。你把所有代码都放在文件末尾,因为你根本就不在乎。CSS像一坨shit。然后你要狗带了:500行的CSS完全没法维护。

我今天有一个小目标:让你更好的去编写CSS。我想让你回首看看自己的旧项目并发出感慨:oh,boy,我怎么能写这么一坨东西?

好吧,你可能会想,你说的有道理。但是CSS框架呢?这就是他们的用法,不是吗?这就是我们编写好CSS代码的方法。

是的没错,不过这样还是会有一些缺点:

  • 它往往会带来平凡的设计
  • 想要定制或跳出CSS框架会变的困难
  • 在使用它们之前,你必须先学习它们

不过毕竟,你已经开始在看这篇文章了。这一定是有原因的,不是吗?所以,不用多说了,让我们开始学习如何更好的编写CSS吧。

注意:这不是关于如何设计优雅应用程序的文章。它是关于学习如何编写和组织可维护的CSS代码的。

SCSS

在这篇文章里我将会用SCSS作为例子。

SCSS是一个CSS的预处理器。简单来说,它是一个CSS的超集:他为CSS添加了一些很酷的功能,例如变量,嵌套,导入和mixins。

我将先谈谈我们立即会使用到哪些功能。

变量

通过SCSS,你可以使用变量了。它带来的主要好处就是可复用性。我们假设你的应用有一组颜色。你的主色调是蓝色。

所以你的应用到处都是蓝色:按钮的背景颜色,标题的颜色,链接。蓝色无处不在。

突然之间,你不喜欢蓝色。你更喜欢绿色了。

  • 没有变量:更改所有使用了蓝色的地方
  • 使用变量:只需更改变量
// 声明变量
$primary-color: #0099ff;
// 引入变量
h1 {
  color: $primary-color;
}
复制代码

嵌套

你还可以使用SCSS来嵌套代码。看一下下面的例子:

h1 {
  font-size: 5rem;
  color: blue;
}
h1 span {
  color: green;
}
复制代码

可以变成下面这样:

h1 {
  font-size: 5rem;
  color: blue;
  
  span {
    color: green;
  }
}
复制代码

更具有可读性,不是吗?使用嵌套来编写复杂选择器所花费的时间更少。

局部文件和引入

出于可维护性和可读性方面的考虑,我们不可能将所有代码保存在一个大文件中。在试验或构建小型应用程序时,这么做也许可以满足你的需求,但在更专业的情况下...请不要这么做。不过幸运的是,SCSS允许我们这样做。

您可以通过使用前置下划线命名文件的方式来创建局部文件:_animations.scss_base.scss_variables.scss等。

至于引入,我们可以使用@import命令。例如,下面这样是你可以做的:

// _animations.scss
@keyframes appear {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
// header.scss
@import "animations";
h1 {
  animation: appear 0.5s ease-out;
}
复制代码

看到这里,你可能会认为这里是不是搞错了。应该是_animations.scss而不是animations

不。当你用这种方式命名时,scss可以很聪明的知道你正在讨论一个局部文件。

以上就是我们所需要了解到的变量嵌套局部文件引入。SCSS还有一些其他功能,像是mixins,继承指令(@for@if,...)之类的,不过我今天不会在这里介绍他们了。

如果你想了解更多的信息,可以查看他们文档。他们写的很不错,非常容易理解。

【译者注:这是scss中文文档的地址】

组织CSS代码:BEM方法论

我已经记不清有多少次在我的CSS课程里用到这些名称了。你懂的:.button.page-1.page-2.custom-input

我们其实经常不知道该如何去命名。然而这是非常重要的。如果你正在构建一个应用程序,并且由于某些原因决定将其搁置几个月,该怎么办?或者更糟糕的是,如果有人要交接该项目怎么办?如果你的CSS代码没有一个正确命名,那么很难一目了然地知道你在说什么。

BEM帮我们解决了这个问题。BEM是一种命名约定,代表着块元素修饰符【译者注:原文为Block Element Modifier。在中文前端圈内发现大部分文章都将block直译为"块",其实译者个人觉得翻译为"模块"可能会让人更好理解一点。不过本文还是选择和已有译法保持一致】。

这种方法可以使我们的代码结构化,更加模块化和可复用。现在让我来解释什么是块,元素和修饰符。

我们可以把“块”视为组件。你还记得小时候玩的乐高积木吗?【译者注:小时候没玩过,现在我也玩不起...】ok,让我们回到过去。

你会如何建造一个简单的房子?你需要一个窗户,一个屋顶,一扇门,一些墙壁,就是这样。那些是我们的。他们各自有各自的作用。

**命名:**块名称:.block 样例:.card.form.post.user-navigation

元素

现在,你将如何用你的乐高去搭一个窗户呢?这发现其中也许有一些看起很像边框,当你把四个边框组装在一起时,一个窗户就搭好啦。那就是我们的元素。它们是“块”的一部分,它们是构建“块”的必要条件。但是,当它们离开块时就没有用了。

**命名:**块名称 + _ + 元素名:.block_element 样例:.post_author.post_date.post_text

修饰符

现在你已经搭起了一个窗户,不过也许你想要的是一个绿色的或小的。这些就是修饰符。它们是“块”或“元素”上的标志,它们用于改变行为和表现等。

**命名:**块名称或元素名 + - + 修饰名:.block_element-modifier, .block-modifier 样例:.post-important.post_btn-disabled

一些笔记

  • 当您使用BEM时,你为类命名,也只能是为类命名。没有ID,没有标签。只有
  • 块/元素可以嵌套到其他块/元素中,但它们必须要能完全独立。记住这个词:独立。因此,请不要因为你想将按钮放在标题下就将margin写在按钮上,否则您的按钮将与您的标题完全绑定。请改用其他公用类来代替这个操作。
  • 是的,你的HTML文件将会过载。但不要担心,与BEM带给您带来的好处相比,这是一个小小的缺点。

一个例子

下面是一个对你的小练习。转到你最喜欢或最常用的网站,并尝试使用BEM。

例如,下面就是我在Google商店中的想象:

谷歌商店BEM

轮到你了。要保持好奇人们如何可以做的更好。你必须自己去搜索,尝试和创造,这样才能更好的贴合你自己的需求。

将它们合在一起

你会发现下面的一些例子充分的展示了BEM的功力。

<!--html-->
<div class="post">
  <span class="post__author">Thomas</span>     
  <span class="post__date">3 minutes ago</span>
  <p class="post__text">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Laboriosam sit voluptatem aut quis quisquam veniam delectus sequi maxime ullam, inventore blanditiis quia commodi maiores fuga, facere quaerat doloremque in. Nisi!
  </p>
</div>

<div class="post mt-large post--important">
  <span class="post__author">Thomas</span>     
  <span class="post__date">2 hours ago</span>
  <p class="post__text">
    Voluptatem incidunt autem consequatur neque vitae aliquam, adipisci voluptatum. Ipsum excepturi dolores exercitationem rem ab similique consequatur nesciunt, tempora aut vel unde.
  </p>
</div>

<!--SCSS-->
.post {
  display: inline-block;
  padding: 1rem;
  background-color: #ccc;
  border: 1px solid #222;
  border-radius: 5px;
  
  &--important {
    background-color: yellow;
  }
  
  &__author {
    font-size: 1.2rem;
    font-weight: bold;
    color: blue;
  }
  
  &__date {
    float: right;
  }
  
  &__text {
    line-height: 2rem;
    font-size: 1.3rem;
  }
}
复制代码

样例1

<!--html-->
<div>
  <button class="btn">
    Click me
  </button>
  <button class="btn btn--danger">
    Danger
  </button>
  <button class="btn btn--success">
    Success
  </button>
  <button class="btn btn--small">
    Small
  </button>
  <button class="btn btn--big">
    Big
  </button>
  <button class="btn btn--border">
    Border
  </button>
</div>

<!--SCSS-->
.colors {
  font-size: 1.5rem;
  font-family: sans-serif;
}

.btn {
    background-color: #FF6B93;
    color: #fff;
    text-transform: uppercase;
    padding: 1.5rem 2.5rem;
    border-radius: 4px;
    transition: all .2s;
    font-size: 1.3rem;
    border: none;
    letter-spacing: 2px;
    cursor: pointer;
  
  &:hover {
    background-color: #D15879;
  }
  
  &:focus {
    outline: none;
  }
  
  &--danger {
    background-color: #FF3B1A;
    
    &:hover {
      background-color: #D43116;
    }
  }
 
  &--success {
    background-color: #00D123;
    
    &:hover {
      background-color: #00AB1D;
    }
  }
  
  &--small {
    padding: 1rem 2rem;
    font-size: 1rem;
  }
  
  &--big {
    padding: 1.8rem 4.5rem;
    font-size: 1.7rem;
  }
  
  &--border {
    background-color: #fff;
    color: #FF6B93;
    border: 1px solid #FF6B93;
    
    &:hover {
      background-color: #FF6B93;
      color: #fff;
    }
  }
}
复制代码

样例2

【译者注:原文是在文章中插入了codepen。为了方便阅读,直接对输出结果进行了截图。有兴趣的读者可以直接访问这两个地址:样例1样例2

组织CSS文件:7-1模式

你坚持看到这儿了?优秀! 现在让我们看看如何组织CSS文件。这部分将真正帮助你提高工作效率,并能够让你立即找到必须要修改的CSS代码的位置。

为此,我们将了解7-1模式。

你可能会想这是个什么玩意【译者注:711便利店?233】。

相信我,这很简单。你只须遵守下面2条规则:

  1. 将所有的局部文件写入7个不同的文件夹中。
  2. 将它们全部导入位于根级别的一个main.scss文件中。

就是这样。

7个文件夹

  • base:在这里,把所有的脚手架代码都放进去。通过脚手架,我指的是每次启动一个新项目时要写的所有CSS代码。例如:排版规则、动画、公用(公用类,我指的是margin-right-largetext-center,……之类的类)。
  • components:这里的名称是明确的。此文件夹包含用于构建页面的所有组件,如按钮,表单,swipers,弹出窗口等。
  • layout:用于布局页面的不同部分。也就是说,页眉,页脚,导航,自己的网格等等。
  • pages:你有时可能会有一个页面会具有一些自己特定的样式。将它们与那些通用的样式分开,然后将它们放在pages文件夹中。
  • themes:如果你的应用有不同的主题(黑暗模式,管理员模式等),请将它们放在此文件夹中。
  • abstracts:将所有函数与变量和mixin一起放在这里。
  • vendors:现在有什么项目是没有依赖外部库的?在vendor文件夹中放入所有不依赖于你的文件。你可能希望在此处添加Font Awesome文件,Bootstrap和类似的东西。

主文件

在这里导入你所有的partials。

@import abstracts/variables;
@import abstracts/functions;
@import base/reset;
@import base/typography;
@import base/utilities;
@import components/button;
@import components/form;
@import components/user-navigation;
@import layout/header;
@import layout/footer;

...
复制代码

是的。这看起很庞大。不过我知道你会这么想,这种架构适用于更大的项目,而不是小的。这里有一个适用于较小项目的版本。

首先,你不需要vendors文件夹。只需将所有外部CSS代码放置在头文件中的链接标签中即可。然后你可以跳过themes文件夹,因为你的应用可能只有一个主题。最后,你的页面不会有很多特定的样式,所以你也可以跳过pages这个页面。太好了,只剩下4个文件夹了!

接下来,你又两个选择:

  1. 你希望你的CSS代码组织遵循7-1模式,因此你保留了abstactcomponentslayoutbase
  2. 你更喜欢有一个大文件夹,把所有的局部文件和你的main.scss文件放在一起。所以你会产生以下类似的东西:
sass/
  _animations.scss
  _base.scss
  _buttons.scss
  _header.scss
  ...
  _variables.scss
  main.scss
复制代码

这完全取决于你自己。

你把我说服了!但是我该怎么用呢?我的意思是,浏览器并不支持SCSS,不是吗?

说的好!现在到了我们的最后一步了。我们将学习如何将SCSS文件编译成CSS。

从SCSS到CSS

为此,你需要先安装Node.jsNPM(或Yarn)

我们将使用一个名为node-sass的包,它能够帮我们将.scss文件编译为.css文件。

它的CLI(命令行界面)相当容易使用:

node-sass <input> <output> [options]
复制代码

node-sass提供了多种选项,不过我们只需要两个就够了:

  • -w: 观察目录或文件。这意味着node-sass能够观察到代码中的任何更改。一旦更改发生时,它会自动编译为CSS。 这在开发时非常有用。
  • --output-style:CSS文件的输出模式是什么。它可以是以下值之一:nested|expanded|compact|compressed。我们将使用它来构建你的CSS文件。

如果你是一个有好奇心的人(我希望你是,开发人员应该保持好奇!),可以到这里查看完整的文档

现在我们已经知道了我们将使用哪些工具。接下来的事就非常简单了。只要跟着下面的步骤走:

  • 创建你的项目:mkdir my-app && cd my-app
  • 初始化:npm init
  • 添加node-sass库:npm install node-sass --save-dev
  • 创建你的文件夹,你的index.html和你的main.scss文件:
touch index.html
mkdir -p sass/{abstracts,base,components,layout} css
cd sass && touch main.scss
复制代码
  • 修改在package.json中你的脚本命令:
{
  ...
  "scripts": {
    "watch:scss": "node-sass sass/main.scss css/style.css -w",
    "build:scss": "node-sass sass/main.scss css/style.css --output
style compressed"
  },
  ...
}
复制代码
  • 将包括那些已编译的CSS文件的引用链接添加到你的index.html文件的head标签中:
<!DOCTYPE html>
<html lang=”en”>
<head>
  <meta charset=”UTF-8">
  <meta name=”viewport” content=”width=device-width, initial-scale=1.0">
  <meta http-equiv=”X-UA-Compatible” content=”ie=edge”>
  <link rel=”stylesheet” href=”css/style.css”>
  <title>My app</title>
</head>
<body>
  <h1 class=”heading”>My app</h1>
</body>
</html>
复制代码

就这样,已经可以跑起来了!当你开始coding并在浏览器中打开index.html时,记得运行npm run watch:scss。如果你想要压缩你的css文件,跑一下npm run build:scss就好了。

添加热更新

你可能在开发中更希望通过热更新来提高效率,而不是每次都要手动重载index.html文件。

只要跟着以下几个简单的步骤:

  • 安装live-server包:npm install -g live-server。注意:这是一个全局
  • 添加npm-run-all包到你的项目依赖中:npm install npm-run-all --save-dev。它能够让你同时运行多个脚本命令。
  • 添加下面的命令到package.json中:
{
  ...
  "scripts": {
    "dev": "npm-run-all --parallel liveserver watch:scss ",
    "liveserver": "live-server",
    "watch:scss": "node-sass sass/main.scss css/style.css -w",
    "build:scss": "node-sass sass/main.scss css/style.css --output-style compressed"
  },
  ...
复制代码

现在,当你运行npm run dev时,你可以立即看到你的修改,而且无需手动重载任何内容。太棒了,不是吗?

不过你知道更棒的是什么吗?为了方便你快速上手,我为此建了一个repo

如果你想要知道我是如何将这些技巧应用到我的项目中的,可以查看这个repo这里是演示结果。我希望你可以通过这个例子拥有更深的理解。

这就是今天要说的一切!现在,你已经做好了编写可维护,模块化和可复用的CSS代码的准备。我希望你喜欢这篇文章。如果是这样的话,请随时在评论中给我反馈。那么,下次再见啦!

关注下面的标签,发现更多相似文章
评论