介绍Sass模块

哈Ha! 我向您介绍了Miriam Suzanne的文章“介绍Sass模块”

最近,Sass中出现了一个您以其他语言熟悉的功能: 模块化系统 。 这是@import一大进步,@ @import是Sass中最常用的功能之一。 尽管现有的@import指令允许您连接第三方程序包并将样式分隔为受支持的元素,但它仍然存在一些局限性

  • @import也存在于CSS中,其行为上的任何差异都可能造成混淆。
  • 如果对一个文件执行@import几次,这会减慢编译速度,导致重新定义冲突,并且您在输出中会得到重复的代码。
  • 一切都在全球范围内,包括第三方软件包-这就是我的color功能可以覆盖现有color功能的方式,反之亦然。
  • 当您使用诸如color之类的函数时,不可能确切知道它的定义位置。 哪个@import连接了它?

Sass软件包的作者(像我一样)试图通过手动设置变量和函数的前缀来解决名称空间问题-但是Sass模块是一个更强大的解决方案。 简而言之, @use @forward被更明确的@use@forward @import代替。 在接下来的几年中,Sass中的@import将被弃用,然后将其删除。 您仍然可以使用CSS Import ,但是Sass不会编译它们。 但请放心,有一个迁移工具可以帮助您升级。

使用@use导入文件


 @use 'buttons'; 

新的@use@import相似,但是有一些明显的区别:

  • 无论您在项目中使用@use多少次,文件都会被导入一次。
  • 以下划线( _ )或连字符( - )开头的变量,混入和函数(在Sass中被称为“成员”)被认为是私有的,不会被导入。
  • 通过@use (在我们的示例中为@use连接的文件中的成员只能在本地访问,而不会传输到后续导入。
  • 同样, @extends仅适用于上游; 也就是说,扩展名仅适用于导入的样式,不适用于导入的样式。
  • 默认情况下,所有导入的成员都有自己的名称空间

当我们通过@use附加文件时,Sass会根据文件名自动生成一个名称空间。

 @use 'buttons'; /*    `buttons`*/ @use 'forms'; /*    `forms`*/ 

现在,我们可以访问buttons.scss文件和forms.scss文件的成员,但是这种访问权限不会在导入之间转移: forms.scss仍然无法访问buttons.scss定义的变量。 由于导入的实体具有名称空间,因此我们必须使用新的点分隔语法来访问它们:

 /* : <namespace>.$variable */ $btn-color: buttons.$color; $form-border: forms.$input-border; /* : <namespace>.function() */ $btn-background: buttons.background(); $form-border: forms.border(); /* : @include <namespace>.mixin() */ @include buttons.submit(); @include forms.input(); 

我们可以通过将as <name>添加到导入中来更改或删除默认名称空间。

 @use 'buttons' as *; /*      */ @use 'forms' as 'f'; $btn-color: $color; /* buttons.$color    */ $form-border: f.$input-border; /* forms.$input-border    */ 

使用as *将模块添加到根名称空间,因此不需要前缀,但是其成员仍受当前文档的本地限制。

导入Sass嵌入式模块


Sass的内部功能也已移至模块化系统,因此我们可以完全控制全局名称空间。 有几个内置模块mathcolorstringlistmapselectormeta ,在使用前必须将其显式导入文件中。

 @use 'sass:math'; $half: math.percentage(1/2); 

嵌入式模块也可以导入全局空间:

 @use 'sass:math' as *; $half: percentage(1/2); 

可以使用已经具有前缀名称的内置函数,例如map-getstr-index ,而无需复制此前缀:

 @use 'sass:map'; @use 'sass:string'; $map-get: map.get(('key': 'value'), 'key'); $str-index: string.index('string', 'i'); 

您可以在Sass模块规范中找到内置模块,功能和名称更改的完整列表。

新增和更改的核心功能


另外一个好处是,这意味着Sass可以安全地添加新的内部mixin和函数,而不会引起名称冲突。 最令人惊讶的示例是sass:meta模块中的load-css sass:meta 。 它的工作方式类似于@use ,但仅返回生成的CSS并在代码中的任何位置动态地工作:

 @use 'sass:meta'; $theme-name: 'dark'; [data-theme='#{$theme-name}'] { @include meta.load-css($theme-name); } 

第一个参数是模块URL(如@use ),但是可以使用变量(甚至使用插值)来动态更改它,例如theme-#{$name} 。 第二个(可选)参数采用具有以下配置的map结构:

 /*   $base-color  'theme/dark'   */ @include meta.load-css( 'theme/dark', $with: ('base-color': rebeccapurple) ); 

$with参数允许您使用map结构配置已加载模块中的任何变量,并且该变量必须满足以下条件:

  • 它不是以_-开头的私有变量-
  • 标有!default默认指令

 /* theme/_dark.scss */ $base-color: black !default; /*    */ $_private: true !default; /*        */ $config: false; /*    ,      !default */ 

注意,键'base-color'设置变量$base-color

sass:meta模块还有另外两个新功能sass:metamodule-variables()module-functions() 。 它们每个都从已经导入的模块的名称和值返回map结构。 它们采用与模块名称空间相对应的一个参数:

 @use 'forms'; $form-vars: module-variables('forms'); /* ( button-color: blue, input-border: thin, ) */ $form-functions: module-functions('forms'); /* ( background: get-function('background'), border: get-function('border'), ) */ 

sass:meta其他几个函数sass:meta - global-variable-exists()function-exists()mixin-exists()get-function() -将接收其他$module参数,这些参数允许我们显式检查每个命名空间。

调整和缩放颜色


sass:color模块对于解决我们的一些旧问题也有一些有趣的保留。 不再推荐使用许多传统函数,例如color.adjust()color.scale() adjust-hue()支持显式函数color.adjust()color.scale()

 /*  lighten(red, 20%) */ $light-red: color.adjust(red, $lightness: 20%); /*  adjust-hue(red, 180deg) */ $complement: color.adjust(red, $hue: 180deg); 


其中一些不推荐使用的功能(例如adjust-hue )是多余且不必要的。 其他-如lightendarkensaturate等。 -需要重新实现以改善内部逻辑。 原始函数基于adjust() ,它使用了线性数学运算:在上面的示例中,当前red亮度增加了20% 。 在大多数情况下,我们希望相对于当前值以一定百分比更改( scale() )颜色:

 /*        20,   0.2,     */ $light-red: color.scale(red, $lightness: 20%); 

在完全弃用并删除这些函数之后,这些函数最终将重新出现在sass:color具有基于color.scale()而不是color.adjust()的新行为。 这将逐渐发生,以避免突然的向后兼容性问题。 同时,我建议手动检查您的代码以查看color.scale()在哪里更有用。

配置导入的库


第三方库或可重用库通常带有一些您可以覆盖的默认值的变量。 我们在导入之前使用变量来完成此操作:

 /* _buttons.scss */ $color: blue !default; /* old.scss */ $color: red; @import 'buttons'; 

由于使用模块时不再能访问局部变量,因此我们需要一种新的方式来设置值。 我们可以通过将设置通过map传递给@use@use

 @use 'buttons' with ( $color: red, $style: 'flat', ); 

这类似于load-css()$with参数,但不是将变量名用作键,而是将变量本身与$符号一起使用。

我喜欢设置的显式性,但是有一条规则使我感到困惑: 第一次使用模块只能配置一次 。 即使使用@import ,连接顺序对于Sass来说也一直很重要,但是这些问题并未引起注意。 现在我们得到一个明显的错误,这既好又有点意外。 确保通过@use连接库,并在文件输入点(导入所有其他文件的中央文档)中配置它们,以便在通过@use连接其他库之前先编译这些设置。

目前(目前)无法将配置“绑定”在一起,使其可编辑,但是您可以包装已配置的模块并将其作为新模块进行传输。

使用@forward传输文件


我们并不总是需要使用文件并引用其成员。 有时我们只想将其传递给后续导入。 假设我们有几个与表单关联的文件,我们想将它们作为一个命名空间连接在一起。 我们可以使用@forward做到这@forward

 /* forms/_index.scss */ @forward 'input'; @forward 'textarea'; @forward 'select'; @forward 'buttons'; 

这些转发文件的成员在当前文档中不可用,也没有创建名称空间,但是当另一个文件通过@use连接它们或通过@use整个集合时,这些变量,函数和mixins将可用。 如果提交的单个文件包含实际的CSS,则在不使用包本身的情况下,也将直接传输它而不生成它。 在此阶段,所有这些都将被视为具有一个名称空间的一个模块:

 /* styles.scss */ @use 'forms'; /*        `forms` */ 

注意 :如果您要求Sass附加文件夹,它将在其中查找index_index文件。

默认情况下,所有公共成员将与模块一起转发。 但是,通过使用showhide条件并指定要添加或排除的特定成员,我们可以更具选择性。

 /*    `border()`   `$border-color`   `input` */ @forward 'input' show border, $border-color; /*     `buttons`    `gradient()` */ @forward 'buttons' hide gradient; 

注意 :当函数和混合模块具有通用名称时,它们会一起添加和隐藏。

为了澄清来源或避免转发模块名称的冲突,我们可以使用as连接文件的成员添加前缀:

 /* forms/_index.scss */ /* @forward "<url>" as <prefix>-*; */ /* ,      `background()` */ @forward 'input' as input-*; @forward 'buttons' as btn-*; /* style.scss */ @use 'forms'; @include forms.input-background(); @include forms.btn-background(); 

而且,如果需要,我们总是可以通过@use使用,并通过@use @forward相同的模块,添加两个规则:

 @forward 'forms'; @use 'forms'; 

如果要预配置库或添加其他工具,然后再将其传输到其他文件,此功能特别有用。 这可以帮助简化连接路径:

 /* _tools.scss */ /*        */ @use 'accoutrement/sass/tools' with ( $font-path: '../fonts/', ); /*    */ @forward 'accoutrement/sass/tools'; /* -  ... */ /* _anywhere-else.scss */ /*      */ @use 'tools'; 

@use@forward必须在文档的根目录(未嵌套)和文件的开头声明。 在导入指令之前,只能出现@charset和简单变量定义。

过渡到模块化系统


为了测试新的语法,我为我的小组创建了一个新的开源Sass库( Cascading Color Systems )和一个新站点 -两者仍在开发中。 我需要从库作者和站点开发人员的角度来理解模块。 让我们从使用模块语法编写站点样式的“最终用户”的经验开始...

支持和写作风格


使用站点上的模块非常有趣。 新语法支持我已经使用的代码体系结构。 我所有的全局设置和工具导入都在同一目录(我称为config )中,该目录带有一个索引文件,该文件传输了我需要的所有内容:

 /* config/_index.scss */ @forward 'tools'; @forward 'fonts'; @forward 'scale'; @forward 'colors'; 

通过开发站点的其他部分,我可以在需要的地方导入这些工具和配置:

 /* layout/_banner.scss */ @use '../config'; .page-title { @include config.font-family('header'); } 

它甚至可以与我现有的库一起使用,例如AccoutrementHerman ,它们仍然使用旧的@import语法。 由于@import规则不会一次到处替换,因此Sass开发人员已经花了一些时间进行过渡。 这些模块现在可用,但是@import不会再过一两年@import -只会在一年后从该语言中删除。 同时,两个系统将以任何方式协同工作:

  • 如果我们对包含新的@use/@forward语法的文件执行@import ,则仅导入公共成员而没有名称空间。
  • 如果我们对包含旧@import语法的文件执行@use@forward ,则可以作为单个名称空间访问所有嵌套的导入。

这意味着您可以立即开始使用新的模块语法,而不必等待发布您喜欢的库的新版本:而且我可以花一些时间来更新我的所有库!

迁移工具


如果使用Jennifer Thakar创建的迁移工具,升级将不会花费很长时间。 可以使用NPM,Chocolatey或Homebrew安装:

 npm install -g sass-migrator choco install sass-migrator brew install sass/sass/migrator 

这不是用于迁移到模块的一次性工具。 现在,Sass恢复了活跃的开发(请参阅下文),迁移工具还将获得定期的更新,以帮助移植每个新功能。 最好在全局安装此工具,并保存以备将来使用。

迁移器可以从命令行启动,希望将其添加到CodeKit和Scout等第三方应用程序中。 将他指向单个Sass文件,例如style.scss并告诉他要应用哪些迁移。 目前,只有一个迁移称为module

 # sass-migrator <migration> <entrypoint.scss...> sass-migrator module style.scss 

默认情况下,迁移器仅更新一个文件,但是在大多数情况下,我们希望更新主文件及其所有依赖项:通过@forward @use@forward@use连接的任何元素。 我们可以通过单独指定每个文件或简单地添加--migrate-deps标志来实现。

 sass-migrator --migrate-deps module style.scss 

对于测试运行,我们可以添加--dry-run --verbose (或缩写为-nv )并查看结果,而无需更改源文件。 我们可以使用许多其他选项来配置迁移-甚至还有一个专门用于帮助库作者删除旧的手动创建的名称空间的选项-但在此我将不对其进行描述。 迁移工具已 在Sass网站完整记录

更新已发布的图书馆


我在库方面遇到了几个问题,特别是当我试图使用户配置可用于多个文件并找到解决方案以解决缺少“链”配置时。 与订单相关的错误可能很难调试,但是值得付出努力,而且我认为我们很快会看到一些其他修复程序。 我仍然需要对复杂软件包的迁移工具进行试验,也许还要为图书馆作者写一篇额外的文章。

现在要知道的重要一点是,Sass在过渡期间为我们提供了保护。 旧的导入和模块不仅可以一起使用,我们还可以创建“ 仅导入 ”文件,为仍通过@import连接我们的库的用户提供更便捷的工作。 在大多数情况下,这将是主软件包文件的替代版本,并且您希望它们位于附近:对于模块用户,为<name>.import.scss对于旧用户,为<name>.import.scss 。 每次用户调用@import <name> ,他都会加载文件的.import

 /*  `_forms.scss` */ @use 'forms'; /*  `_forms.import.scss` */ @import 'forms'; 


这对于为不使用模块的开发人员添加前缀特别有用:

 /* _forms.import.scss */ /*       */ @forward 'forms' as forms-*; 


Sass更新


您可能还记得,几年前Sass冻结了新功能的添加,因此其各种实现(LibSass,Node Sass,Dart Sass)赶上了原始的Ruby实现,从而完全放弃了它 。 冻结在去年以GitHub上的几个新功能以及活跃的讨论和开发而结束-但不是那么庄重。 如果您错过了这些发行版,则可以阅读Sass博客


当前,Dart Sass是一种规范的实现,通常是第一个引入新功能的实现。 如果您想接收所有最新消息,我建议您切换到它。 您可以使用NPM,Chocolatey或Homebrew 安装Dart Sass 。 它也适用于gulp-sass

像CSS(从CSS3开始)一样,新版本不再有单个版本号。 所有Sass实现都使用相同的规范,但是每个实现都有唯一的发布时间表和编号,这在Jina设计的精美新文档中的支持信息中得到体现。

图片

Sass模块将于2019年10月1日Dart Sass 1.23.0中可用

Source: https://habr.com/ru/post/zh-CN471924/


All Articles