Sass
Sass 是一种流行的CSS 预处理器,使用一种较为紧凑的、类似于缩进的语法,不使用花括号和分号来分隔样式规则。SCSS 则采用与原生 CSS 相似的语法,使用花括号和分号来分隔样式规则。sass从第三代开始,放弃了缩进式风格,并且完全向下兼容普通的css代码,这一代的sass也被称为scss。
一、嵌套
1、选择器嵌套
.container {
width: 900px;
margin: 0 auto;
.header {
height: 90px;
line-height: 90px;
.logo {
width:100px;
height: 60px;
}
}
.center {
height: 600px;
background-color: #f00;
}
.footer {
font-size: 16px;
text-align: center;
}
}
//并列选择器
.alert, .warning {
ul, p {
margin-right: 0;
margin-left: 0;
padding-bottom: 0;
}
}
//组合选择器
ul > {
li {
list-style-type: none;
}
}
h2 {
+ p {
border-top: 1px solid gray;
}
}
p {
~ {
span {
opacity: 0.8;
}
}
}
2、父选择器嵌套&
.container {
width: 900px;
margin: 0 auto;
a {
color: #333;
&:hover {
text-decoration: underline;
color: #f00;
}
}
.top {
border: 1px #ff0 solid;
&-left {
float: left;
width: 200px;
}
}
}
3、属性嵌套
.container {
a {
color: #0ff;
font: {
size: 14px;
family: sans-serif;
weight: bold;
}
}
}
4、占位符%
以 %
开头,并且不包含在 CSS 输出中。
.alert:hover, %strong-alert {
font-weight: bold;
}
%strong-alert:hover {
color: red;
}
5、@at-root
.container {
display: flex;
@at-root {
background-color: gray;
color: white;
}
.nested {
font-size: 14px;
@at-root {
font-weight: bold;
}
}
}
二、注释
// 这是单行注释,不会被编译
/*
* 这是多行注释,会被编译
*/
三、变量
1、定义规则
- 变量以
$
开头,后面跟变量名 - 变量名可包含字母、数字、下划线、连接符,且不能以数字开头;
- 写法同CSS,即变量名和值之间用冒号(
:
)分隔; - 变量一定要先定义,后使用
TIP
下划线也连接符 通过下划线与连接符定义的同名变量视为同一变量,最终取决于最后一次定义。
$font-size: 14px;
$font_size: 20px;
.container {
font-size:$font-size; //font-size:20px
}
2、变量值类型
sass支持6种主要的数据类型
Numbers
:如12,20pxStrings
:有引号字符串与无引号字符串,如"foo","bar",gameColors
:颜色英文单词、#RRGGBB、rgb(R, G, B),hsl(H, S, L)如red、#ff0edf、#0df98fff、rgb(255,0,0),rgba(255,255,0,.8),hsl(0, 100%, 50%)Booleans
:true、falsenull
Lists
:用空格或逗号分隔,如10px 20px 10px 20px
、Arial, sans-serif, Mircosoft YaHEI
Maps
:相当于js中的object对象,如(key1: value, key2: value2)Calculations
:计算表达式,如calc(400px + 10%),min(100px, calc(1rem + 10%))Functions
:函数
3、变量默认值
$color: #333;
//如果$color之前没定义就使用如下默认值
$color: #999 !default;
.container {
border-color: $color;
}
4、变量作用域
局部变量
在选择器内定义的变量,只能在选择器范围内使用。
.container {
$font-size: 14px; //只能在container容器内使用
font-size: $font-size;
.title {
font-size: $font-size;
}
}
全局变量
定义后能全局使用的变量。
- 在选择器之外的最前处定义
$font-size: 16px;
.container {
font-size: $font-size;
}
.header {
font-size: $font-size;
}
- 使用
!global
定义
.container {
$font-size: 16px !global;
font-size: $font-size;
}
.header {
font-size: $font-size;
}
5、内置变量
定义在内置模块的变量且无法被修改。
@use "sass:math" as math;
math.$pi: 0; // This assignment will fail.
四、插值
#
$class-name: danger;
$attr: color;
$author: '中年大叔学前端'
/*
* 这是注释部分
* @author: #{$author}
*/
a.#{$class-name} {
border-#{$attr}: #ff0;
}
五、运算
1、关系运算符
==
、!=
、<
、>
、<=
、>=
2、逻辑运算符
and
、or
、not
3、算术运算符
+
、-
、*
、/
、%
TIP
以下三种情况/
将被视为除法运算符:
- 如果值或值的一部分是变量或函数的返回值时
- 如果值被圆括号包裹时
- 如果值是算数表达式的一部分时
$width: 900px;
div {
width: $width /2 ;
z-index: round(10) / 2;
height: (500px / 2);
margin-left: 5px + 8px / 2px;
}
注意
%
与px
不能一起运算- 纯数字与
%
或px
运算时会自动转化成相应的%
或px
4、字符串运算符
+
注意
- 如果有引号字符串(位于
+
左侧)连接无引号字符串,则运算结果是有引号 - 如果无引号字符串(位于
+
左侧)连接有引号字符串,则运算结果没有引号
六、函数
@function和@return
语法
@function <function-name>(<parameters>) {
// Function body
@return <value>;
}
示例
@function calculate-width($width, $padding) {
@return $width + 2 * $padding;
}
.container {
width: calculate-width(200px, 10px);
}
七、混入
@mixin和@include
@mixin show {
display : block;
}
@mixin hide($color) {
display : none;
color : $color;
}
@mixin block-margin($top, $right, $bottom: 0, $left: 0) {
margin-top: $top;
margin-right: $right;
margin-bottom: $bottom;
margin-bottom: $left;
}
@mixin linear-gradient($direction, $gradients...) {
background-color: nth($gradients, 1);
background-image: linear-gradient($direction, $gradients);
}
.box{
width : 100px;
@include show;
@include hide(red);
@include block-margin(10px, 20px, 10px, 30px);
@include block-margin($left: 10px, $right: 20px, $top: 10px, $bottom: 20px);
@include block-margin(10px,20px);
@include linear-gradient(to right, #ff0, #f00, #f0f);
}
八、继承
@extend
.color { color:red}
%line{ //占位符
display : inline;
}
.box{
@extend %line;
@extend .color;
}
TIP
继承与混入的区别:
- 继承会将公共部分单独抽离出来,减少代码冗余,而混入不会
- 继承会编译后出现无用的类名(可以结合占位符
%
使用解决编译后出现无用类名问题),而混入不会
九、流程控制
1、@if...@else
语法
@if <condition> {
// Code block to be executed if the condition is true
} @else if <condition> {
// Code block to be executed if the condition is true
} @else {
// Code block to be executed if no condition is true
}
示例
$color: red;
@if $color == red {
.box {
background-color: $color;
}
} @else if $color == blue {
.box {
background-color: $color;
color: white;
}
} @else {
.box {
background-color: gray;
}
}
2、@each
遍历列表
语法
@each $item in <list> {
// Code block to be executed
}
示例
$colors: red, green, blue;
@each $color in $colors {
.box-#{$color} {
background-color: $color;
}
}
遍历映射
语法
@each $key, $value in <map> {
// Code block to be executed
}
示例
$font-sizes: (
small: 12px,
medium: 16px,
large: 20px
);
@each $name, $size in $font-sizes {
.text-#{$name} {
font-size: $size;
}
}
解构赋值遍历键值对
语法
@each $var1, $var2 in <list> {
// Code block to be executed
}
示例
$list: (1, red), (2, green), (3, blue);
@each $num, $color in $list {
.box-#{$num} {
background-color: $color;
}
}
3、@for
语法
// 循环将从 <start> 开始,逐步增加到等于或大于 <end> 的值
@for $var from <start> through <end> {
// Code block to be executed
}
// 循环将从 <start> 开始,逐步增加到小于 <end> 的值
@for $var from <start> to <end> {
// Code block to be executed
}
示例
$font-sizes: 12px 14px 16px 18px;
@for $i from 1 through length($font-sizes) {
$font-size: nth($font-sizes, $i);
h#{$i} {
font-size: $font-size;
}
}
4、@while
语法
@while <condition> {
// Code block to be executed
}
示例
$first: 0;
$second: 1;
$count: 10;
@while $count > 0 {
$next: $first + $second;
$first: $second;
$second: $next;
$count: $count - 1;
}
十、导入
@use
@use 规则从其他 Sass 样式表中加载混合、函数和变量,并将来自多个样式表的 CSS 组合在一起。由 @use 加载的样式表称为“模块”。
语法
@use "<url>"
示例:加载成员
<namespace>.<variable>
, <namespace>.<function>()
, @include <namespace>.<mixin>()
// src/_corners.scss
$radius: 3px;
@mixin rounded {
border-radius: $radius;
}
// style.scss
@use "src/corners";
.button {
@include corners.rounded;
padding: 5px + corners.$radius;
}
TIP
私有成员 以 - 或 _ 开头的名称
// src/_corners.scss
$-radius: 3px;
@mixin rounded {
border-radius: $-radius;
}
// style.scss
@use "src/corners";
.button {
@include corners.rounded;
padding: 5px + corners.$-radius; // This is an error! $-radius isn't visible outside of `_corners.scss`.
}
示例:自定义模块命名
@use "<url>" as <namespace>
// src/_corners.scss
$radius: 3px;
@mixin rounded {
border-radius: $radius;
}
// style.scss
@use "src/corners" as c;
.button {
@include c.rounded;
padding: 5px + c.$radius;
}
示例:配置模块
@use <url> with (<variable>: <value>, <variable>: <value>)
// _library.scss
$black: #000 !default;
$border-radius: 0.25rem !default;
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;
code {
border-radius: $border-radius;
box-shadow: $box-shadow;
}
// style.scss
@use 'library' with (
$black: #222,
$border-radius: 0.1rem
);
WARNING
- 不必显式写出要加载的文件的扩展名; @use "variables" 将自动加载 variables.scss 、 variables.sass 或 variables.css
- 模块将始终首先相对于当前文件加载,不要求使用
./
进行相对导入,直接@use "variables"即可自动加载路径,仅当不存在与模块 URL 匹配的相对文件时,才会使用加载路径 - 仅作为模块加载而不是自行编译的 Sass 文件以
_
开头(如_public.scss
),这些被称为部分文件,它们告诉 Sass 工具不要尝试自行编译这些文件,导入部分时可以省略_
- 如果在文件夹中写入
_index.scss
或_index.sass
,则在加载文件夹本身的 URL 时将自动加载索引文件 - 除了加载 .sass 和 .scss 文件外,Sass 还可以加载普通的旧 .css 文件
与 @import 的区别
- @use 仅使变量、函数和混合在当前文件的范围内可用。它永远不会将它们添加到全局范围
- @use 只加载每个文件一次。这可确保您最终不会意外地多次复制依赖项的 CSS
- @use 必须出现在文件的开头,并且不能嵌套在样式规则中
- 每个 @use 规则只能有一个 URL
- @use 要求在其 URL 两边加上引号,即使使用缩进语法也是如此
十一、导出
@forward
语法
@forward "<url>"
示例
// src/_list.scss
@mixin list-reset {
margin: 0;
padding: 0;
list-style: none;
}
// bootstrap.scss
@forward "src/list";
// styles.scss
@use "bootstrap";
li {
@include bootstrap.list-reset;
}
示例:添加前缀@forward "<url>" as <prefix>-*
// src/_list.scss
@mixin reset {
margin: 0;
padding: 0;
list-style: none;
}
// bootstrap.scss
@forward "src/list" as list-*;
// styles.scss
@use "bootstrap";
li {
@include bootstrap.list-reset;
}
示例:控制可见性@forward "<url>" hide <members...>
或 @forward "<url>" show <members...>
// src/_list.scss
$horizontal-list-gap: 2em;
@mixin list-reset {
margin: 0;
padding: 0;
list-style: none;
}
@mixin list-horizontal {
@include list-reset;
li {
display: inline-block;
margin: {
left: -2px;
right: $horizontal-list-gap;
}
}
}
// bootstrap.scss
@forward "src/list" hide list-reset, $horizontal-list-gap;
示例:配置模块@forward <url> with (<variable>: <value>, <variable>: <value>)
// _library.scss
$black: #000 !default;
$border-radius: 0.25rem !default;
$box-shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;
code {
border-radius: $border-radius;
box-shadow: $box-shadow;
}
// _opinionated.scss
@forward 'library' with (
$black: #222 !default,
$border-radius: 0.1rem !default
);
// style.scss
@use 'opinionated' with ($black: #333);
TIP
@forward 规则的配置可以在其配置中使用 !default 标志。这允许模块更改上游样式表的默认值,同时仍允许下游样式表覆盖它们。
十二、内置模块
1、color函数
rgba($color, $alpha)
:设置颜色的透明度,返回一个新的带有透明度的颜色值lighten($color, $amount)
:使颜色变亮,返回一个更亮的颜色值darken($color, $amount)
:使颜色变暗,返回一个更暗的颜色值saturate($color, $amount)
:使颜色饱和度增加,返回一个更饱和的颜色值desaturate($color, $amount)
:使颜色饱和度减少,返回一个更不饱和的颜色值mix($color1, $color2, $weight)
:混合两个颜色,返回一个介于两者之间的颜色值
2、list函数
list.append($list, $val, $separator: auto)
:将值 $val 添加到列表 $list 的末尾,使用指定的分隔符 $separator。返回更新后的列表。list.index($list, $value)
:返回值 $value 在列表 $list 中的第一个匹配项的索引。list.join($list1, $list2, $separator: auto, $bracketed: auto)
:将列表 $list2 连接到列表 $list1 的末尾,使用指定的分隔符 $separator。如果 $bracketed 参数为 true,则将结果列表包裹在方括号中。返回连接后的列表。list.length($list)
:返回列表 $list 的长度(元素数量)。list.separator($list)
:返回列表 $list 中的分隔符。list.nth($list, $n)
:返回列表 $list 中的第 $n 个元素。
3、map函数
map.deep-merge($map1, $map2)
:深度合并两个映射 $map1 和 $map2,返回合并后的映射。如果有相同的键,后者的值将覆盖前者。map.deep-remove($map, $key, $keys...)
:从映射 $map 中深度删除指定的键 $key 及其嵌套键 $keys,返回删除后的映射。map.get($map, $key, $keys...)
:获取映射 $map 中指定键 $key 及其嵌套键 $keys 对应的值。map.set($map, $key, $value)
:将映射 $map 中的键 $key 设置为指定的值 $value,返回更新后的映射。map.keys($map)
:返回映射 $map 中所有的键组成的列表。map.values($map)
:返回映射 $map 中所有的值组成的列表。
4、math函数
math.ceil($number)
:返回不小于 $number 的最小整数。math.clamp($min, $number, $max)
:将 $number 限制在 $min 和 $max 之间,如果 $number 小于 $min,返回 $min;如果 $number 大于 $max,返回 $max;否则返回 $number。math.floor($number)
:返回不大于 $number 的最大整数。math.max($number...)
:返回一组数中的最大值。math.min($number...)
:返回一组数中的最小值。math.round($number)
:将 $number 四舍五入为最接近的整数。math.abs($number)
:返回 $number 的绝对值。math.hypot($number...)
:返回给定一组数的平方和的平方根。math.div($number1, $number2)
:将 $number1 除以 $number2,返回结果。math.percentage($number)
:将 $number 转换为百分比形式(乘以 100 并添加百分号)。math.random($limit: null)
:生成一个随机数。如果提供了 $limit 参数,则随机数将介于 0 和 $limit 之间。
5、meta函数
meta.calc-args($calc)
:返回给定 calc() 函数的参数列表meta.calc-name($calc)
:返回给定 calc() 函数的名称meta.call($function, $args...)
:调用指定名称的函数,并传递给定的参数meta.content-exists()
:检查当前选择器是否具有 ::content 伪元素meta.feature-exists($feature)
:检查指定功能(feature)是否存在meta.function-exists($name, $module: null)
:检查指定名称的函数是否存在meta.get-function($name, $css: false, $module: null)
:获取指定名称的函数,返回函数的定义meta.global-variable-exists($name, $module: null)
:检查指定名称的全局变量是否存在meta.inspect($value)
:返回给定值的字符串表示形式meta.keywords($args)
:返回关键字参数的名称列表meta.mixin-exists($name, $module: null)
:检查指定名称的混合器是否存在meta.module-functions($module)
:获取指定模块中定义的函数列表meta.module-variables($module)
:获取指定模块中定义的变量列表meta.type-of($value)
:返回给定值的类型meta.variable-exists($name)
:检查指定名称的变量是否存在
6、selector函数
selector.is-superselector($super, $sub)
:检查 $super 是否是 $sub 的超级选择器(即,是否包含 $sub 的所有匹配)。返回布尔值。selector.append($selectors...)
:将多个选择器合并为一个选择器。返回合并后的选择器。selector.extend($selector, $extendee, $extender)
:将 $extender 扩展到 $extendee 的选择器上,并返回扩展后的选择器。selector.nest($selectors...)
:将多个选择器嵌套在一起形成一个复合选择器。返回嵌套后的选择器。selector.parse($selector)
:将选择器解析为简单选择器的列表。selector.replace($selector, $original, $replacement)
:将选择器中的 $original 替换为 $replacement,返回替换后的选择器。selector.unify($selector1, $selector2)
:将两个选择器合并为一个共同选择器。返回合并后的选择器。selector.simple-selectors($selector)
:提取选择器中的简单选择器(如类名、ID、伪类等),返回简单选择器的列表。
7、string函数
string.quote($string)
:在字符串 $string 的两端添加引号(单引号或双引号),返回带引号的字符串。string.index($string, $substring)
:返回字符串 $string 中子字符串 $substring 的第一个匹配项的索引。string.insert($string, $insert, $index)
:在字符串 $string 的指定索引 $index 处插入 $insert,返回插入后的字符串。string.length($string)
:返回字符串 $string 的长度。string.slice($string, $start-at, $end-at: -1)
:从字符串 $string 中截取指定范围的子字符串。string.split($string, $separator, $limit: null)
:将字符串 $string 根据分隔符 $separator 进行拆分为多个子字符串,并返回子字符串的列表。string.to-upper-case($string)
:将字符串 $string 转换为大写形式。string.to-lower-case($string)
:将字符串 $string 转换为小写形式。string.unique-id()
:生成一个唯一的字符串标识符,每次调用都返回不同的值。string.unquote($string)
:移除字符串 $string 的引号,返回不带引号的字符串。
十三、BEM命名架构
BEM (Block Element Modifier) 是一种前端开发中常用的命名约定和方法论,用于管理和组织 CSS 类名。BEM 的目标是创建可重用、可维护且易于理解的代码。
BEM 架构的核心思想是将页面分解为独立的块(Blocks),并在其内部定义元素(Elements)和修饰符(Modifiers)。这种分层结构有助于创建模块化、高度可组合的代码。
下面是 BEM 架构的主要组成部分:
- Block(块): 块是页面上的独立组件或模块,它们是可重用的独立实体。每个块都有一个唯一的类名作为标识符,类名使用连字符分隔(例如:.block-name)
- Element(元素): 元素是块的组成部分,它们没有独立存在的意义。元素的类名由块的类名和元素名组成,用双下划线连接(例如:.block-name__element-name)
- Modifier(修饰符): 修饰符用于改变块或元素的外观、状态或行为。修饰符的类名由块或元素的类名、连字符和修饰符名组成,用双连字符连接(例如:.block-name--modifier-name 或 .block-name__element-name--modifier-name)
1、定义
$namespace:'kw' !default;
$block-selector: "-" !default;
$element-selector: "__" !default;
$modifier-selector: "--" !default;
@mixin B($block) {
$block-name: $namespace + $block-selector + $block;
.#{$block-name}{
@content; //内容替换
}
}
@mixin E($element) {
$element-name: & + $element-selector + $element;
@at-root { //跳出父级层
#{$element-name } {
@content;
}
}
}
@mixin M($modifier) {
$modifier-name: & + $modifier-selector + $modifier;
@at-root {
#{$modifier-name} {
@content;
}
}
}
2、引入
// 以vite为例
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins: [vue()],
css: {
preprocessorOptions: {
scss: {
additionalData: "@import './src/bem.scss';"
}
}
}
})
3、使用
<!--以vue为例-->
<script setup lang="ts" >
import { ref, reactive } from "vue"
import Menu from './Menu/index.vue'
import Content from './Content/index.vue'
import Header from './Header/index.vue'
</script>
<template>
<div class="kw-wraps">
<div class="kw-wraps--primary">
<Menu></Menu>
</div>
<div class="kw-wraps__right">
<Header></Header>
<Content></Content>
</div>
</div>
</template>
<style scoped lang="scss">
@include B(wraps){
// ...
@include E(right){
// ...
}
@include M(primary){
// ...
}
}
</style>