如何使用Sass和SMACSS维护CSS

本文由大漠根据Ben Smithett的《How to Scale and Maintain Legacy CSS with Sass and SMACSS》所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:http://webuild.envato.com/blog/how-to-scale-and-maintain-legacy-css-with-sass-and-smacss/,以及作者相关信息

——作者:Ben Smithett

——译者:大漠

我们一直以来都是SMACSS的忠实粉丝,然而一个纯SMACSS方法最适合于一个全新的项目中的普通CSS。我们的市场网站,我们使用了Sass编写样式,而且里面还有好几年的CSS遗留物。

我们最近在精减我们的CSS,让我们的团队更方便的维护,而在精减过程中,我们团队并没有扔掉我们现有的样式或者从零开始。

我们基于SMACSS方法着手解决SMACSS和OOCSS的问题,但从BEMToadstool我们也有一些修改和一些想法。

注意:你将需要对SMACSS有点了解,如果你不了解,可以点击这里

SMACSS的呈现

SMACSS定义了五种样式类型:

我们的方法看起来像这样:

Base(基本)

在新项目中我们的基本样式仅仅使用了Normalize,用来重置元素的基本样式(颜色、排版、外距和内距等)。

不幸的是,在线上的基本CSS来自一个时间相当久的CSS重置,里面有一些默认字体样式几乎都覆盖了。多年来,这些样式都放置在顶部,难以改变不影响其他所有的样式。

即使有这些缺点,我们仍然可以修改我们的基本样式,就像SMACSS的基本样式。

Layout(布局)

在我们的方法中不是基本样式和全局的类名而是模块。

SAMCSS规划了主要布局组件(如,页头header,侧栏sidebar,网格grid等等)和其他的一切。我们发现这种区别有几个不必要的因素:

布局和模块之间的界线太模糊了,布局做为一种特殊的类别保留下来是很价值的。

Module(模块)

模块是独立的,可重用的组件,哪怕是不知道它们的父容器。他们唯一的依赖关系是应用基本样式。当它不在需要时,我们可以安全的删除模块,而不什么影响我们的CSS。

BEM双下划线语法用于一个模块的子组件范围中,我们使用CSS子选择器随意适合深度的适用性

BEM双连字符语法作为修饰符来表示子类,或和关键字is-、模块的具体状态相结合。

因为设置模块的宽度width,定位position,外距margin都需要上下文出现的相关因素,我们的模块要么是全屏的块元素要么是内联元素。

这里有一个示例(modules/_my_module.scss):

.my-module {
    background-color: maroon;
    position: relative;

    > a {
        color: aqua;
    }
}
.my-module--important {
    @extend .my-module;
    border: 3px solid fuchsia;
}
.my-module--is-active {
    background-color:red;
}
.my-module__close-button {
    position: absolute;
    right: 0;
    top: 0;
}

当我第一次开始写模块就像这样,我最终使用很复杂的类来定义模块的名字:.my-module__child-component__grandchild-component--modifier

但除了position和尺寸相关属性外,大多数子组件可以提取出自己独立的模块。所以如果你离开定位到父元素,我们可以设置为三个小的、独立的模块。

modules/_my_module.scss:

.my-module {
    //...
}
.my-module__child-component {
    width: 100px;
}

modules/_child_component.scss:

.child-component {
    //...
}
.child-component__grandchild-component {
    position: absolute;
    top: 10px;
}

modules/_grandchild-component.scss:

.grandchild-component {
    //...
}
.grandchild-component--modifier {
    //...
}

example.html:

<div class="my-module">

    <div class="my-module__child-component">
        <div class="child-component">

            <div class="child-component__grandchild-component">
                <div class="grandchild-component--modifier"></div>
            </div>

        </div>
    </div>

</div>

.grandchild-component.child-component独立于他们的父容器。这个模块是用于他的子容器定位。这样做好处是嵌套的UI组件彼此完全脱离。

State(状态)

模块的具体状态作为模块的本身被定义在相同的文件中(如上面的.my-module--is-active),但我们要保持全局状态类的分离,如.is-hidden

Theme(皮肤)

我们为各个模板市场写theme(如ThemeForestGraphicRiver制作各作皮肤),但我们通过在一个配置文件中设置变量的设置来实现站点的特定风格。

Sass将一切整合

Configuration(配置)

application.scss第一个导入的样式文件就是_config.scss。在这里,我们设置了全局变量,共同使用。这里包括颜色、字体大小、字体、响应式断点等等。

我们还包括市场特定的配置文件,用来设置为每个市场的配色文案的变量。

Mixins(混合)

所有的Mixin保存在自己的文件中并放置在一个叫mixins的目录中,和全局都可以使用。我们也导入了处理浏览器供应商前缀的Mixin库,如Compass的Sprites图和供应商前缀。

Grid(网格)

我们的网格框架只是一个模块。

我们避开在HTML中使用类似于span-5这样的网格类名,相反使用Susy这种基于列宽而又独立于模块的类名。

modules/_page.scss:

.page {
    //...
}
.page__sidebar {
    @include span-columns(3,12);
}
.page__content {
    @include span-columns(9 omega,12);
}

在模块中.grid只是包含所有东西,他只是Susy网格容器

Internet Explorer

我们仍然支持IE7和IE8。我们过去使用HTML5 Boilerplate方法来处理那些浏览器兼容,但这意味着我们要使用很多.lt-ie8这样的类名来处理兼容。

现在我们使用这样的技巧来为那些浏览器生成独立的application-ie8.cssapplication-ie7.css样式。

IE指定的样式就写在模块中。

modules/_my_module.scss:

.my-module {
    color: chartreuse;

    @if $ie7 {
        position: relative;
        zoom:1;
    }
}

给好的浏览器提供了一个简洁的application.css,里面没用任何IE垃圾代码,相反老IE用户会得到他们自己的特殊版本。

我们不能做什么

我们不追求可读的CSS输出。当你像这样写模块,可以查看类名和直接选择正确的Sass文件而不是通过开发者工具试图找出一个特定的样式。Source Maps也一样。

我们不打算从我们编译的CSS中删除每一个重复点。我们想要开发尽可能的容易,而又不影响性能。到目前为止用mixins模块代替@extend,这样并不会增加原始文件大小。

结论

开始几个月,我们将模块的文件放到有点乱的stylesheets目录。当我们添加新的特性和转换现有的特性,我们的modules目录下的样式文件只增不减。

来自ThemeForest的主要样式文件application.scss,现在看起来像这样:

// Config
@import config_global;
@import config_themeforest;

// Vendor mixin libraries
@import compass;
@import susy;

// Our mixins
@import mixins/**/*;

// Old crud. Our base styles, plus everything else that will eventually 
// be converted into modules.
@import old_stuff/**/*;

// Modules
@import modules/**/*;

// Global state classes
@import state;

我们可以成功的实现现代化的CSS架构,而没有仍掉我们现有的样式或从零开始。

扩展阅读

译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!

出处:

英文原文:http://webuild.envato.com/blog/how-to-scale-and-maintain-legacy-css-with-sass-and-smacss/

中文译文:http://www.w3cplus.com/preprocessor/how-to-scale-and-maintain-legacy-css-with-sass-and-smacss.html