css模块化设计和sass(scss)

749 阅读14分钟

sass学习

image.png

1.预处理

CSS本身是很好玩的.但是随着项目的发展,样式表变得庞大,复杂,难以维护.这时候预处理工具(preprocessor)可以派上用场了,Sass提供了很多原生CSS所没有的功能,比如说

---变量(variables),

---嵌套(nesting),

---混入(mixins),

---继承(inheritance),

还有很多其他的好东西,让CSS变得有趣.

2.变量

把变量当做是一种存储信息的方式,存储那些在整个样式表中经常被重用的信息。你可以存储样式颜色,字体,或者任何你认为能重用的CSS值。Sass使用$符号来声明变量,例子如下\

$font-stack: Helvetica, sans-serif;
$primary-color: #333;

body {
  font: 100% $font-stack;
  color: $primary-color;
}

在Sass处理的时候,Sass把我们定义的变量 fontstackfont-stack 和 primary-color输出为标准的CSS,并把变量值写入CSS中.

--当我们需要在CSS中多次输入同一颜色值的时候,这个功能实在是太高效了.

body {
  font: 100% Helvetica, sans-serif;
  color: #333;
}

3.嵌套

写HTML的时候,你可能注意到了,HTML文件的书写方式很有结构性,层层嵌套.但是CSS的编写却没有这种特性.

Sass为你的CSS选择器提供了像HTML文件一样的的嵌套和层级功能.

--需要注意的是,过度使用Sass嵌套会写出不易维护,而且不合理的CSS.

nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

你会发现ul,li,a 选择器被嵌套在nav选择器内,这是一个非常好的CSS代码组织方式,使CSS代码可读性更高. --由SCSS转换的CSS文件格式如下:

nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

nav li {
  display: inline-block;
}

nav a {
  display: block;
  padding: 6px 12px;
  text-decoration: none; 
}

\

\

4.Sass部分组成文件:

你可以创建一个Sass文件的组成文件(也是Sass格式文件) ,用来包含CSS片段,并由其他Sass文件来调用,这是一个CSS模块化的好方式,并且有助于维护CSS.

组成文件就是创建一个Sass文件,并且名字前面带有下划线,你可以命名为像

 _partial.scss

这样,下划线让Sass知道这个文件是部分组成文件,而且这个文件不会被生成为CSS文件

Sass部分组成文件用 @import 导入.

5.导入:

CSS有一个重要的功能: 让你把CSS文件分割成更小的,可维护的各个部分文件.唯一的缺点就是每次在CSS中使用@import就会创建一个HTTP请求,Sass以现在CSS @import功能为基础做到了只需要一次HTTP 请求,把要被引入的文件合成进你要用的文件中,这样只需要提供一个文件给浏览器.

有两个Sass文件,_reset.scss and base.scss.我们想把_reset.css引入base.scss文件中:

// _reset.scss

html,
body,
ul,
ol {
   margin: 0;
  padding: 0;
}
// base.scss

@import 'reset';

body {
  font: 100% Helvetica, sans-serif;
  background-color: #efefef;
}

注意: 我们在base.scss文件中使用@import 'reset'功能时,引入的文件,不需要写文件扩展名

.scss

,Sass能够自动补全你写的文件名.生成的CSS文件如下:

html, body, ul, ol {
  margin: 0;
  padding: 0;
}

body {
  font: 100% Helvetica, sans-serif;
  background-color: #efefef;
}

.......

6.混入:

有时候CSS写起来很无聊,尤其是需要添加浏览器前缀的时候.mixin功能让我们把想重用的CSS声明组成一个可重用的组,甚至还可以传入数值,让我们的mixin功能更有扩展性.

--一个用mixin功能添加浏览器前缀的例子:

@mixin border-radius($radius) {
  -webkit-border-radius: $radius;
     -moz-border-radius: $radius;
      -ms-border-radius: $radius;
          border-radius: $radius;
}

.box { @include border-radius(10px); }

在例子中,创建minxin,首先要写@minxin标识符,然后命名为border-radius,在圆括号()内写入变量$radius,这样就可以传入半径值.

创建mixin后,我们就可以把它作为CSS声明用,使用@include方式调用 (@include空格加上mixin名字和里面的实参)

转换的CSS文件如下:

.box {
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
  -ms-border-radius: 10px;
  border-radius: 10px;
}

7.继承:

这是Sass中最有用的功能,使用@extend 让我们从一个选择器中共用CSS属性到另一个选择器.在我们的例子中,我们将创建一个包含错误,警告,成功的简单的系列提示信息

.message {
  border: 1px solid #ccc;
  padding: 10px;
  color: #333;
}

.success {
  @extend .message;
  border-color: green;
}

.error {
  @extend .message;
  border-color: red;
}

.warning {
  @extend .message;
  border-color: yellow;
}

这能够帮助我们避免在HTML文件中重复编写标签的类名.转换的CSS如下所示:

.message, .success, .error, .warning {
  border: 1px solid #cccccc;
  padding: 10px;
  color: #333;
}

.success {
  border-color: green;
}

.error {
  border-color: red;
}

.warning {
  border-color: yellow;
}

8.运算符:

在CSS中做数学运算非常有用,Sass给我们了提供了非常容易上手的数学运算符+, -, *, /, 和 %.在下面的例子中,我们要为aside 和 article的width做一些简单运算:

.container { width: 100%; }


article[role="main"] {
  float: left;
  width: 600px / 960px * 100%;
}

aside[role="complementary"] {
  float: right;
  width: 300px / 960px * 100%;
}

我们基于960px建立了一个简单的流动网格,Sass中的运算器能够把我们输入的px格式转换成对应的个百分比.

.container {
  width: 100%;
}

article[role="main"] {
  float: left;
  width: 62.5%;
}

aside[role="complementary"] {
  float: right;
  width: 31.25%;
}
  1. 控制指令 (Control Directives) SassScript 提供了一些基础的控制指令,比如在满足一定条件时引用样式,或者设定范围重复输出格式。控制指令是一种高级功能,日常编写过程中并不常用到,主要与混合指令 (mixin) 配合使用,尤其是用在 Compass 等样式库中。

9.1. if()

The built-in if() function allows you to branch on a condition and returns only one of two possible outcomes. It can be used in any script context. The if function only evaluates the argument corresponding to the one that it will return – this allows you to refer to variables that may not be defined or to have calculations that would otherwise cause an error (E.g. divide by zero).

9.2. @if

当 @if 的表达式返回值不是 false 或者 null 时,条件成立,输出 {} 内的代码:

p {
  @if 1 + 1 == 2 { border: 1px solid; }
  @if 5 < 3 { border: 2px dotted; }
  @if null  { border: 3px double; }
}

编译为

p { border: 1px solid; }

@if 声明后面可以跟多个 @else if 声明,或者一个 @else 声明。如果 @if 声明失败,Sass 将逐条执行 @else if 声明,如果全部失败,最后执行 @else 声明,例如:

$type: monster;
p {
  @if $type == ocean {
    color: blue;
  } @else if $type == matador {
    color: red;
  } @else if $type == monster {
    color: green;
  } @else {
    color: black;
  }
}

编译为

p { color: green; }

9.3. @for

@for 指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。这个指令包含两种格式:@for varfrom<start>through<end>,或者@forvar from <start> through <end>,或者 @for var from to ,区别在于 through 与 to 的含义:当使用 through 时,条件范围包含 与 的值,而使用 to 时条件范围只包含 的值不包含 的值。另外,var可以是任何变量,比如var 可以是任何变量,比如 i; 和 必须是整数值。

@for $i from 1 through 3 {
  .item-#{$i} { width: 2em * $i; }
}

编译为

.item-1 {width: 2em; }
.item-2 {width: 4em; }
.item-3 {width: 6em; }

9.4. @each

@each 指令的格式是 varin<list>,var in <list>, var 可以是任何变量名,比如 length或者length 或者 name,而 是一连串的值,也就是值列表。

@each 将变量 $var 作用于值列表中的每一个项目,然后输出结果,例如:

@each $animal in puma, sea-slug, egret, salamander {
  .#{$animal}-icon {
    background-image: url('/images/#{$animal}.png');
  }
}

编译为

.puma-icon {background-image: url('/images/puma.png'); }
.sea-slug-icon {background-image: url('/images/sea-slug.png'); }
.egret-icon {background-image: url('/images/egret.png'); }
.salamander-icon {background-image: url('/images/salamander.png'); }

9.5. @while

@while 指令重复输出格式直到表达式返回结果为 false。这样可以实现比 @for 更复杂的循环,只是很少会用到。例如:

$i: 6;
@while $i > 0 {
  .item-#{$i} { width: 2em * $i; }
  $i: $i - 2;
}
.item-6 {width: 12em; }
.item-4 {width: 8em; }
.item-2 { width: 4em; }
  1. 混合指令 (Mixin Directives) 混合指令(Mixin)用于定义可重复使用的样式,避免了使用无语意的 class,比如 .float-left。混合指令可以包含所有的 CSS 规则,绝大部分 Sass 规则,甚至通过参数功能引入变量,输出多样化的样式。

10.1. 定义混合指令 @mixin (Defining a Mixin: @mixin)

混合指令的用法是在 @mixin 后添加名称与样式,比如名为 large-text 的混合通过下面的代码定义:

@mixin large-text {
  font: {
    family: Arial;
    size: 20px;
    weight: bold;
  }
  color: #ff0000;
}

混合也需要包含选择器和属性,甚至可以用 & 引用父选择器:

@mixin clearfix {
  display: inline-block;
  &:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
  }
  * html & { height: 1px }
}

10.2. 引用混合样式 @include (Including a Mixin: @include)

使用 @include 指令引用混合样式,格式是在其后添加混合名称,以及需要的参数(可选):


.page-title {
  @include large-text;
  padding: 4px;
  margin-top: 10px;
}

编译为


.page-title {
  font-family: Arial;
  font-size: 20px;
  font-weight: bold;
  color: #ff0000;
  padding: 4px;
  margin-top: 10px; }

也可以在最外层引用混合样式,不会直接定义属性,也不可以使用父选择器。


@mixin silly-links {
  a {
    color: blue;
    background-color: red;
  }
}
@include silly-links;

编译为


a { color: blue; background-color: red; }

混合样式中也可以包含其他混合样式,比如


@mixin compound {
  @include highlighted-background;
  @include header-text;
}
@mixin highlighted-background { background-color: #fc0; }
@mixin header-text { font-size: 20px; }

10.3. 参数 (Arguments)

参数用于给混合指令中的样式设定变量,并且赋值使用。在定义混合指令的时候,按照变量的格式,通过逗号分隔,将参数写进圆括号里。引用指令时,按照参数的顺序,再将所赋的值对应写进括号:

@mixin sexy-border($color, $width) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}
p { @include sexy-border(blue, 1in); }

编译为


p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed; }

混合指令也可以使用给变量赋值的方法给参数设定默认值,然后,当这个指令被引用的时候,如果没有给参数赋值,则自动使用默认值:

@mixin sexy-border($color, $width: 1in) {
  border: {
    color: $color;
    width: $width;
    style: dashed;
  }
}
p { @include sexy-border(blue); }
h1 { @include sexy-border(blue, 2in); }

编译为


p {
  border-color: blue;
  border-width: 1in;
  border-style: dashed; }
 
h1 {
  border-color: blue;
  border-width: 2in;
  border-style: dashed; }

10.3.1. 关键词参数 (Keyword Arguments)

混入(mixin)在引入(@include指令)的时候也可以使用明确的关键字参数。例如,上面的例子可以写成:

p { @include sexy-border($color: blue); }
    h1 { @include sexy-border($color: blue, $width: 2in); }

虽然这是不够简明,但是它可以使样式表更容易阅读。它给函数呈现了更加灵活的接口,它使多参数的混入更加容易调用。

命名的参数可以按任何顺序进行传递,有默认值的参数可以省略。由于命名参数是变量名,下划线和连字符可以互换使用。

可变参数 (Variable Arguments)

有时,不能确定一个混入(mixin)或者一个函数(function)使用多少个参数。例如,用于创建盒子阴影(box-shadow)的一个混入(mixin)可以采取任何数量的box-shadow作为参数。对于这些情况,Sass支持"可变参数",参数在声明混入(mixin)或函数(function)结束的地方,所有剩余的参数打包成一个列表(list)。参数看起来就像普通参数一样,但后面跟随着...。例如:

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

.shadows {
  @include box-shadow(0px 4px 5px #666, 2px 6px 10px #999);
}

编译为:

.shadows {
  -moz-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  -webkit-box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
  box-shadow: 0px 4px 5px #666, 2px 6px 10px #999;
}

可变参数可以包含任何关键字参数传递给混入(mixin)或者函数(function)。这些可以使用keywords($args)函数 来访问,返回一个map,参数名称字符串(无$)和值的键值对。

可变参数,也可以在调用(@include指令)一个混入(mixin)时使用。使用相同的语法,你可以扩展值的列表(list),以便每个值作为单独的参数传入,或扩展值的map,以使每个键值对作为一个关键字参数处理。例如:

@mixin colors($text, $background, $border) {
      color: $text;
      background-color: $background;
      border-color: $border;
}

$values: #ff0000, #00ff00, #0000ff;
    .primary {
      @include colors($values...);
}

$value-map: (text: #00ff00, background: #0000ff, border: #ff0000);
    .secondary {
      @include colors($value-map...);
}

编译为:

.primary {
  color: #ff0000;
  background-color: #00ff00;
  border-color: #0000ff;
}

.secondary {
  color: #00ff00;
  background-color: #0000ff;
  border-color: #ff0000;
}

你可以同时传递一个列表(list)和一个map参数,只要列表(list)在map上之前,比如@include colors($values..., $map...)

您可以使用可变参数来包装一个混入(mixin)并且添加额外的样式,而不改变混入(mixin)的参数签名。如果你这样做,关键字参数将通过包装的混入(mixin)直接传递。例如:

@mixin wrapped-stylish-mixin($args...) {
      font-weight: bold;
      @include stylish-mixin($args...);
}

.stylish {
  // The $width argument will get passed on to "stylish-mixin" as a keyword
      @include wrapped-stylish-mixin(#00ff00, $width: 100px);
}

传递内容块到混入(Passing Content Blocks to a Mixin)

样式内容块可以传递到混入(mixin)包含样式的位置。样式内容块将出现在混入内的任何 @content 指令的位置。这使得可以定义抽象 关联到选择器和指令的解析。

例如:

@mixin apply-to-ie6-only {
  * html {
    @content;
  }
}
@include apply-to-ie6-only {
  #logo {
    background-image: url(/logo.gif);
  }
}

生成:

* html #logo {
  background-image: url(/logo.gif);
}

同样的混入(mixin)可以在.sass 简写语法(@mixin 可以用 = 表示,而 @include 可以用 + 表示)来完成:

=apply-to-ie6-only
  * html
    @content

+apply-to-ie6-only
  #logo
    background-image: url(/logo.gif)

注意:  当@content指令指定多次或在一个循环中指定的时候,样式块将在每次调用中被复制并引用。

变量的作用域和内容块(Variable Scope and Content Blocks)

传递给混入(mixin)的内容块在其被定义的作用域中进行运算,而不是混入(mixin)的作用域。这意味着混入(mixin)的局部变量不能传递给样式块使用,并且变量将解析为全局值:

$color: white;
    @mixin colors($color: blue) {
  background-color: $color;
      @content;
      border-color: $color;
}
.colors {
  @include colors { color: $color; }
}

编译为:

.colors {
  background-color: blue;
  color: white;
  border-color: blue;
}

另外,这清楚地表明,变量和传递到块中使用的混入,指向块定义的周围其他样式。例如:

#sidebar {
  $sidebar-width: 300px;
      width: $sidebar-width;
  @include smartphone {
    width: $sidebar-width / 3;
  }
}

scss学习

$color: white;
@mixin colors($color: blue) {
  background-color: $color;
  @content;
  border-color: $color;
}
.colors {
  @include colors { color: $color; }
}
编译后:
.colors {
  background-color: blue;
  color: white;
  border-color: blue;
}

参考: zhuanlan.zhihu.com/p/157686527 segmentfault.com/a/119000004…

juejin.cn/post/705510…

sass-lang.com/documentati…

CSS 模块化设计

什么是css模块化设计

  • 你是否为 class 命名而感到苦恼?
  • 你是否有怕跟别人使用同样 class 名而感到担忧?
  • 你是否因层级结构不清晰而感到烦躁?
  • 你是否因代码难以复用而感到不爽?
  • 你是否因为 common.css 的庞大而感到恐惧?

你如果遇到如上问题,那么就很有必要使用 css 模块化--其实就是为了我们每个模块的每一个类名都是独立无二,互不干扰,避免全局污染,复用性低,命名困难等~

为什么要css模块化设计

手写源生 CSS

在我们最初学习写页面的时候,大家都学过怎么去写 css,也就以下几种情况:

  • 行内样式,即直接在 html 中的 style 属性里编写 css 代码。
  • 内嵌样式,即在 html h 中的 style 标签内编写 class,提供给当前页面使用。
  • 导入样式,即在内联样式中 通过 @import 方法,导入其他样式,提供给当前页面使用。
  • 外部样式,即使用 html 中的 link 标签,加载样式,提供给当前页面使用。

我们在不断摸索中,逐渐形成了以编写内嵌样式外部样式为主要的编写习惯。

读到这里大家肯定有所疑问,为什么不建议使用行内样式?

使用行内样式的缺点

  • 样式不能复用。
  • 样式权重太高,样式不好覆盖。
  • 表现层与结构层没有分离。
  • 不能进行缓存,影响加载效率。

然后我们继续剖析一下,为什么不建议使用导入样式?

经测试,在 css 中使用 @import 会有以下两种情况:

1、在 IE6-8 下,@import 声明指向的样式表并不会与页面其他资源并发加载,而是等页面所有资源加载完成后才开始下载。

2、如果在 link 标签中去 @import 其他 css,页面会等到所有资源加载完成后,才开始解析 link 标签中 @import 的 css。

使用导入样式的缺点 - 导入样式,只能放在 style 标签的第一行,放其他行则会无效。 - @import 声明的样式表不能充分利用浏览器并发请求资源的行为,其加载行为往往会延后触发或被其他资源加载挂起。 - 由于 @import 样式表的延后加载,可能会导致页面样式闪烁。

使用预处理器 Sass/Less

随着时间的不断发展,我们逐渐发现,编写源生的 css 其实并不友好,例如:源生的 css 不支持变量,不支持嵌套,不支持父选择器等等,这些种种问题,催生出了像 sass/less 这样的预处理器。

预处理器主要是强化了 css 的语法,弥补了上文说了这些问题,但本质上,打包出来的结果和源生的 css 都是一样的,只是对开发者友好,写起来更顺滑。

后处理器 PostCSS

随着前端工程化的不断发展,越来越多的工具被前端大佬们开发出来,愿景是把所有的重复性的工作都交给机器去做,在 css 领域就产生了 postcss。

postcss 可以称作为 css 界的 babel,它的实现原理是通过 ast 去分析我们的 css 代码,然后将分析的结果进行处理,从而衍生出了许多种处理 css 的使用场景。

常用的 postcss 使用场景有:

  • 配合 stylelint 校验 css 语法
  • 自动增加浏览器前缀 autoprefixer
  • 编译 css next 的语法

更多 postcss 使用场景

CSS 模块化迅速发展

随着 react、vue 等基于模块化的框架的普及使用,我们编写源生 css 的机会也越来越少。我们常常将页面拆分成许多个小组件,然后像搭积木一样将多个小组件组成最终呈现的页面。

但是我们知道,css 是根据类名去匹配元素的,如果有两个组件使用了一个相同的类名,后者就会把前者的样式给覆盖掉,看来解决样式命名的冲突是个大问题。

为了解决这个问题,产生出了 CSS 模块化的概念。

CSS 模块化的实现方式

BEM 命名规范

BEM 的意思就是块(block)、元素(element)、修饰符(modifier)。是由 Yandex 团队提出的一种前端命名方法论。这种巧妙的命名方法让你的 css 类对其他开发者来说更加透明而且更有意义。

BEM 的命名规范如下:

/* 块即是通常所说的 Web 应用开发中的组件或模块。每个块在逻辑上和功能上都是相互独立的。 */
.block {
}

/* 元素是块中的组成部分。元素不能离开块来使用。BEM 不推荐在元素中嵌套其他元素。 */
.block__element {
}

/* 修饰符用来定义块或元素的外观和行为。同样的块在应用不同的修饰符之后,会有不同的外观 */
.block--modifier {
}

通过 bem 的命名方式,可以让我们的 css 代码层次结构清晰,通过严格的命名也可以解决命名冲突的问题,但也不能完全避免,毕竟只是一个命名约束,不按规范写照样能运行。

我们再看一下OOCSS(面向对象CSS)

OOCSS 表示的是面向对象 CSS(Object Oriented CSS),是一种把面向对象方法学应用到 CSS 代码组织和管理中的实践。 OOCSS最关键的一点就是:提高他的灵活性和可重用性。这个也是OOCSS最重要的一点。OOCSS主张是通过在基础组件中添加更多的类,从而扩展基础组件的CSS规则,从而使CSS有更好的扩展性。

我们有一个容器是页面page的1/4宽,有一个蓝色的背景,1px灰色的边框,10px的左右边距,5px的上边距,10px的下边距,以前对于这样一个样式,我们常常给这个容器创建一个类,并把这些样式全部加上。像下面这样。

// template

<div class="size1of4"></div>

// style

.size1of4 {

  background: blue;

  border: 1px solid #ccc;

  margin: 5px 10px 10px;

  width: 25%;

}

然而使用oocss的话,我们不这样做,我把为这个容器创建更多的类,并且每个样式对应一个类,这样是为了后面可以重复使用这些组件的样式,避免重复写相同的样式,就拿这个实例来说,我们给这个容器增加下面的类:bgBlue,solidGray,mts,mlm,mrm,mbm

// template

<div class="size1of4 bgBlue solidGray mts mlm mrm mbm"></div>

// style

.size1of4 {width: 25%;}

.bgBlue {background:blue}

.solidGray {border: 1px solid #ccc}

.mts {margin-top: 5px}

.mrm {margin-right: 10px}

.mbm {margin-bottom: 10px}

.mlm {margin-left: 10px}

OOCSS的优点

  • 减少CSS代码。
  • 具有清洁的HTML标记,有语义的类名,逻辑性强的层次关系。
  • 语义标记,有助于SEO。
  • 更好的页面优化,更快的加载时间(因为有很多组件重用)。
  • 可扩展的标记和CSS样式,有更多的组件可以放到库中,而不影响其他的组件。
  • 能轻松构造新的页面布局,或制作新的页面风格。

OOCSS的缺点

  • OOCSS适合真正的大型网站开发,因为大型网站用到的可重用性组件特别的多,如果运用在小型项目中可能见不到什么成效。所以用不用OOCSS应该根据你的项目来决定。
  • 如果没用巧妙的使用,创建组件可能对于你来说是一堆没用的东西,成为一烂摊子,给你的维护带来意想不到的杯具,说不定还是个维护的噩梦。
  • 最好给每一个组件备写一份说明文档,有助于调用与维护。

AMCSS(属性模块)。

属性模块或者说AM,其核心就是关于定义命名空间用来写样式。通俗的讲就是,给一个元素加上属性,再通过属性选择器定位到这个元素。达到避免过多的使用class。

// template

<div am- Row ></div>

<div am- Column = "12"> Full < /div>

</ div> <div am- Row > <div am- Column = "4"> Thirds </div>

<div am- Column = "4"> Thirds </div>

<div am- Column = "4"> Thirds < /div> </ div>

// style

[am- Row ] { /* max-width, clearfixes */ }

[am- Column ~= "1" ] { /* 1/12th width, floated */ }

[am- Column ~= "2" ] { /* 1/6th width, floated */ }

[am- Column ~= "3" ] { /* 1/4th width, floated */ }

[am- Column ~= "4" ] { /* 1/3rd width, floated */ }

[am- Column ~= "5" ] { /* 5/12th width, floated */ } /* etc */

[am- Column ~= "12" ] { /* 100% width, floated */ }

你会注意到第一件事情就是有am-前缀。这也是AM核心部分,确保属性模块不会与现有属性冲突。你可以使用你自己喜欢的任何前缀名,我常使用的是ui-、css-或者其他前缀,但这些示例中使用的是am-前缀。HTML的有效性对你或你的项目来说是非常重要,就类似于使用data-前缀开头定义的属性类似。 你可能会注意到的第二件事情就是类似于1、4或12这样的值,使用类名变得极为麻烦——造成冲突的机会很多。但定义了我们自己的命名空间,实际上将空间变得很小,用于工作中不会造成冲突。为了更好的工作,可以自由选择最简明而且有意义的标记。

CSS的scoped实现?

现在在各种框架中都会有scoped属性,使我们的css具有模块化性质,不会污染到其他模块,那么scoped是如何实现的呢?我们一起来揭开它神秘的面纱吧?

如果你是一个勤奋好学的同学,你一定会发现在HTML的style标签中有一个scoped属性。让我们来一起看一下这个属性的神奇吧。

一直以来,文档上的STYLE元素通常都是作用域全局的,选择器按照全局的CSS优先规则来设置的。要实现局部的选择需要先选到容器元素,再用后代选择器来实现。scoped属性可以让STYLE元素不再作用于全局,而从当前STYLE元素所在的容器开始选择后代。

<div>

  <style scoped >

    span {color:red;}

  </style>

  <span> 我是第1DIV内的SPAN </span>

</div>

<div>

  <style scoped >

    span {color:green;}

  </style>

  <span> 我是第2DIV内的SPAN </span>

</div>

<div>

  <span> 我是第3DIV内的SPAN </span>

</div>

我们来看一下vue的代码,当我们在style中加了scoped属性后图片

咦,这不就是我们刚刚讲过的AMCSS(属性模块)的应用吗?也就是说vue在编译的时候,把带有scoped属性的的模块,加上了一个唯一的属性,然后通过类名+属性选择器的方法来实现模块化!

CSS Modules

CSS Modules 指的是我们像 import js 一样去引入我们的 css 代码,代码中的每一个类名都是引入对象的一个属性,通过这种方式,即可在使用时明确指定所引用的 css 样式。

并且 CSS Modules 在打包的时候会自动将类名转换成 hash 值,完全杜绝 css 类名冲突的问题。

使用方式如下:

1、定义 css 文件。

.className {
  color: green;
}
/* 编写全局样式 */
:global(.className) {
  color: red;
}

/* 样式复用 */
.otherClassName {
  composes: className;
  color: yellow;
}

.otherClassName {
  composes: className from "./style.css";
}

2、在 js 模块中导入 css 文件。

import styles from "./style.css";

element.innerHTML = '<div class="' + styles.className + '">';

3、配置 css-loader 打包。

CSS Modules 不能直接使用,而是需要进行打包,一般通过配置 css-loader 中的 modules 属性即可完成 css modules 的配置。

// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /.css$/,
        use:{
          loader: 'css-loader',
          options: {
            modules: {
              // 自定义 hash 名称
              localIdentName: '[path][name]__[local]--[hash:base64:5]',
            }
          }
       }
    ]
  }
};

我们来探索一下webpack是怎么实现模块化的。

With :local (without brackets) local mode can be switched on for this selector. :global(.className) can be used to declare an explicit global selector. With :global (without brackets) global mode can be switched on for this selector. webpack会把class分为两种,一种是local(本地的),一种是global(全局的)。默认导出的都是本地的,但是你可以通过 :global(...)开关来控制导出全局。下面我们看一下栗子。

// 输入

: local (.className) { background: red; }

: local .className { color: green; }

: local (.className .subClass) { color: green; }

: local .className .subClass : global (. global - class -name) { color: blue; }

// 导出

._23_aKvs-b8bW2Vg3fwHozO { background: red; }

._23_aKvs-b8bW2Vg3fwHozO { color: green; }

._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 { color: green; }

._23_aKvs-b8bW2Vg3fwHozO ._13LGdX8RMStbBE9w-t0gZ1 . global - class -name { color: blue; }

:local(className)被编译为唯一可识别的标示,:global(className)原样输出,当然我们也可以控制导出的格式。配置如下:

{

  test: /.css$/ ,

  use : [

    {

     loader: 'css-loader',

     options: {

       modules: true ,

       localIdentName: '[path][name]__[local]--[hash:base64:5]'

     }

   }

 ]

}

4、最终打包出来的 css 类名就是由一长串 hash 值生成。

._2DHwuiHWMnKTOYG45T0x34 {
  color: red;
}

._10B-buq6_BEOTOl9urIjf8 {
  background-color: blue;
}

参考文档:blog.csdn.net/weixin_4029…

www.html.cn/doc/sass/#m…

www.sass.hk/docs/ sass-lang.com/documentati…

zhuanlan.zhihu.com/p/100133524

zhuanlan.zhihu.com/p/28675375

mp.weixin.qq.com/s/0N4NLkRNP…