Scss
yuhuo2022-03-28开发库样式库
编译方式
方式一:
安装 sass 包
npm install sass
使用 sass 包编译
const sass = require('sass');
const result = sass.compile(scssFilename);
方式二:
使用编译工具,比如 webpack,通过 sass-loader 调用 sass 包进行编译。
关于
node-sass 包已弃用,改用 sass 包。
因为 node-sass 是在 Node 环境下调用基于 C/C++ 实现的 LibSass,安装时会有各种版本环境问题。而 sass 基于 Dart,可以编译成 js,直接在 Node 下运行。
如果需要使用 node-sass,在 npm 安装时,有一步是到 github 上下载文件的,通常会失败,可以单独设置个映射:npm config set sass_binary_site=https://registry.npmmirror.com/node-sass
。
导入
内部导入
// 相对路径,直接导入
@import "./scss/one", "./scss/two";
// 绝对路径,嵌套导入
.container {
@import "@/views/style/scss/scss/one";
}
标签导入
<style lang="scss" scoped src="./scss/one.scss"></style>
注意
- 文件 A 中 import 文件 B,B 的代码会照搬到 A 中 import 的位置,因此 B 中代码使用到相对路径是相对于 A 的,需谨慎使用。A 的 import 后面的代码可以使用 B 中的定义的变量,混合器,继承等。
- 局部文件使用
_
开头,如_ one.scss
,编译后不会生成单独的 css 文件。 - 引用时可省略文件名后缀
.scss
,以及局部文件的开头_
。 - 正常情况下,css@import 会等浏览器解析时才加载该 css 文件,多个 scss 会生成多个 css 文件,但在当前 vue3 项目的同个页面下,都会被 webpack 打包成一个统一的 css 文件。
注释
$version: "1.2.3";
/*
css 标准注释,会出现在生成的css文件中,但压缩模式下会删除。
使用变量:#{$version}
*/
// scss 静默注释,不会出现在生成的css文件中
变量/嵌套
// 块级作用域,下划线_和中划线-连接符都可
$base_color: #111;
// 后者覆盖前者
$base_color: #222;
// 默认变量,权重最低,能被前者覆盖
$base_color: #333 !default;
.box {
height: 200px;
// 群组嵌套
.content, .part {
.name {
// 变量引用变量
$base_border: 2px solid $base_color;
// 定义全局变量
$fontSize: 16px !global;
// 父选择器
&:hover {
color: red;
}
}
// 使用全局变量
font-size: $fontSize;
}
}
混合器
// 无参数
@mixin namePadding {
padding-top: 10px;
}
// 带参数
@mixin nameFont($fontSize, $i, $label) {
// 插值语句 #{}
// 选择器中使用
.name:nth-child(#{$i}) {
font-size: $fontSize;
}
.name_#{$label} {
// 属性名中使用
#{$attr}-size: $fontSize;
}
}
// 参数带默认值
@mixin nameColor($normal, $hover: $normal, $visited: red) {
.name {
color: $normal;
// 拼接成选择器名,等同于 .name_label
&_label {
color: black;
}
&:active {
color: $visited;
}
}
}
// 带内容
@mixin nameText($align) {
.name {
text-align: $align;
@content;
}
}
.box {
// 引用混合器
.name {
@include namePadding;
}
// 按顺序传参
@include nameFont(30px, 1, "label");
// 按名称传参
@include nameFont($i: 1, $fontSize: 20px, $label: "label");
// 使用参数默认值
@include nameColor(blue);
// 传混合器导入内容
@include nameText(center) {
text-shadow: none;
}
}
继承
.error {
margin-top: 20px;
span {
font-style: italic;
}
}
div.error {
color: red;
}
// 占位选择器,专门用来被extend,不会被单独编译
%extreme {
letter-spacing: 1px;
}
// 继承了.error相关的所有样式
// 即所有的.error替换成.error,.seriousError
.seriousError {
@extend .error;
@extend %extreme;
text-decoration: underline;
}
错误用法
// 不要用后代选择器去继承(如下)否则情况会变得复杂
.main .seriousError {
@extend .error;
}
// 不要跨@media层去继承外部的样式,必须在同一层中
@media print {
.seriousError {
@extend .error;
}
}
注意
- 混合器用于展示性样式的重用,是对属性的复制。
- 继承用于语义化样式的重用,是对选择器的复制。
运算
数字运算
$font-size: 12px;
.avatar {
width: (40px + 10px) * 2 / 2;
// 使用#{}给变量,以确保 / 被当成分隔符而不是除法运算
font: #{$font-size} / 30px sans-serif;
// random() 生成 0 ~ 1 的随机小数(包含0不包含1)
font-size: random() + px;
// random(x) 生成 1 ~ x 的随机整数(包含1和x)
font-size: 12 + random(10) + px;
}
颜色运算
$color: rgba(255, 0, 0, 0.5);
.avatar {
color: (#101010 + #202020) * 2 / 2;
// alpha值必须相同才能运算
color: rgba(255, 0, 0, 0.75) + rgba(0, 255, 0, 0.75);
// 增加alpha
color: opacify($color, 0.2);
// 减少alpha
color: transparentize($color, 0.2);
// rgba转#AABBCCDD
color: ie-hex-str($color);
// 色相-饱和度-亮度函数
color: hsl(0, 100%, 50%);
}
字符串运算
$height: "50px";
.avatar {
// #{}将有引号转为无引号(可用于选择器)
height: #{$height};
// 编译结果有无引号看 + 的左侧
cursor: poin + "ter"; // 无引号
// #{}添加动态的值
content: "Foo #{5 + 10} " + Bar; // 有引号
}
数组运算
.avatar {
$arr1: 10px auto;
$arr2: 0 auto;
// $separator 拼接符:comma 逗号,space 空格,auto 自动(默认)
// 拼接数组
margin: join($list1: $arr1, $list2: $arr2, $separator: auto);
// 遍历数组
@each $var in $arr1 {
margin-top: $var;
};
// 数组添加新值
margin: append($list: $arr1, $val: 0, $separator: space);
// 取数组中的某项值
margin-top: nth($list: $arr1, $n: 1);
}
指令
@media
$media: screen;
$feature: -webkit-min-device-pixel-ratio;
$value: 1.5;
// 使用插值语句
@media #{$media} {
.sidebar {
// 嵌套媒体查询
@media ($feature: $value) {
width: 500px;
}
}
}
// 编译为如下
// @media screen and (-webkit-min-device-pixel-ratio: 1.5) {
// .sidebar[data-v-141e8fb2] {
// width: 500px;
// }
// }
@at-root
.parent {
// 从嵌套移动到根作用域上
@at-root .child {
width: 10px;
}
@at-root {
.child1 {
width: 10px;
}
.child2 {
width: 10px;
}
}
}
@if
// 常用于对混合器的参数判断
$type: 1;
.if {
@if $type == 1 {
color: blue;
} @else if $type == 2 {
color: red;
} @else if $type == 3 {
color: green;
} @else {
color: black;
}
}
@for
@for $i from 1 through 3 {
.for-#{$i} {
width: 2em * $i;
}
}
@each
// 遍历一维数组
@each $animal in puma, slug, egret, salamander {
.#{$animal}-icon {
background-image: url("/images/#{$animal}.png");
}
}
// 遍历二维数组
@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 $key, $value in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$key} {
font-size: $value;
}
}
@while
$i: 6;
@while $i > 0 {
.while-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
@function
$grid-width: 40px;
$gutter-width: 10px;
// 自定义函数
@function grid-width($n) {
@return $n * $grid-width + ($n - 1) * $gutter-width;
}
// 使用函数
.avatar {
width: grid-width(5);
}