SASS 学习笔记
总共会写两个练手项目,成品在 https://goldenaarcher.com/scss-study 可以看到,代码在 https://github.com/GoldenaArcher/scss-study。
什么是 SASS
SASS 是 CSS 预处理,它提供了变量(虽然现在 CSS 也提供了,不过 SASS 的更加灵活),嵌套、mixin、函数、导入和扩展等功能,可以高效地做到代码复用。SASS 包括 SASS 和 SCSS,二者都支持嵌套、mixin 和变量,主要的区别在:
-
语法
SCSS 的语法更加贴近 CSS,而 SASS 不适用
{}
和;
,并且依赖缩进定义结构(有点类似 python 的写法)因此 SASS 的排版必然是更加简洁和美观的,相对而言刚从 CSS 转到 SASS 也有可能会不太适应
-
兼容性
SCSS 更加接近 CSS 的语法,因此兼容性相对更好一些,比较适合作为 CSS 到 SASS 的过渡。当然,对于不是非常复杂的项目,使用 SCSS 本身也够了
SASS 的支持相对更强一些,不过因为兼容性和语法的问题,流行度相对低一些
-
学习曲线
SASS 比 SCSS 高
这篇笔记主要学习的是 SCSS 为主。
基础
配置
SASS 作为 CSS 的预处理,无法直接在浏览器中运行,因此需要下载对应的包将写好的 SASS 转化为 CSS,使得浏览器可以解析。
编译的方式有通过编辑器,或者是使用 node 依赖完成,这里使用后者,方式为下载 sass
,并且在 package.json
中添加一下代码:
json
{
"scripts": {
"watch": "sass scss/:css/ -w"
}
}
这样 sass
会将 scss
文件夹下的内容编译后保存到 css
文件夹下,-w
的 flag 代表监听状态,他会监听 scss 文件夹下的变化,并且重新进行编译。
项目整体结构大概如下:
除了 sass
之外,还有比较臭名昭著的 node-sass
,虽然 node-sass
还是在维护的,并且目前也支持到 node20,而且常规的 SCSS 功能都能实现完成编译,不过 node-sass
的兼容性真的很有问题......反正我本人在 Windows 上尝试运行 node-sass 的时候碰到很多问题。
另一个 SASS 的配置方法在 sass 简易配置 里有 cv,那个用的包比较多,具体干什么的还没怎么看,不过想要比较完整的项目配置,可以看看这个。
变量
scss 的变量以 $
开始,我是觉得目前 CSS 对变量的支持也挺好的,不过考虑到兼容性的问题,统一使用 SCSS 会方便些,具体使用方法如下:
scss
// 定义
$color-dark: #262626;
$color-black: #000;
$color-primary: #d3ab55;
$color-secondary: #bbb;
$color-white: #fff;
$font-dancingScript: 'Dancing Script', cursive;
$font-josefinSans: 'Josefin Sans', sans-serif;
$font-nunito: 'Nunito', sans-serif;
// 使用
body {
// local scope也可以重写变量
// 想要在本地重写global变量可以使用下面的语法:
// $color-white: #eee !global;
background-color: $color-dark;
}
它的编译结果如下:
css
body {
background-color: #262626;
}
可以看到 $color-dark
已经被编译了,而不是直接使用变量,所以如果要有老版浏览器兼容的考虑,使用 SCSS 变量会方便一些。
像是主题颜色(primary、 secondary、warning、success 这种颜色)和字体大小、breakpoint 一般都推荐使用全局定义的变量来实现。练手的项目 1 中对于颜色、字体都使用了变量进行定义,但是 media query 没有,大概因为边写边感觉的原因......?
嵌套
嵌套是一个我觉得使用 SCSS 非常方便的点,如下面这个 HTML 的结构:
html
<nav class="navbar">
<input type="checkbox" name="check" id="check" class="checkbox" hidden />
<div class="hamburger-menu">
<label for="check" class="menu">
<div class="menu-line menu-line-1"></div>
<div class="menu-line menu-line-2"></div>
<div class="menu-line menu-line-3"></div>
</label>
</div>
</nav>
要选择 navbar > hamburger > menu
,并且分别应用样式,CSS 的写法为:
css
.navbar {
}
.navbar .hamburger {
}
.navbar .hamburger .menu {
}
@media (max-width: 760px) {
.navbar .hamburger {
}
.navbar .hamburger .menu {
}
}
SCSS 的写法为:
scss
.navbar {
.hamburger {
@media (max-width: 760px) {
}
.menu {
@media (max-width: 760px) {
}
}
}
}
我个人还是比较偏好这种嵌套式的写法,尤其是一些样式都比较依赖选择多个 class selector 去增加权重覆写样式的情况下,这样的确能少写一些代码。media query 也嵌套在这里,找 responsive 的实现代码也更方便一些。
extend
extend 是一个比较强大的方法,其实现和使用方法如下:
scss
.full-space {
width: 100%;
height: 100%;
}
.header {
@extend .full-space;
}
编译后的结果为:
css
.full-space,
.header {
width: 100%;
height: 100%;
}
如果有多个样式都 extend 了同一个样式,那么 SCSS 也会将其打包在一起,而不是额外重复一遍 CSS,如:
scss
.full-space {
width: 100%;
height: 100%;
}
.header {
@extend .full-space;
}
.footer {
@extend .full-space;
}
对应的 CSS:
css
.full-space,
.header,
.footer {
width: 100%;
height: 100%;
}
mixin
mixin 是另一个 SCSS 强大的地方,它的使用方法为:
scss
@mixin textStyles($transform: uppercase) {
font-weight: 300;
letter-spacing: 2px;
text-transform: $transform;
}
.main-name {
font-family: $font-nunito;
font-size: 50px;
color: $color-secondary;
@include textStyles;
}
编译后的结果为:
css
.main-name {
font-family: 'Nunito', sans-serif;
font-size: 50px;
color: #bbb;
font-weight: 300;
letter-spacing: 2px;
text-transform: uppercase;
}
与 extend 最大的不同有两点:
- mixin 可以接受参数
- mixin 会将定义好的样式添加到当前 selector 中
总体来说,如果一个样式的代码是固定且不会变动的,并且想减少 CSS 的大小,那么就可以使用 extend。相反,如果想要一个代码更加的动态,需要依靠传入的变量进行修改时,就可以使用 mixin,另一个比较适合使用 mixin 的案例是 transition,一般 duration、应用的样式及延迟都不太一样,这时候可以使用 mixin 减少编程时的代码量。
mixin 在提供 default value 是可以不传值的,不传值的情况下 SCSS 会使用默认值。不提供默认值好像是会报错的来着......
function
function 可以实现一些计算,如:
scss
@function fontSize($size: 12px) {
@return $size * 2;
}
对于一些小型的项目来说,function 的使用并不一定会很方便,不过对于一些大型项目,特别是 margin、padding 都有定义好的 responsive 项目,使用 function 会方便很多。
SCSS 也有一些预设的 function,如颜色有 darken
, lightedn
等 数字有 percent
等,数学有 min
, max
等,以便开发。
placeholder selector
用 extend
会创建一个空置的 class,使用 placeholder selector 可以解决这个问题,用法如下:
scss
%full-space {
width: 100%;
height: 100%;
}
.header {
@extend %full-space;
}
.footer {
@extend %full-space;
}
对应的 CSS:
css
.header,
.footer {
width: 100%;
height: 100%;
}
import & partials
partial 指的是 SCSS 文件名在命名时使用 _
作为前缀的命名规范,如 _base.scss
,这样 SCSS 就不会多生成一个 _base.scss
的文件。随后使用 import
关键词在 main.scss
中导入对应的包,就可以将 _base.scss
的样式添加到 main.scss
中,如:
-
_base.scss
scss$color-dark: #262626; $color-black: #000; $color-primary: #d3ab55; $color-secondary: #bbb; $color-white: #fff; $font-dancingScript: 'Dancing Script', cursive; $font-josefinSans: 'Josefin Sans', sans-serif; $font-nunito: 'Nunito', sans-serif;
-
main.scss
scss@import 'base'; @import 'layout'; @import 'components';
因为 base
是最先导入的,layout
和 component
也可以使用 base
中定义好的变量名。
一些有趣的 CSS 小技巧
使用 checkbox
checkbox 本身可以使用 HTML5 的 hidden
,同时使用选择器,这样可以在不懈 JS 的情况下完成 onclick
的事件实现
hamburger icon
这个在点击的时候有两个特效:
第一个 90 度翻转比较好理解,第二个也是用 CSS 实现的,简单的说就是将中间的那条线透明度设置为 0,同时左右两根线分别按照 z 轴向左向右旋转一定角度,获取下面的箭头形状:
然后搭配 transform-origin: right;
使用即可。
这个用法真的好巧妙啊。