less和sass的区别及常见用法

389 阅读12分钟

1、Sass和Less的比较

相同之处

  1. 混入(Mixins) ——class中的class;
  2. 参数混入——可以传递参数的class,就像函数一样;
  3. 嵌套规则——Class中嵌套class,从而减少重复的代码;
  4. 运算——CSS中用上数学;
  5. 颜色功能——可以编辑颜色;
  6. 名字空间(namespace) ——分组样式,从而可以被调用;
  7. 作用域——局部修改样式;
  8. JavaScript 赋值——在CSS中使用JavaScript表达式赋值。

不同之处

1、Less环境较Sass简单

Cass的安装需要安装Ruby环境,Less基于JavaScript,是需要引入Less.js来处理代码输出css到浏览器,也可以在开发环节使用Less,然后编译成css文件,直接放在项目中,有less.app、SimpleLess、CodeKit.app这样的工具,也有在线编辑地址。

2、Less与Sass处理机制不一样

前者是通过客户端处理的,后者是通过服务端处理,相比较之下前者解析会比后者慢一点

  1. sass同通过ruby 是在服务器端处理。Sass的安装需要Ruby环境,是在服务端处理的。
  2. less是通过js编译 是在客户端处理。 Less是需要引入less.js来处理Less代码输出css到浏览器,也可以在开发环节使用Less,然后编译成css文件,直接放到项目中

2、sass的常见用法

Sass 有两种语法格式。首先是 SCSS (Sassy CSS) —— 也是本文示例所使用的格式 —— 这种格式仅在 CSS3 语法的基础上进行拓展,所有 CSS3 语法在 SCSS 中都是通用的,同时加入 Sass 的特色功能。此外,SCSS 也支持大多数 CSS hacks 写法以及浏览器前缀写法,以及早期的 IE 滤镜写法。这种格式以 .scss 作为拓展名。

另一种也是最早的 Sass 语法格式,被称为缩进格式 (Indented Sass) 通常简称 "Sass",是一种简化格式。它使用 “缩进” 代替 “花括号” 表示属性属于某个选择器,用 “换行” 代替 “分号” 分隔属性,很多人认为这样做比 SCSS 更容易阅读,书写也更快速。缩进格式也可以使用 Sass 的全部功能,只是与 SCSS 相比个别地方采取了不同的表达方式。这种格式以 .sass 作为拓展名。

定义变量

$ 定义变量,嵌套规则内定义的变量只能在嵌套规则内使用(局部变量),不在嵌套规则内定义的变量则可在任何地方使用(全局变量)。将局部变量转换为全局变量可以添加 !global 声明

// 例一:
$highlight-color: #F90;
.selected {
  border: 1px solid $highlight-color; // 变量引用
  $width: 5em !global; // 声明为全局变量
}

// 例二:
$nav-color: #F90; //全局变量
nav {
  $width: 100px;  //局部变量,仅能在当前规则块下使用
  width: $width;
  color: $nav-color;
}

规则嵌套

即:css选择器俄罗斯套娃

// 基本使用:
#content {
  background-color: #f5f5f5;
  aside { background-color: #eee }
}

编译后:
#content { background-color: #f5f5f5 }
#content aside { background-color: #eee }

大多数情况下这种简单的嵌套都没问题,但是有些场景下不行,比如你想要在嵌套的选择器 里边立刻应用一个类似于:hover的伪类。为了解决这种以及其他情况,sass提供了一个特殊结构&(父元素选择器)。

& 父元素选择器使用:

// & 父元素选择器使用:
article a {
  color: blue;
  &:hover { color: red }
}

编译后:
article a { color: blue }
article a:hover { color: red }

嵌套属性:

// 嵌套属性:
nav {
  border: 1px solid #ccc {
  left: 0px;
  right: 0px;
  }
}

编译后:
nav {
  border: 1px solid #ccc;
  border-left: 0px;
  border-right: 0px;
}

群组选择器、子组合选择器、同层级选择器:

article {
  ~ article { border-top: 1px dashed #ccc }
  > section { background: #eee }
  dl > {
    dt { color: #333 }
    dd { color: #555 }
  }
  nav + & { margin-top: 0 }
}

编译后:
article ~ article { border-top: 1px dashed #ccc }
article > footer { background: #eee }
article dl > dt { color: #333 }
article dl > dd { color: #555 }
nav + article { margin-top: 0 }

@media

// Sass 中 `@media` 指令与 CSS 中用法一样,只是增加了一点额外的功能:允许其在 CSS 规则中嵌套。
// 如果 `@media` 嵌套在 CSS 规则内,编译时,`@media` 将被编译到文件的最外层,包含嵌套的父选择器。这个功能让 `@media` 用起来更方便,不需要重复使用选择器,也不会打乱 CSS 的书写流程。
.sidebar {
  width: 300px;
  @media screen and (orientation: landscape) {
    width: 500px;
  }
}
// 编译为:
.sidebar {
  width: 300px; }
  @media screen and (orientation: landscape) {
    .sidebar {
      width: 500px; } }

导入sass文件(@import)

css有一个特别不常用的特性,即@import规则,它允许在一个css文件中导入其他css文件。然而,后果是只有执行到@import时,浏览器才会去下载其他css文件,这导致页面加载起来特别慢。

sass也有一个@import规则,但不同的是,sass@import规则在生成css文件时就把相关文件导入进来。这意味着所有相关的样式被归纳到了同一个css文件中,而无需发起额外的下载请求。另外,所有在被导入文件中定义的变量和混合器均可在导入文件中使用。

嵌套导入:
// 生成的结果跟你直接在.blue-theme选择器内写_blue-theme.scss文件的内容完全一样。
// 被导入的局部文件中定义的所有变量和混合器,也会在这个规则范围内生效。这些变量和混合器不会全局有效,这样我们就可以通过嵌套导入只对站点中某一特定区域运用某种颜色主题或其他通过变量配置的样式。
.blue-theme {@import "blue-theme"}   

.blue-theme {
  aside {
    background: blue;
    color: #fff;
  }
}
// 默认变量值(!default):
// 它很像`css`属性中`!important`标签的对立面,不同的是`!default`用于变量,含义是:如果这个变量被声明赋值了,那就用它声明的值,否则就用这个默认值。
$fancybox-width: 400px !default;
.fancybox {
   width: $fancybox-width;
}

混入(@mixin、@include)

// 混合器使用`@mixin`标识符定义。这个标识符给一大段样式赋予一个名字,这样你就可以轻易地通过引用这个名字重用这段样式
@mixin rounded-corners {
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
}
// 使用@include 引入
notice {
  background-color: green;
  border: 2px solid #00aa00;
  @include rounded-corners;
}

// sass最终生成:
.notice {
  background-color: green;
  border: 2px solid #00aa00;
  -moz-border-radius: 5px;
  -webkit-border-radius: 5px;
  border-radius: 5px;
}

混合器中不仅可以包含属性,也可以包含css规则,包含选择器和选择器中的属性,如下代码:

// 定义混合器 no-bullets
@mixin no-bullets {
  list-style: none;
  li {
    list-style-image: none;
    list-style-type: none;
    margin-left: 0px;
  }
}
// 引入混合器
ul.plain {
  color: #444;
  @include no-bullets;
}

// `sass`的`@include`指令会将引入混合器的那行代码替换成混合器里边的内容。最终,上边的例子如下代码:

ul.plain {
  color: #444;
  list-style: none;
}
ul.plain li {
  list-style-image: none;
  list-style-type: none;
  margin-left: 0px;
}

给混合器传参, 支持默认参数:

// 定义
@mixin link-colors(
    $normal,
    $hover,
    $visited: $normal) 
{
  color: $normal;
  &:hover { color: $hover; }
  &:visited { color: $visited; }
}
// 使用
a {
  @include link-colors(blue, green); // @include link-colors(blue, green) $visited也会被自动赋值为 blue
}

//Sass最终生成的是:
a { color: blue; }
a:hover { color: green; }
a:visited { color: blue; }

继承(@extend) (仅Sass)

混合器主要用于展示性样式的重用,而类名用于语义化样式的重用。因为继承是基于类的(有时是基于其他类型的选择器),所以继承应该是建立在语义化的关系上。当一个元素拥有的类(比如说.seriousError)表明它属于另一个类(比如说.error),这时使用继承再合适不过了。

// 通过选择器继承继承样式
// 例一
.error {
  border: 1px solid red;
  background-color: #fdd;
}
.seriousError {
  @extend .error;
  border-width: 3px;
}

// 例二
.disabled {
  color: gray;
  @extend a;
}

@extend背后最基本的想法是,如果.seriousError @extend .error, 那么样式表中的任何一处.error都用.error``.seriousError这一选择器组进行替换。这就意味着相关样式会如预期那样应用到.error.seriousError。当.error出现在复杂的选择器中,比如说h1.error``.error a或者#main .sidebar input.error[type="text"],那情况就变得复杂多了,但是不用担心,sass已经为你考虑到了这些。

关于@extend有两个要点你应该知道。

1、跟混合器相比,继承生成的css代码相对更少。因为继承仅仅是重复选择器,而不会重复属性,所以使用继承往往比混合器生成的css体积更小。如果你非常关心你站点的速度,请牢记这一点。

2、继承遵从css层叠的规则。当两个不同的css规则应用到同一个html元素上时,并且这两个不同的css规则对同一属性的修饰存在不同的值,css层叠规则会决定应用哪个样式。相当直观:通常权重更高的选择器胜出,如果权重相同,定义在后边的规则胜出。

混合器本身不会引起css层叠的问题,因为混合器把样式直接放到了css规则中,而继承存在样式层叠的问题。被继承的样式会保持原有定义位置和选择器权重不变。通常来说这并不会引起什么问题,但是知道这点总没有坏处。

saasScript

运算

SassScript 支持 6 种主要的数据类型:

  • 数字,1, 2, 13, 10px
  • 字符串,有引号字符串与无引号字符串,"foo", 'bar', baz
  • 颜色,blue, #04a3f9, rgba(255,0,0,0.5)
  • 布尔型,true, false
  • 空值,null
  • 数组 (list),用空格或逗号作分隔符,1.5em 1em 0 2em, Helvetica, Arial, sans-serif
  • maps, 相当于 JavaScript 的 object,(key1: value1, key2: value2)

SassScript 也支持其他 CSS 属性值,比如 Unicode 字符集,或 !important 声明。然而Sass 不会特殊对待这些属性值,一律视为无引号字符串。

SassScript 支持数字的加减乘除、取整等运算 (+, -, *, /, %),如果必要会在不同单位间转换值。

p {
  width: 1in + 8pt;
  color: #010203 * 2;
  margin: 3px + 4px auto;
}
$value: null;
p:before {
  content: "I ate #{5 + 10} #{$value}  pies!";
  font-family: sans- + "serif";
}

函数

Sass 支持自定义函数,并能在任何属性值或 Sass script 中使用:

$grid-width: 40px;
$gutter-width: 10px;

@function grid-width($n) {
  @return $n * $grid-width + ($n - 1) * $gutter-width;
}

#sidebar { width: grid-width(5); }

// 编译为
#sidebar {
  width: 240px; }

控制指令 (仅Sass)

@if @else if

// @if @else if
$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; }

@for

@for 指令可以在限制的范围内重复输出格式,每次按要求(变量的值)对输出结果做出变动。这个指令包含两种格式:@for $var from <start> through <end>,或者 @for $var from <start> to <end>

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

// 编译为
.item-1 {
  width: 2em; }
.item-2 {
  width: 4em; }
.item-3 {
  width: 6em; }

@each

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

@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'); }

@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; }

3、Less的常见用法

定义变量

@定义变量

@width: 10px; 
@height: @width + 10px; 

#header { 
  width: @width; 
  height: @height; 
}

规则嵌套

同:sass

.clearfix {
  display: block;
  zoom: 1;
  
  // & 表示当前父级
  &:after {
    content: " ";
    display: block;
    font-size: 0;
    height: 0;
    clear: both;
    visibility: hidden;
  }
}

@规则嵌套和冒泡

@ 规则(例如 @media 或 @supports)可以与选择器以相同的方式进行嵌套。@ 规则会被放在前面,同一规则集中的其它元素的相对顺序保持不变。这叫做冒泡(bubbling)。

.component {
  width: 300px;
  @media (min-width: 768px) {
    width: 600px;
    @media  (min-resolution: 192dpi) {
      background-image: url(/img/retina2x.png);
    }
  }
  @media (min-width: 1280px) {
    width: 800px;
  }
}

// 编译为:
.component {
  width: 300px;
}
@media (min-width: 768px) {
  .component {
    width: 600px;
  }
}
@media (min-width: 768px) and (min-resolution: 192dpi) {
  .component {
    background-image: url(/img/retina2x.png);
  }
}
@media (min-width: 1280px) {
  .component {
    width: 800px;
  }
}

导入less文件(@import)

“导入”的工作方式和你预期的一样。你可以导入一个 .less 文件,此文件中的所有变量就可以全部使用了。如果导入的文件是 .less 扩展名,则可以将扩展名省略掉:

@import "library"; // library.less
@import "typo.css";

混入

// 定义 .bordered
.bordered {
  border-top: dotted 1px black;
  border-bottom: solid 2px black;
}
//引入.bordered
#menu a {
  color: #111;
  .bordered(); 
}

运算

算术运算符 +-*/ 可以对任何数字、颜色或变量进行运算。如果可能的话,算术运算符在加、减或比较之前会进行单位换算。计算的结果以最左侧操作数的单位类型为准。如果单位换算无效或失去意义,则忽略单位。无效的单位换算例如:px 到 cm 或 rad 到 % 的转换。

// 所有操作数被转换成相同的单位
@conversion-1: 5cm + 10mm; // 结果是 6cm
@conversion-2: 2 - 3cm - 5mm; // 结果是 -1.5cm

// conversion is impossible
@incompatible-units: 2 + 5px - 3cm; // 结果是 4px

// example with variables
@base: 5%;
@filler: @base * 2; // 结果是 10%
@other: @base + @filler; // 结果是 15%

@base: 2cm * 3mm; // 结果是 6cm

@color: (#224488 / 2); // 结果是 #112244
background-color: #112244 + #111; // 结果是 #223355

@color: #222 / 2; // results in `#222 / 2`, not #111
background-color: (#FFFFFF / 16); //results is #101010

@var: 50vh/2;
width: calc(50% + (@var - 20px));  // 结果是 calc(50% + (25vh - 20px))

函数

Less 内置了多种函数用于转换颜色、处理字符串、算术运算等。这些函数在Less 函数手册中有详细介绍。

@base: #f04615;
@width: 0.5;

.class {
  width: percentage(@width); // returns `50%`
  color: saturate(@base, 5%);
  background-color: spin(lighten(@base, 25%), 8);
}

命名空间和访问符

(不要和 CSS @namespace 或 namespace selectors 混淆了)。

有时,出于组织结构或仅仅是为了提供一些封装的目的,你希望对混合(mixins)进行分组。你可以用 Less 更直观地实现这一需求。假设你希望将一些混合(mixins)和变量置于 #bundle 之下,为了以后方便重用或分发:

#bundle() {
  .button {
    display: block;
    border: 1px solid black;
    background-color: grey;
    &:hover {
      background-color: white;
    }
  }
  .tab { ... }
  .citation { ... }
}

现在,如果我们希望把 .button 类混合到 #header a 中,我们可以这样做:

#header a {
  color: orange;
  #bundle.button();  // 还可以书写为 #bundle > .button 形式
}

注意:如果不希望它们出现在输出的 CSS 中,例如 #bundle .tab,请将 () 附加到命名空间(例如 #bundle())后面。

映射

从 Less 3.5 版本开始,你还可以将混合(mixins)和规则集(rulesets)作为一组值的映射(map)使用。

#colors() {
  primary: blue;
  secondary: green;
}

.button {
  color: #colors[primary];
  border: 1px solid #colors[secondary];
}

// 输出符合预期:
.button {
  color: blue;
  border: 1px solid green;
}