学习一下 less sass

174 阅读3分钟

less、sass 入门

一门向后兼容的 CSS 扩展语言

Less 不会直接生效成样式,而是被编译为 CSS 之后才能生效

使用 Less 本质上来说还是在使用 CSS,只是一些语法糖写法,可以由 less-loader 去转换成标准的 CSS,所以 CSS Module 不好写的问题还是有

CSS in JS 和 CSS Module

都是通过生成唯一的类名来避免全局样式冲突,确保样式的局部作用域

两者都支持样式与组件直接关联,提高了组件的封装性

cssinjs 是将样式直接嵌入到 js 中,更灵活,可以动态样式,

css module 样式在构建时就已经确定(开发模式可以热更新)

  • CSS Module
  • CSS-in-JS 有运行时效率问题,还会干扰react-dev-tool,但是局部样式书写方便
  • Tailwind CSS 预设样式,然后直接使用类名,编译成 css 文件
  • Sass

传统的用 bem 命名法来保证样式局部生效

用法

手动使用

可以在线上进行实践,把 less 转为 css less2css.org

也可以在本地

npm install less
​
# 使用全局安装的 less 或者 node_modules/.bin/lessc
lessc --version / -v
​
# 把指定的 less 文件转换成 css 文件
# lessc [option ...] <source> [destination]
lessc ./src/index.less ./src/index.css

webpack 中配置

下载 less 和 less-loader 即可

vite 中配置

export default defineConfig({
  css: {
    // css模块化配置项
  	modules:{
      // ....
    }
    // 预处理器配置项
    preprocessorOptions: {
      scss: {
        // 一些配置项
      },
      less: {
        // 一些配置项
      }
    }
  }
})


Sass 快速入门

变量

$ 符号定义变量和使用变量,并且在 sass 中,中划线和下划线互通,可以用一个定义,另一个使用

作用域:在规则集内定义只能在该规则集内使用(包括子规则集)

$nav-border: 1px solid red;
nav {
  $width: 100px;
  width: $width; // 在规则集内定义只能在规则集内使用
  border: $nav-border;
}
// 编译后
nav {
  width: 100px;
  border: 1px solid red;
}

嵌套

& 符号代表父选择器

同样支持 css 的群组选择器写法

还支持属性嵌套,写法是从属性的一个中划线断开,然后把子属性写到 {}

nav {
  width: 1px;
  border: {
    style: solid;
    width: 1px;
    color: red;
  }
}

导入

@import 进行导入

局部文件

sass 的局部文件名以下划线开头,,这样的文件被称为局部文件,不会被生成对应的独立的 css 文件,导入这个文件时可以省略开头的下划线

@import "themes/night-sky" // 导入 "theme/_night-sky.scss"

默认变量值

一般情况下,反复声明同一个变量,只有最后一处会有效

但是使用默认值时,如果已经被声明了会直接使用声明的值,否则使用默认值

$fan-width: 400px !default; // 如果前面(或者导入的库中)已经声明了这个变量,则使用声明的值
.fancybox {
  width: $fan-width;
}

嵌套导入

嵌套导入,局部文件会被直接插入到导入它的地方

// _blue-theme.scss
aside {
  color: blue;
}
​
// index.scss
.blue-theme {
  @import "blue-theme";
}
​
// 编译后
.blue-theme {
  aside {
    color: blue;
  }
}

原生导入

遇到这三种情况时,会被视为是原生的导入(@import 语句会保留在生成的 css 文件中)

  • 被导入的文件名后缀为 .css
  • 被导入的名字是一个 url 地址
  • 被导入的文件名是一个 CSS 的 url()

如果要直接把一个 css 文件的内容插入,可以把该文件后缀改为 .scss ,再导入,因为 sass 完全支持 css 语法

静默注释

div {
  width: 1px; // 这种注释不会出现在生成的 css 文件中
  height: 2px; /* 这种注释会出现在生成的 css 文件中 */
  color/* CSS 标准格式注释出现在原生CSS不支持的地方,也不会出现在生成的css 文件中 */: red;
}

混合

用于重用样式,用 @mixin 标识符定义,@include 调用

混合器传参

// 定义一个混合器,可以传参,有一个参数有默认值
@mixin link-colors($normal, $hover, $visited: green) {
  color: $normal;
  &:hover { color: $hover }
  &:visited { color: $visited }
}
​
a {
  @include link-colors(blue, red, grey)
}
​
// 通过 $name: value 传参,可以不关注顺序
div {
  @include link-colors(
    $normal: blue,
    $visited: grey,
    $hover: red
   );
}

继承

基于类名的重用

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

混合器本身不会引起 css 层叠问题,因为混合器直接把样式放到 css 中,权重不变

Less快速入门

变量 Variables

变量可以用来代替:规则值、规则名、url、import 导入的部分或者完整路径(可以用于切换主题)

@ 前缀声明一个变量,@{} 来读取变量,如果是直接使用变量值,可以省略 {}

@primary: #428bca; // 声明变量
@primary-dark: darken(@link-color, 10%); // 通过变量和函数计算另一个变量
@images: "../img"; // url
@selector: banner; // 选择器
@property: background; // 属性.@{selector} {
  @{property}: url("@{images}/wave.png"); // 属性名
  @{property}-color: #0ee; // 属性名的一部分
}
​
// 可变变量
.section {
  @color: primary;
  .element {
    color: @@color; // 用多重 @ 符号来取值
  }
}

混合 Mixins

混合是一种将一组属性从一个规则集包含到另一个规则集的方法

比 sass 中的混合写法更简单

.bordered {
  border: 1px solid red;
}
​
#id {
  color: #111;
  .bordered(); // .bordered 所属的规则就包含在这个规则集下面了
}
div {
  #id(); // 也可以用 id 进行混合
}

如果希望创建的 mixin 不被编译成 css 输出,需要在定义的时候就加上括号

.mixin() {
  color: red;
}
// 命名空间
#outer() {
  .inner {
    color: blue
  }
}

嵌套 Nesting

& 代表当前选择器的父选择器

.c {
  color: red;
  &:hover {
    color: blue;
  }
}
// 编译后的 css 文件
.c {
  color: red;
}
.c:hover {
  color: blue;
}

@规则(例如 @media @supports)会被冒泡到前面

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

运算 Operations

算术运算符可以对任何数字、颜色、或变量进行运算,从 4.0 开始,括号外的 / 不会被计算,而是直接转换成 CSS,calc 中的变量会被编译成值,但是里面的计算也会保留原样

@color: #222 / 2; 
@var: 12px;
.c {
  background-color: (#FFFFFF / 16);
  color: @color;
  height: calc(50%  + @var - 220px);
}
​
// 编译后
.c {
  background-color: #101010;
  color: #222 / 2;
  height: calc(50% + 12px - 220px);
}

转义 Escaping

转义允许使用任意字符串作为属性或者变量值 ~"anything" 将会被原样输出

在 less 3.5+版本中,很多转义都不需要了,可以直接简写了

@min700: ~"(min-width: 700px)";
@min800: (min-width: 800px); // 可以直接简写了
.element {
  @media @min700 {
    font-size: 12px;
  }
}
// 编译
@media (min-width: 700px){
  .element {
    font-size: 12px;
  }
}

函数 Functions

Less 中内置了多种用于转换颜色、处理字符串、算术运算等,参考函数手册

命名空间和访问符

出于组织和封装的目的,可以对混合进行分组,便于分发和重用

// 可以通过后面是否附加括号来决定是否要被编译成 CSS 输出
// 如果有括号,那只有使用的地方会被编译成 CSS 输出
// 如果没有括号,那会被编译成普通的 类选择器规则集或id选择器规则集,使用的地方也会输出一遍
#bundle() {
  .button {
    display: block;
    border: 1px solid black;
    background-color: grey;
    &:hover {
      background-color: white;
    }
  }
  .tab {
    background-color: red;
  }
}
​
div {
  #bundle.button();
  background-color: #bundle.tab[backgroundcolor] // 映射
}
​
// 编译后
header {
  display: block;
  border: 1px solid black;
  background-color: grey;
  background-color: red; // 映射的
}
header:hover {
  background-color: white;
}

映射

3.5+版本,可以将 mixins 的规则集当成一组值的映射使用,可见上面例子

作用域 Scope

混合和变量定义和CSS 自定义属性(CSS变量)一样,不必在引用前先定义,而且也会按照作用域进行查找使用

@var: red;
.div {
  p {
    color: @var;
  }
  @var: white;
}
// 编译后
.div p {
  color: white;
}

CSS 变量和作用域

:root {
  --color1: red;
  --color2: black; // 备用
}
.div {
  color: var(--color1, --color2);
}

注释

和 js 一样

导入

在 CSS 中必须把 @import 放在其他规则集前面,但是在 Less 中不需要

  • 如果导入的 .css 文件,则将被视为 CSS 并且保持原样
  • 如果是其他任何扩展名或者没有扩展名后缀,都会被当成 .less 导入
@import "library"; // library.less
@import "index.css";
@import (keyword) "index.less";

在React 项目中,如果在不同组件分别导入 CSS 文件,其实是会对全局生效的,按照导入顺序优先级

插件

functions.add('pi', function() {
    return new tree.Dimension(Math.PI);
});
.show-me-pi {
  value: 3.141592653589793;
}
​

函数手册

less 内置的一些函数, less函数手册

if(condition, trueValue, falseValue)

根据条件使用某一个值

@some: foo;
div {
  color: if((iscolor(@same))), @some, black);
}

boolean(condition)

保存一个 布尔值变量,方便后续的 if 等使用

@bg: black;
@is-bg-light: boolean(luma(@bg) > 50%);
​
div {
  color: if(@is-bg-light, black, white);
}

escape(string)

对输入字符串中的一些特殊字符进行编码,输出成新的字符串

  • 不编码:, / ? @ & + ' $ ! ~
  • 常见编码字符:# = () {} <> : ^
escape('a=1'); // a%3D1

e

字符串转换成不带引号的 css 或 less 规则

%format

带有 % 号的语句,会进行格式化,用后续参数替代前缀% 的符号,可以相同,会按照索引顺序来替换

format-a-d:%("repetitions: %a file:%b", 1, 2)

replace(string, pattern, replacement[, flags])

把 string 中的 pattern 替换成 replacement

flags 类似正则:g 替换所有,i 不区分大小写

length(用逗号或者空格分割开的一组值)

返回这组值有几个

@list: "banna", "tomato", "potato";
n: length(@list); // n: 3
length(1px solid red); // 3

extract(list, index)

按照索引返回空格或者逗号隔开的一组数据中的某个值

style: extract(8px solid red, 2); // style: solid

range(start, end, step)

生成一组值,start 和 step 都是可选,start 默认是 1 或者 1px

value: range(4); // value: 1 2 3 4;
value2: range(10px, 30px, 10); // value2: 10px 20px 30px

each(list, rules)

对 list 里的每个值按照 rules 进行操作

@list: blue, green, red;
each(@list, {
  .sel-@{value} {
    a: b;
  }
})
​
// 等价于
.sel-blue {
  a: b;
}
.sel-green {
  a: b;
}
.sel-red {
  a: b;
}
​
// 也可以对规则组使用
@set: {
  one: blue;
  two: green;
  three: red;
}
  .set {
    each(@set, {
    @{key}-@{index}: @value;
    })
    }
  

Math 方法

内值了一批数学方法,对数字进行处理,使用和 js 类似

  • ceil 进一
  • floor 收尾
  • percentage 转换成带 % 格式
  • round 四舍五入,第二个参数可以指定位数
  • sqrt 开方,单位不会 进行操作,保留原单位
  • abs 取绝对值
  • mod 求余
  • min 数组取最小
  • max 数组取最大
  • pow 计算次方
  • sin ,还有其他三角函数计算不一一列举

类型方法

  • isnumber 判断是否是数字,可以带单位,但是16进制不判断为数字
  • isstring 是否是字符串
  • iscolor 判断是否为颜色值,16进制和预设值等
  • isruleset 是否是规则集
  • isdefined 变量是否被定义了
  • isem ispixel isurl iskeyword 等

各种单位转换和颜色转换函数

less 中还内置了各种单位转换和颜色转换的函数,不一一列举了,秉承着样式结构逻辑分离的原则,把计算逻辑放在 js 中,平时开发基本上用不上这些内置函数,可以参考 less函数手册