Getting SASSy with CSS






4.89/5 (11投票s)
本文通过讨论 SASS 试图解决的问题来描述 SASS 的语法。
引言
在本文中,我想介绍 SASS(Syntactically Awesome StyleSheets)的一些特性。SASS 允许您以编程方式定义样式表的多个方面,并将其“编译”为标准的 CSS。为了演示这一点,我将通过重构一个预先存在的 CSS 文件来完成,以展示 SASS 所能解决的问题。希望本文能为您提供有用的参考和入门指南。由于这是 SASS 的入门介绍,我将只介绍语法,不打算涵盖一些更高级的方面,例如 SASS 的缓存配置或输出样式等。
背景
总的来说,本文档面向 SASS 新手,但您应该对 HTML 和 CSS 有相当的了解,这样本文才能对您有所帮助。以下是一些您可能会发现有用的资源列表。
关于 LESS 的说明
许多概念都适用于 LESS,它是一种类似的 CSS 预处理器语言。我更喜欢 LESS 在*基础*方面的语法,因为它感觉更“CSS 式”,但出于与 本文相同的原因,我认为 SASS 在这方面更胜一筹。不过,两者都是不错的选择。LESS 的网址是 http://lesscss.org/ 。
我使用 SASS 的另一个原因是,它被用在我刚刚开始工作的网站上。因此,我对 SASS 的接触相当有限,在撰写本文时,我既巩固了到目前为止所学的内容,也帮助推广了这项技术本身。当我开始研究 SASS 类 CSS 生成技术时,它是少数几项立刻让我觉得“毫无疑问应该采用”的技术之一,当然前提是您正在从事的项目能够使用它。
设置
我待办事项列表中的第一项是创建一个 MVC3 应用程序作为示例代码。如果您不了解 MVC3 的工作原理,这应该不成问题:在标记方面,生成的 HTML 是最重要的。我不会完全引用 MVC3 视图,我也可以轻松地使用一个 HTML 文档。我在示例代码的名为“Vanilla HTML and CSS”的解决方案文件夹中包含了生成的 HTML(以及原始 CSS),这样您就可以参考这些内容,以防您对 MVC3 和 Razor 不确定。运行应用程序会得到
获取 SASS
最简单的方法是通过 NUGET(可以从 https://nuget.net.cn/ 安装)包,首先从 Visual Studio IDE 打开程序包管理器控制台
然后,在控制台窗口中复制/键入以下命令
install-package sassandcoffee
Nuget 将 SASS 安装到您的项目中,系统会提示您安装定义文件,选择“是”。如果您更喜欢 GUI,也可以使用“管理解决方案的 NuGet 程序包”选项,搜索“sassandcoffee”。
此时,值得安装“Mindscape Web Workbench”,它为 SASS 提供了智能感知、格式化和其他编辑器支持。关闭 Visual Studio,在此处下载 Workbench,然后打开 .vsix 文件进行安装。您只需为您的 Visual Studio 安装执行一次此操作。
使用 SASS
我们需要了解的第一件事是 CSS 可以直接与 SASS 一起使用,这很简单,只需将“.CSS”文件重命名为“.SCSS”即可。如果您安装了 Workbench,图标会像这样改变
运行应用程序会产生与早期截图相同的输出。scss 文件被“编译”成一个 CSS,供网站使用。
您眼尖的读者会注意到文件扩展名是 scss 而不是 sass。有一个基于缩进的旧语法,使用 .sass 扩展名。虽然它很简洁,但对 Web 开发人员来说不如 scss 语法自然:纯 CSS 在 .sass 文件中*无效*,但在 .scss 文件中*有效*。我将不介绍 sass 语法,因为我认为在新开发工作中没有令人信服的理由使用它。.scss 文件更接近 CSS 语法。
您更眼尖的读者会注意到,我没有编辑 HTML 标头中对 CSS 的引用,并且页面仍然呈现。在 ASP.NET 项目中,Workbench 会在 Visual Studio 中*保存* .scss 文件时将其“编译”为 CSS。这样做的好处是,当应用程序部署到服务器时,服务器无需在运行时执行此操作,并且几乎没有性能损失。
好了,我们已经花了一点时间了,仍然还在原地踏步,那兴奋点在哪里呢?
变量
默认 MVC 项目的 CSS 结构相当完善,但有一个指示性问题是文件顶部的注释:
/*----------------------------------------------------------
The base color for
this template is #5c87b2. If you'd like
to use a different
color start by replacing all instances of
#5c87b2 with your
new color.
----------------------------------------------------------*/
如果您想将基本颜色更改为,比如说,粉红色,您需要进行搜索和替换!SASS 可以更优雅地处理这个问题:我们只需定义一个变量并使用它
$base-color:
#FFA0A0; //Define a pink base colour in place of the blue
body
{
background-color: $base-color;
…
}
这值得仔细研究:$
符号告诉 SASS 这是一个变量。$base-color: #FFA0A0;
将变量设置为一种非常讨喜的粉红色。background-color: $base-color;
将背景颜色设置为参数值。*请注意,SASS 兼容 C 风格的单行注释!*
在此示例中,基础颜色仅在菜单的底部边框中使用
ul#menu
{
border-bottom: 1px $base-color solid;
…
}
现在我们只需要更改 base-color
变量就可以更改整个页面。我想让这个边框变暗,让它更醒目。SASS 有许多内置函数,其中一个可以变暗。我还会使边框更宽,以便更清楚地看到它:
ul#menu
{
border-bottom: 5px darken($base-color, 33%) solid;
…
}
渲染后得到
我们不只局限于颜色。我们可以将变量设置为许多内容,例如,大部分文本基于 em 大小,例如标题,并对它们执行操作,例如根据基本大小设置字体高度。
h1, h2, h3, h4, h5,
h6
{
font-size: 1.5em;
…
}
h1
{
font-size: 2em;
…
}
p, ul
{
…
line-height: 1.6em;
}
等等,变成
$base-text-size:
1em;
h1, h2, h3, h4, h5,
h6
{
font-size: $base-text-size + 0.5;
…
}
h1
{
font-size: $base-text-size + 1;
…
}
p, ul
{
…
line-height: $base-text-size + 0.6;
}
请注意,我在这里对变量执行了一个操作,此外,我不需要指定单位(在此情况下是 em),SASS 为我算出来了!
如何读取生成的 CSS 进行调试
您可能已经注意到需要查看正在生成的内容。有两种非常简单的方法。第一种(Workbench 提供)是展开 .scss 文件下的树形结构,生成的 CSS 就在那里。第二种方法是将浏览器中引用的样式表的 URL 输入到浏览器的地址栏,就像 SASS 不存在一样。对于默认的 MVC3 应用程序,它是 https://:nnnn/Content/Site.css,其中 nnnn 是分配的端口号,在示例应用程序中设置为 1999。
一个非常好的特性是,如果您犯了一个语法错误,Workbench 会将报告放入 CSS 中。假设我在基础颜色参数声明中漏掉了终止 ;
$base-color: #FFA0A0
页面将呈现,但没有样式:SASS 无法生成样式表。如果按照上面的方法导航到 css 路径,会显示一个有用的错误消息
/* Syntax error: Invalid CSS after
"body": expected selector or at-rule, was "{"
on line 9 of C:\Users\Keith\documents\visual
studio 2010\Projects\SassExample\SassExample\Content\Site.scss
Use --trace for backtrace.
*/
创建 CSS 属性块:Mixins
Mixins 就像超级变量,它们允许您一次设置多个属性。 在应用程序中,我想使标题和页脚变亮,并给它们圆角。我可以使用的 CSS/SCSS 是:
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
background-color: lighten($base-color, 10%);
前三个属性通过 WebKit 提供跨浏览器支持,直到 CSS3 规范实现。最后一行通过 SASS 函数将背景颜色变亮 10%。我可以在标题和页脚的 CSS 部分都放置这些,但这似乎是我们经常想要实现的事情。第一步是将其抽象成一个 mixin
@mixin round-corner
{
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius;
background-color: lighten($base-color, 10%);
}
现在我们将 mixin 包含在我们需要应用它的地方
#header
{
…
@include round-corner();
}
#footer
{
…
@include round-corner();
}
渲染页面后得到:
这里有几点。 我们可以轻松预见到将圆角 mixin 重用到具有更多或更少圆角的其他元素。在截图中,页脚在白色背景上,我不希望它太暗,而且由于它没有内容,角落也太大了。我仍然可以通过参数化边角半径和变亮的程度来保留我的单个 mixin
@mixin round-corner ($radius, $lightenAmount)
{
border-radius: $radius;
-moz-border-radius: $radius;
-webkit-border-radius: $radius;
background-color: lighten($base-color, $lightenAmount);
}
现在我们只需在使用的地方提供值
#header
{
…
@include round-corner(10px, 10%);
}
#footer
{
…
@include round-corner(5px, 5%);
}
结果如下:
@mixin
和 @import
语句前面的 @
符号表示该语句是一个指令。我们将在本文的后面介绍更多指令。
结构化 CSS
嵌套
到目前为止,我们所取得的成就已经相当有用了,仅凭 DRY(Don’t Repeat Yourself - 不要重复自己)原则就值得称赞。现在我们可以看看 CSS 本身的重构。让我们来看看菜单系统的 CSS:
ul#menu
{
border-bottom: 5px darken($base-color,33%) solid;
padding: 0 0 2px;
position: relative;
margin: 0;
text-align: right;
}
ul#menu li
{
display: inline;
list-style: none;
}
ul#menu li#greeting
{
padding: 10px 20px;
font-weight: bold;
text-decoration: none;
line-height: 2.8em;
color: #fff;
}
这相当标准,但有一些缺点:我使用了 ul#menu
、ul#menu li
和
的选择器。所有这些,我都重复(至少)ul#menu li#greeting
ul#menu
。另一个问题是,尽管这些样式是相关的,但在 CSS 结构中却不能清晰地反映出来。我现在已经习惯了,但在我刚开始从事 Web 开发时,我觉得很不满意,而且很容易在选择器中输入一个难以追踪的拼写错误。SASS 允许我们在 .scss 文件中嵌套 CSS 选择器,例如 ul#menu 及其子列表项:
ul#menu
{
border-bottom: 5px darken($base-color,33%) solid;
padding: 0 0 2px;
position: relative;
margin: 0;
text-align: right;
li
{
display: inline;
list-style: none;
}
}
我现在不再需要在子列表项前包含 ul#menu
。SASS 生成的这些元素的 CSS 在语义和语法上与以前相同,但在 .scss 文件中的嵌套以更明显的方式将元素关联起来,并且误输入复合选择器的风险现在降低了。 嵌套不只是一个级别,我可以进一步嵌套元素,如果我添加 greeting
ul#menu
{
border-bottom: 5px darken($base-color,33%);
padding: 0 0 2px;
position: relative;
margin: 0;
text-align: right;
li
{
display:inline;
list-style: none;
#greeting
{
padding: 10px 20px;
font-weight: bold;
text-decoration: none;
line-height: 2.8em;
color: #fff;
}
}
}
查看生成的 CSS 会突出显示嵌套的一个陷阱。ID #greeting
需要紧跟在 li
之后,但生成的 CSS 中有一个空格:ul#menu li #greeting
。要解决这个问题,我们需要在 greeting 前使用父选择器 &
,因此上面的代码变成
ul#menu
{
border-bottom: 5px darken($base-color,33%) solid;
padding: 0 0 2px;
position: relative;
margin: 0;
text-align: right;
li
{
display: inline;
list-style: none;
&#greeting
{
padding: 10px 20px;
font-weight: bold;
text-decoration: none;
line-height: 2.8em;
color: #fff;
}
}
}
现在生成的 CSS 如预期所示。父选择器更常用于伪类,例如 a:hover
、a:link
等,我们期望看到类似这样的内容
a
{
…
&:hover
{
…
}
&:link
{
…
}
}
属性嵌套
除了上面提供的标准嵌套之外,我们还可以嵌套属性,一个很好的例子是设置字体属性,就像在 body 的样式中一样
body
{
…
font-size: 75%;
font-family: Verdana, Tahoma, Arial, "Helvetica Neue";
…
}
嵌套属性后,变成这样
body
{
…
font:
{
size: 75%;
family: Verdana, Tahoma, Arial, "Helvetica Neue", Helvetica, Sans-Serif;
}
…
}
拆分 SCSS 文件
嵌套 CSS 在一定程度上为文件添加了逻辑结构,但文件本身很长。我们可能不希望有多个 CSS 文件,因为这会增加服务器的工作量,并降低页面加载/渲染时间。SASS 允许我们通过 @import
指令来拆分 scss 文件。我们可以通过这种方式导入纯 CSS 文件或 .scss 文件,在生产服务器上性能不受影响,因为如果我们设置正确,最终结果仍然是我们单个 CSS 文件。我们可以将 scss 文件分解成多个独立的文件,最明显的重构点是 Microsoft 在其中添加注释作为标题的地方(例如,为菜单分离文件中的菜单样式)。 我将在示例应用程序中这样做,但在文章中展示会很麻烦,所以请参阅解决方案中的内容。 我想为通用声明创建一个额外的 .scss 文件,我将在下面的示例中使用它。还记得我们在本文前面创建的带参数的圆角 mixin 吗?
$base-color: #FFA0A0; //Define a pink base color
$base-text-size: 1em;
我也知道我将在本文后面向此文件添加更多功能,因此我想将其拆分到一个名为“CommonDeclarations.scss”的文件中。由于安装了 Workbench,这很容易,右键单击 Visual Studio 的解决方案资源管理器中的“Content”文件夹,然后选择“添加新项”。在“Web”(我必须滚动,您的可能不同)下,您会找到这个
将文件名更改为“_CommonDeclarations.scss”并单击“添加”,下划线前缀是约定俗成的,告诉 SASS 该文件用于导入(部分文件)。接下来,我只需从旧文件中剪切我想要的内容并粘贴到新文件中。 最后一步是将 @import "CommonDeclarations";
行添加到定义了通用声明的地方。请注意,我不需要文件扩展名或 _ 前缀。 现在我可以继续以同样的方式分解主 site.scss 文件。我将为每个注释创建一个文件,作为原始 CSS 中 Microsoft 在创建项目时添加的标题,作为示例,因为其中每个注释通常处理一个逻辑分组。
其他指令
如前所述,@
前缀表示一个指令,还有其他内置的指令可以让我们增加 DRY(Don’t Repeat Yourself)的优势。我将一一介绍它们
@extend 指令
这允许我们基于另一个样式派生样式。处理任何 Web 表单验证元素的 CSS 是一个很好的例子。在重构为单独的样式表后,这目前位于 _ValidationHelpers.scss 文件中
.field-validation-error
{
color: #ff0000;
}
.validation-summary-errors
{
color: #ff0000;
font-weight:bold;
}
这两项都是红色的,如果我们想改变颜色,很可能需要同时改变两者。在这个基本示例中,我们可以使用参数,但也有一个真正的关系,摘要样式*与*字段验证相关,所以我将删除摘要样式的颜色并扩展字段验证样式:
.field-validation-error
{
color: #ff0000;
}
.validation-summary-errors
{
@extend .field-validation-error;
font-weight: bold;
}
只有当一种样式真正依赖于另一种样式时,我才需要这样做,这是它的试金石,即如果我们想更改基本样式,扩展样式是否也应该改变。 需要注意的一点是,生成的 CSS 现在略有不同:
.field-validation-error,
.field-validation-error, .validation-summary-errors {
color: #ff0000; }
.validation-summary-errors {
font-weight: bold; }
请注意,CSS 已部分压缩,这是 SASS 提供的另一项功能,尽管本文未涵盖。可以从已扩展的样式(称为链式)进行扩展,并在同一块中进行多次扩展,尽管项目中没有足够复杂的 CSS 需要这样做。还可以扩展复杂的选择器,例如 a:hover
,语法完全相同。有关 extend 的更多文档可以在此处找到
其他指令 – 函数和控制流
为了完整起见,我们将介绍一些更高级的基础知识。
函数
SASS 具有内置函数,例如 hsl
函数接受色相、饱和度和亮度三个参数,并将其转换为 RGB
例如,我们将使用 hsl 函数将主布局中使用的 H1 设置为中等紫色。
#header h1
{
…
color: hsl(308, 44%, 28%);
…
}
编译后得到 #header h1 {
…
color: #67285e;
…
}
文档建议使用显式的关键字参数,这意味着与上面相同,但为了清晰起见,它建议如下
#header h1 {
…
color: hsl($hue: 308, $saturation: 44%, $lightness: 28%);
…
}
无论您使用哪种语法,结果都将是这种非常讨喜的设计
扩展可用函数
我们可以扩展函数列表以添加自己的函数。假设我们想将宽度标准化为 10px 的倍数。我们可以提供一个函数来做到这一点
$base-width: 10px;
@function keith-width-multiplier($multiple)
{
@return $multiple * $base-width;
}
请注意,我已经为函数名加上了 keith 前缀,SASS 文档建议为所有*自定义函数*添加前缀,以区分它们与现有函数(如 hsl
)的区别。它建议使用您的公司名称,但由于我是在业余时间工作,所以我决定表现出极大的谦逊并使用我自己的名字 。
现在,举一个假设的例子:
.foo
{
width: keith-width-multiplier(3);
}
这将导致类为 foo 的所有元素宽度为 30px。
控制流指令
这些被认为是 SASS 中的高级功能,甚至文档也建议您不要正常使用它们:https://sass-lang.cn/docs/yardoc/file.SASS_REFERENCE.html#control_directives。 我包含了它们,因为有了这些,SASS 语法就功能齐全了。与上面的自定义函数一样,我没有在示例代码中包含下面的示例,它们根本不需要。以下示例也可能不是达到所需目的的最佳方法(它们未包含在示例代码中),它们旨在尽可能清晰,而不是用于实际场景。
@if
正如我们所料,这允许进行决策。假设我们想根据变量 $backgroundcolor
设置 span 的颜色。如果它是白色,color
应该是黑色,如果 $backgroundcolor
是黑色,color
应该是白色,否则 color
应该是灰色。
span
{
@if $backgroundcolor = #FFFFFF
{
color:#000000;
}
@elseif $backgroundcolor = #000000
{
color:#FFFFFF;
}
@else
{
color:#696969;
}
}
当然,在实际情况中,上面的内容会受益于重构!
@for 和字符串插值 #{…}
这是我们的第一个循环结构,它在值之间循环。有了它,我们甚至可以创建多个 CSS 定义。在这个例子中,我们将为从 h1 到 h4 的标题创建样式,字体大小递减:
$biggest-width: 8em;
@for $i from 1 through 4
{
h#{$i} {
font-size: $biggest-width /$i;}
}
编译后会生成 h1h1 {
font-size: 8em; }
h2 {
font-size: 4em; }
h3 {
font-size: 2.667em; }
h4 {
font-size: 2em; }
}
注意 #{$i}
这个术语,它接受值(在本例中是 $i
)并*直接输出到 CSS*。它不仅可以用于循环,还可以用于属性名和值。另一个需要注意的是,对于四种标题类型,这个循环是过度设计的。如果您能想象设置多个表格列或行样式,循环结构会更有意义。
@while
While 执行与 for 循环类似的功能。像任何主流语言中的 while 循环一样,值必须在循环中改变,以便条件能够终止。 我们可以将上面的 for 循环重写为
$val : 1;
@while $val = 4 {
h#{$val} {
font-size: $biggest-width / $val<}
}
这会输出与 for 循环相同的 CSS,但在这种情况下不太优雅:仅仅因为您可以做到,并不意味着您应该这样做 。在实际情况中,while 循环可能用于更复杂的循环。
@each
Each 迭代一个列表,列表可以是任何东西。为简单起见,我想举一个创建具有红色文本的 .red 类样式、黑色和绿色的示例
@each $color in red black green <{
.#{$color&} { color: $color;}
}
这将输出
.red {
color: red}
.black {
color: black;}
.green {
color: green; }
在这种情况下,我们已将变量 $color
分配给字符串列表中的一个值
结论
很多年前,当我开始从事 Web 开发时,我来自一个(当时)主要是 C++ 的背景,我感到很沮丧。为什么我需要不断重复调色板中的值?为什么我不能根据另一个样式或调色板值来确定一个颜色的基础?为什么 CSS 语法不能很好地反映选择器的嵌套?所有这些问题或多或少都被 SASS 解决了
- 参数
- 函数和 mixins
- 嵌套语法
此外,SASS 允许我们定义自己的函数,从而提供扩展点。它还允许我们将 .css 分解成逻辑文件块,而不会影响性能。最后,SASS 允许我们向 CSS 添加控制流,几乎使其成为图灵完备的。
SASS(或 SASS 类技术)几乎是毫无疑问的选择,前提是您有一个允许您使用的环境,而且这个门槛非常低。它允许您在自己满意的程度上简化和合理化您的 CSS,几乎没有实际成本。
修订历史
- 2012/07/24 初始版本。
- 2012/07/25 添加了缺失的示例解决方案!