我们使用css来编写样式,但是随着样式效果的多样化以及复杂化,css变量常量的缺失、语法的呆板等一成不变的写法就会十分臃肿难以维护。
所以基于css扩展了一套属于自己的语法,通过专门的编程语言,扩展css的编程能力,在编译成css。常见的库有less、scss/sass、stylus等。
完美兼容css代码,结构清晰便于扩展
支持css定义变量常量、代码嵌套
提供函数,支持循环语句
支持模块化,通过混合(Mixins)实现复用
HTML不能使用scss文件,只能使用css文件,所以在使用scss时需要动态监听,然后引入编译之后的css静态文件。
// 全局安装
npm install sass -g
//局部安装
npm install sass
// 监听文件夹
sass --watch scss:css
// 监听单个文件
sass --watch a.scss:a.css
按照上述操作之后,在书写样式表时使用scss进行开发,cmd会自动生成css文件
vue使用scss可以通过两步安装,也可合二为一
// 分两步安装
// 安装sass-loader
npm install sass-loader --save-dev
// 安装dart-sass
npm install sass --save-dev
// 合二为一
npm i sass sass-loader -D
在.vue文件中使用
安装sass-loader和node-sass依赖
npm install sass-loader node-sass --save-dev
打开react的webpack配置,找到module下的rules,oneof数组中,然后找到最后一个配置修改添加
{
test:/\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader']
}
import引入scss文件
import "./App.scss";
有全局变量、局部变量和默认值。
sass的变量必须是 $ 开头,后面紧跟变量名,变量值和变量名之间需要使用冒号 : 分隔开,如果值后面加上 !default 则表示默认值。变量用在属性名中时,需要写在 #{ } 里面
编译完成之后的css为
.div{
width: 300px;
height: 150px;
background-color: #55ff00;
}
代码嵌套进行后代选择,代码更直观,在选择嵌套中可是使用 & 表示父元素。并且除了选择器可以嵌套,属性和伪类伪元素也可以嵌套。属性嵌套指的是有些属性拥有同一个开始单词,如border-top,border-right都是以border开头
.div{
width:300px;
height: 300px;
background-color: #55ff00;
.dot{
width: 100px;
height: 100px;
background-color: pink;
border: {
top: 10px solid #000;
right: 10px solid blue;
};
&::before{
content: '我是before';
font-size: 12px;
}
.text{
font-size: 36px;
color: red;
}
}
}
编译完成之后的css为
.div{
width: 300px;
height: 300px;
background-color: #55ff00;
}
.div .dot {
width: 100px;
height: 100px;
background-color: pink;
border-top: 10px solid #000;
border-right: 10px solid blue;
}
.div .dot::before {
content: '我是before';
font-size: 12px;
}
.div .dot .text{
font-size: 36px;
color: red;
}
Mixins是css预处理语言最强大的特性,每一种完善的预处理都必不可少,可以将一部分公用样式抽出,作为独立定义的模块,然后再需要使用的地方直接调用。
声明的 @mixin 中还可以定义变量和接收参数,通过 @include 调用
scss文件编写
@mixin boxStyle {
$bgc: pink;
width: 300px;
height: 300px;
background-color: $bgc;
}
.box{
@include boxStyle
}
编译完成之后的css为
.box{
width: 300px;
height: 300px;
background-color: pink;
}
scss文件编写
@mixin boxStyle($bgc: pink) {
width: 300px;
height: 300px;
background-color: $bgc;
}
.box1{
@include boxStyle // 使用默认背景色 pink
}
.box2{
@include boxStyle(blue) // 背景色为 blue
}
.box3{
@include boxStyle(yellow) // 背景色为 yellow
}
编译完成之后的css为
.box1{
width: 300px;
height: 300px;
background-color: pink;
}
.box2{
width: 300px;
height: 300px;
background-color: blue;
}
.box3{
width: 300px;
height: 300px;
background-color: yellow;
}
scss文件编写
@mixin boxStyle($bgc: pink,$width:300px,$height:300px) {
width: $width;
height: $height;
background-color: $bgc;
}
.box1{
@include boxStyle(red)
}
.box2{
@include boxStyle($width:100px)
}
.box3{
@include boxStyle($height:150px,$bgc:#ccc)
}
.box4{
@include boxStyle(#000, 200px, 50px)
}
编译完成之后的css为
.box1 {
width: 300px;
height: 300px;
background-color: red;
}
.box2 {
width: 100px;
height: 300px;
background-color: pink;
}
.box3 {
width: 300px;
height: 150px;
background-color: #ccc;
}
.box4 {
width: 200px;
height: 50px;
background-color: #000;
}
通过 @use 导入scss模块文件,自动生成一个命名空间,通过 . 语法访问模块里面的变量,只会引入和执行一次。而通过 @import 多次导入会进行多次编译
模块文件test.scss
$font-stack: Helvetica, sans-serif;
$text-color: #333;
$fontSize: 16px;
.span {
font: 100% $font-stack;
color: $text-color;
}
index文件导入使用
// 使用@use导入文件
@use 'test.scss' as test; // 生成了一个 test 命名空间
.box {
background-color: test.$text-color;
font-size: test.$fontSize
}
编译完成之后的css为
.span {
font: 100% Helvetica, sans-serif;
color: #333;
}
.box {
background-color: #333;
font-size: 16px;
}
继承可以让一个选择器继承另一个选择器的所有样式,在使用继承时使用 @extend 需要继承的选择器。
scss文件编写
.message-shared {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.message {
width: 200px;
height: 50px;
@extend .message-shared;
}
编译完成之后的css为
.message {
width: 200px;
height: 50px;
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
scss文件编写
%message-shared {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.message {
height: 50px;
@extend %message-shared;
}
.success {
@extend %message-shared;
border-color: green;
}
编译完成之后的css为
.message {
height: 50px;
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
border: 1px solid green;
padding: 10px;
color: #333;
}
可以对数值型的value进行加减乘除四则计算,以及使用+进行字符串拼接
scss文件编写
$containerSize:150px;
$ballSize:10px;
$dotn:36;
.dot{
font-size: $dotn * 0.5px;
background-color: red;
width: $containerSize + $ballSize;
height: $containerSize - $ballSize;
transform: rotate(360deg / $dotn) translateY(-$containerSize / 2 - $ballSize);
&::before{
content: '欢迎来到' + '复仇联盟';
}
}
编译完成之后的css为
.dot {
font-size: 18px;
background-color: red;
width: 160px;
height: 140px;
transform: rotate(10deg) translateY(-75px);
}
.dot::before {
content: "欢迎来到复仇联盟";
}
通过 @if 、 @else if 、 @else 来实现条件判断
.h1{
$type: monster;
@if $type == ocean {
color: blue;
} @else if $type == matador {
color: red;
} @else if $type == monster {
color: green;
} @else {
color: black;
}
}
.h2{
@if 1 + 1 == 2 { border: 1px solid; }
@if 5 < 3 { border: 2px dotted; }
@if null { border: 3px double; }
}
编译完成之后的css为
.h1 {
color: green;
}
.h2 {
border: 1px solid;
}
支持for循环语句,通过 @for 、 @each 、 @while 实现循环,可以配合map和list使用
包含两种格式:@for $var from
@for $i from 1 through 3 {
.item-#{$i} { width: 2em * $i; }
}
@for $i from 1 to 3 {
.every-#{$i} { width: 10em * $i; }
}
编译完成之后的css为
.item-1 {
width: 2em;
}
.item-2 {
width: 4em;
}
.item-3 {
width: 6em;
}
.every-1 {
width: 10em;
}
.every-2 {
width: 20em;
}
@each 指令的格式是 $var in , $var 可以是任何变量名
是值列表。@each 将变量 $var 作用于值列表中的每一个项目,然后输出结果
@each $animal in puma, sea-slug, egret, salamander {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
}
}
编译完成之后的css为
.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');
}
@each指令还可以使用多个变量,如@each $var1、$var2…… in在里面如果是列表列表,则子列表的每个元素都被分配给相应的变量
@each $animal, $color, $cursor in (puma, black, default),(sea-slug, blue, pointer),(egret, white, move) {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$header} {
font-size: $size;
}
}
编译完成之后的css为
.puma-icon {
background-image: url('/images/puma.png');
border: 2px solid black;
cursor: default;
}
.sea-slug-icon {
background-image: url('/images/sea-slug.png');
border: 2px solid blue;
cursor: pointer;
}
.egret-icon {
background-image: url('/images/egret.png');
border: 2px solid white;
cursor: move;
}
h1 {
font-size: 2em;
}
h2 {
font-size: 1.5em;
}
h3 {
font-size: 1.2em;
}
@while 指令重复输出格式直到表达式返回结果为 false。这样可以实现比 @for 更复杂的循环,只是很少会用到。要注意避免陷入死循环
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
编译完成之后的css为
.item-6 {
width: 12em;
}
.item-4 {
width: 8em;
}
.item-2 {
width: 4em;
}
lighten($color, 10%); /* 返回的颜色在$color基础上变亮10% */
darken($color, 10%); /* 返回的颜色在$color基础上变暗10% */
saturate($color, 10%); /* 返回的颜色在$color基础上饱和度增加10% */
desaturate($color, 10%); /* 返回的颜色在$color基础上饱和度减少10% */
grayscale($color); /* 返回$color的灰度色*/
complement($color); /* 返回$color的补色 */
invert($color); /* 返回$color的反相色 */
mix($color1, $color2, 50%); /* $color1 和 $color2 的 50% 混合色*/
/*
这是一个
多行注释
*/
// 这是一个单行注释
Sass 拓展了 @import 的功能,允许其导入 SCSS 或 Sass 文件。被导入的文件将合并编译到同一个 CSS 文件中,另外,被导入的文件中所包含的变量或者混合指令 (mixin) 都可以在导入的文件中使用。
less官网下载less.js文件,在.html文件中引入
// 分两步安装
// 安装less-loader
npm install less-loader --save-dev
// 安装dart-less
npm install less --save-dev
// 合二为一
npm i less less-loader -D
命令行操作安装
// 暴露webpack.config.js
npm run eject
// 安装
npm i less less-loader --save
配置webpack.config.js文件
// 在文件中按住Ctrl+F进行搜索,首先搜 style files regexes 找到位置后添加如下代码
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;
// 在文件中按住Ctrl+F进行搜索,搜 getStyleLoaders 找到位置后添加如下代码
{
loader: require.resolve('less-loader'),
options: lessOptions,
}
// 在文件中按住Ctrl+F进行搜索,搜 getCSSModuleLocalIdent 找到位置后添加如下代码
{
test: lessRegex,
exclude: lessModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap,
},
'less-loader'
),
sideEffects: true,
},
{
test: lessModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction && shouldUseSourceMap,
module: true,
getLocalIdent: getCSSModuleLocalIdent
},
'less-loader'
),
},
变量处理方式–懒加载,所有 Less 变量的计算,都是以这个变量最后一次被定义的值为准。Less的变量名使用 @ 符号开始。变量用在属性名中时,需要写在 @{ } 里面
编译完成之后的css为
#header {
width: 10px;
height: 20px;
background-color: #55ff00;
}
Less 提供了使用嵌套代替层叠或与层叠结合使用的能力,在选择嵌套中可是使用 & 表示父元素。
#header {
color: black;
.navigation {
font-size: 12px;
}
.logo {
width: 300px;
}
&::after {
content: " ";
font-size: 0;
visibility: hidden;
}
}
编译完成之后的css为
#header {
color: black;
}
#header::after {
content: " ";
font-size: 0;
visibility: hidden;
}
#header .navigation {
font-size: 12px;
}
#header .logo {
width: 300px;
}
less的混合是一种将一组属性从一个规则集包含(或混入)到另一个规则集的方法,就像在当前的Class中增加一个属性一样。
在less可以将Mixins看成是一个类选择器,Mixins也可以设置参数,并给参数设置默认值。设置参数的变量名是使用 @ 开头,同样参数和默认参数值之间需要使用冒号 : 分隔开。
.bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
padding: 10px;
}
.item1{
background-color: pink;
.bordered()
}
.item2{
background-color: red;
.bordered
}
编译完成之后的css为
.item1 {
background-color: pink;
border-top: dotted 1px black;
border-bottom: solid 2px black;
padding: 10px;
}
.item2 {
background-color: red;
border-top: dotted 1px black;
border-bottom: solid 2px black;
padding: 10px;
}
.bordered(@width:2px,@pad:10px){
border:@width solid red;
padding: @pad;
}
.btn1 {
.bordered();
}
.btn2 {
.bordered(5px);
}
.btn3{
.bordered(@pad:5px)
}
.btn4{
.bordered(3px, 20px)
}
编译完成之后的css为
.btn1 {
border: 2px solid red;
padding: 10px;
}
.btn2 {
border: 5px solid red;
padding: 10px;
}
.btn3 {
border: 2px solid red;
padding: 5px;
}
.btn4 {
border: 3px solid red;
padding: 20px;
}
less一样可以进行四则运算
// 在加、减或比较之前会进行单位换算,最左侧操作数的单位类型为准
// 所有操作数被转换成相同的单位
@conversion-1: 5cm + 10mm; // 结果是 6cm
@conversion-2: 2 - 3cm - 5mm; // 结果是 -1.5cm
@incompatible-units: 2 + 5px - 3cm; // 结果是 4px
// 乘法和除法不作转换
@base: 2cm * 3mm; // 结果是 6cm
// 颜色计算
@color: (#224488 / 2); // 结果是 #112244
background-color: #112244 + #111; // 结果是 #223355
// calc() 并不对数学表达式进行计算,但是在嵌套函数中会计算变量和数学公式的值
@var: 50vh/2;
width: calc(50% + (@var - 20px)); // 结果是 calc(50% + (25vh - 20px))
LESS中通过guarded mixins代替if/else,利用关键词 when 来实现简单的条件判断
.bod (@num) when (@num > 3){
border: 1px solid;
}
.bod (@num) when (@num < 3){
border: 2px dotted;
}
.bod (@num) when (@num = 3){
border: 3px double;
}
.btn1{.bod(5)}
.btn2{.bod(2)}
.btn3{.bod(3)}
编译完成之后的css为
.btn1 {
border: 1px solid;
}
.btn2 {
border: 2px dotted;
}
.btn3 {
border: 3px double;
}
进行与或判断
/* 当下边 div 中 .size 传入的第一个参数是100px或者第二个参数是100px才会执行
(),()相当于JS中的|| 与判断*/
.size(@width,@height) when (@width = 100px),(@height = 100px){
width: @width;
height: @height;
}
div{
.size(100px,100px);
background: red;
}
/* 当下边 div 中 .size 传入的第一个参数是100px并且第二个参数是100px才会执行
()and()相当于JS中的&& 或判断*/
.size(@width,@height) when (@width = 100px) and (@height = 100px){
width: @width;
height: @height;
}
div{
.size(100px,100px);
background: red;
}
在 Less 中,混合可以调用它自身,当一个混合递归调用自身,再结合 guard 表达式和模式匹配这两个特性,就可以写出循环结构。
.xkd(@n, @i: 1) when (@i =< @n) {
.grid@{i} {
width: (@i * 100% / @n);
}
.xkd(@n, (@i + 1));
}
.xkd(5);
编译完成之后的css为
.grid1 {
width: 20%;
}
.grid2 {
width: 40%;
}
.grid3 {
width: 60%;
}
.grid4 {
width: 80%;
}
.grid5 {
width: 100%;
}
lighten(@color, 10%); // 返回的颜色在@color基础上变亮10%
darken(@color, 10%); // 返回的颜色在@color基础上变暗10%*/
saturate(@color, 10%); // 返回的颜色在@color基础上饱和度增加10%
desaturate(@color, 10%); // 返回的颜色在@color基础上饱和度降低10%
spin(@color, 10); // 返回的颜色在@color基础上色调增加10
spin(@color, -10); // 返回的颜色在@color基础上色调减少10
mix(@color1, @color2); // 返回的颜色是@color1和@color2两者的混合色
/*
这是一个
多行注释
*/
// 这是一个单行注释
可以导入一个 .less 文件,此文件中的所有变量就可以全部使用了。如果导入的文件是 .less 扩展名,则可以将扩展名省略掉
npm install stylus
//类似标准语法
p {
color: #ffffff;
}
// omit brackets 省略花括号
p
color: #ffffff;
// 省略花括号和分号
p
color #ffffff
Stylus对变量名没有任何限定,可以是$开始,也可以是任意字符,而且与变量值之间可以用冒号、空格隔开,并且不需要分配值给变量就可以定义引用属性
size = 10px
.top
width: size
size = 20px
.btn
width: size
.box
width w = 150px
height h = 80px
margin-left -(w / 2)
margin-top -(h / 2)
编译完成之后的css为
.top {
width: 10px;
}
.btn {
width: 20px;
}
.box{
width:150px;
height:80px;
margin-left:-75px;
margin-top:-40px;
}
可以不使用任何符号,就是直接声明Mixins名,然后在定义参数和默认值之间用等号(=)来连接。
bordered(myWidth=2px,pad=10px){
border:myWidth solid red;
padding:pad;
}
.btn1 {
bordered();
}
.btn2 {
bordered(5px);
}
.btn3{
bordered(pad=5px)
}
.btn4{
bordered(3px, 20px)
}
编译完成之后的css为
.btn1 {
border: 2px solid red;
padding: 10px;
}
.btn2 {
border: 5px solid red;
padding: 10px;
}
.btn3 {
border: 2px solid red;
padding: 5px;
}
.btn4 {
border: 3px solid red;
padding: 20px;
}
Stylus中通过if、else if、else、unless(基本与if相反)实现条件判断来提供语言的流控制,通过for/in实现循环迭代。可以在样式中省略大括号({})。
// 逻辑
box(x, y, margin = false)
padding y x
if margin
margin y x
else
padding y x
body
box(5px, 10px, true)
// 循环
// for [, ] in
.box
colors = red pink yellow blue
for col, i in colors
foo i col
编译完成之后的css为
body{
padding: 10px 5px;
margin: 10px 5px;
}
.box {
foo: 0 red;
foo: 1 pink;
foo: 2 yellow;
foo: 3 blue;
}
lighten(color, 10%); // 返回的颜色在'color'基础上变亮10%
darken(color, 10%); // 返回的颜色在'color'基础上变暗10%
saturate(color, 10%); // 返回的颜色在'color'基础上饱和度增加10%
desaturate(color, 10%); // 返回的颜色在'color'基础上饱和度降低10%
注释与上相同