作者简介:
李中凯老师,8年前端开发,前端负责人,擅长JavaScript/Vue。
公众号:1024译站
掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/posts
主要分享:Vue.js, JavaScript,CSS


Sass刚刚发布了一个你可能从其他语言中认识的主要新功能:模块系统。这是最常用的Sass功能之一@import向前迈出的一大步。虽然当前的@import规则允许引入第三方包,并将Sass分成可管理的多个“partials”,但它有一些限制:

  • @import 也是一个CSS特性,两者之间的区别可能会让人感到困惑

  • 如果多次@import相同的文件,它会降低编译速度,导致覆盖冲突,并生成重复的输出。

  • 所有东西都在全局命名空间中,包括第三方包——所以我的color()函数可能会覆盖你现有的color()函数,反之亦然。

  • 当你使用像color()这样的函数时,很难确切地知道它是在哪定义的。它来自哪个@import?

Sass包的作者(像我一样)试图通过手动为变量和函数添加前缀来解决命名空间问题,但是Sass模块是一个更强大的解决方案。简而言之,@import被更明确的@use@forward规则所取代。在接下来的几年里,Sass@import将被弃用,然后被删除。你仍然可以使用CSS import,但是它们不会被Sass编译。别担心,有一个迁移工具可以帮助你升级!

使用@use导入文件

@use 'buttons';

新的@use 类似于@import。但有一些明显的区别:

  • 该文件只导入一次,不管在项目中@use它多少次。

  • 以下划线(_)或连字符(-)开头的变量、mixin 和函数(Sass称为"成员变量")被认为是私有的,不会被导入。

  • 导入的文件(这里即buttons.scss)中的成员变量只在局部可用,而不会传递到未来的导入结果中。

  • 类似地,@extends将只应用于上游链——即只扩展被导入的文件中的选择器,而不是执行导入命令的文件。

  • 所有导入的成员变量默认拥有命名空间

当我们@use 一个文件时,Sass会根据文件名自动生成一个命名空间:

@use 'buttons'; // 生成了一个`buttons` 命名空间
@use 'forms'; // 生成了一个 `forms` 命名空间

我们现在可以同时访问buttons.scss 和forms.scss中的成员变量。但是这两个文件之间并不能互相访问变量。由于导入的特性是带命名空间的,所以我们必须使用一个新的点号分割语法来访问它们:

// variables: <namespace>.$variable
$btn-color: buttons.$color;
$form-border: forms.$input-border;// functions: <namespace>.function()
$btn-background: buttons.background();
$form-border: forms.border();// mixins: @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);

Sass模块也可以导入到全局命名空间中:

@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和函数,而不会引起命名冲突。这个版本中最激动人心的例子是一个名为load-css()sass:meta mixin。跟@use 类似 ,但它只返回转换后的CSS输出,我们可以在代码中的任何地方动态使用:

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

第一个参数是一个模块URL(类似@use),但是它可以被变量动态更改,甚至包括插值表达式,如theme-#{$name}。第二个(可选)参数接受配置值项键值对:

// 在加载之前设置'theme/dark' 中的 $base-color 变量
@include meta.load-css('theme/dark',$with: ('base-color': rebeccapurple)
);

参数 $with接受被加载模块中的任何变量的键和值:

  • 不以_-开头的全局变量(现在用于表示私有)

  • 标记为 !default 的可配置值

// theme/_dark.scss
$base-color: black !default; // 可被配置
$_private: true !default; // 不可被配置,因为是私有的
$config: false; // 不可被配置,因为没有被标记为 !default

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

还有两个新的sass:meta函数module-variables()module-functions()。每个函数返回被导入模块中的成员名和值的键值对。它们接受一个与模块命名空间匹配的参数:

@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函数global-variable-exists()function-exists()mixin-exists() 和 get-function() 有额外的$module参数,允许我们显式地检查每个命名空间。

调整和缩放颜色

sass:color 模块也有一些有趣的注意事项,因为我们试图摆脱一些遗留问题。许多遗留的快捷方式如lighten()或者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)变得多余和不必要了。其他的比如lighten, darkensaturate等等,需要用更好的内部逻辑重新构建。原来的函数是基于adjust()的,它利用了线性数学:在上面的例子中,给当前red 变浅20%。在大多数情况下,我们实际上想要相对于当前值缩放(scale())颜色深浅的百分比:

// 跟white相差20%,而不是在当前深浅度上增加20%
$light-red: color.scale(red, $lightness: 20%);

一旦完全弃用并删除,这些快捷函数最终将以color.scale()而不是color.adjust()为基础重新出现在sass:color 中。这是分阶段进行的,以避免出现突然的向后不兼容的变化。与此同时,我建议你手动检查你的代码,看看color.scale() 在什么地方更适合你。

配置导入的库

第三方或可重用的库通常带有默认的全局配置变量可供覆盖。我们通常在导入之前对变量进行这样的操作:

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

由于使用过的模块不能够再访问本地变量,我们需要一种新的方法来设置这些默认值。我们可以通过给@use添加配置键值对来实现:

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

这类似于load-css()中的$with 参数。但是我们不使用变量名作为键,而是使用变量本身,以$开头。

我喜欢这种显式的配置方式,但是有一条规则让我犯了好几次错误:一个模块只能配置一次,即第一次使用它时。导入顺序对Sass来说一直很重要,即便@import也是如此。但这些问题总是静默地失败。现在我们得到一个明确的错误,这是好事,有时也令人惊讶。
确保使用@use时在“入口”文件(导入所有部分的中心文档)中首先配置库,以便在其他地方@use库之前编译这些配置。

(目前来说)不可能在保持可编辑的同时将配置“链接”在一起,但是你可以将已配置的模块与扩展打包,并将其作为新模块传递。

用@forward传递文件

我们并不总是需要使用一个文件,并访问它的成员。有时我们只是想把它传给未来的导入操作。假设我们有多个与表单相关的partials,我们希望将它们全部导入为一个命名空间。我们可以用 @forward来实现:

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

被转发的文件的成员在当前文档中不可访问,也没有创建命名空间,但是当另一个文件想要@use 或@forward 整个集合时,这些变量、函数和mixin 就是可访问的。如果转发的部分包含实际的CSS,那么在使用包之前,它也不会生成输出。在这一点上,它将被视为单个模块与单个命名空间:

// styles.scss
@use 'forms'; // 导入`forms` 命名空间下的所有被转发的成员

注:如果你要求Sass导入一个目录,它会寻找一个名为index_index的文件)

默认情况下,所有公共成员将使用一个模块进行转发。但我们可以更有选择性地添加show 或hide语句,来包含或排除指定的成员:

// 只转发'input' 中的 border() mixin 和 $border-color 变量
@forward 'input' show border, $border-color;// 转发'buttons' 里的所有成员, gradient() 函数除外
@forward 'buttons' hide gradient;

注意:当函数和mixin共享一个名称时,它们会一起显示和隐藏。

为了区分来源,或避免转发模块之间的命名冲突,我们可以在转发时对模块成员使用as 前缀:

// forms/_index.scss
// @forward "<url>" as <prefix>-*;
// 假设两个模块都有一个background() mixin
@forward 'input' as input-*;
@forward 'buttons' as btn-*;// style.scss
@use 'forms';
@include forms.input-background();
@include forms.btn-background();

而且,如果需要,我们可以对同一模块同时使用 @use@forward :

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

如果你希望在将库传递给其他文件之前,用配置或任何其他工具包装库,那么这一点特别有用。它甚至可以帮助简化导入路径:

// _tools.scss
// 只使用该库一次,并带有配置参数
@use 'accoutrement/sass/tools' with ($font-path: '../fonts/',
);
// 随即转发配置后的库
@forward 'accoutrement/sass/tools';// 在这里添加其他扩展…// _anywhere-else.scss
// import the wrapped-and-extended library, already configured
@use 'tools';

@use@forward必须在(非嵌套的)文档的根部和文件的开头声明。只有@charset和简单的变量定义可以出现在导入指令之前。

维护和编写样式

在网站上使用模块非常有趣。新的语法鼓励我已经在使用的代码结构。我所有的全局配置和工具导入都在一个目录中(我称之为 config),其中有一个索引文件,可以转发我需要的所有内容:

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

在我构建网站的其他部分时,我可以在任何需要的地方导入这些工具和配置:

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

这甚至适用于我现有的Sass库,比如accout和Herman,它们仍然使用旧的@import语法。由于@import规则不会在一夜之间被全部替换,所以Sass提供了一个过渡期。现在就可以使用模块功能,但是@import在一两年后才会被弃用,并且在一年后才会从语言中删除。在此期间,这两个系统将朝两个方向共同努力:

  • 如果我们 @import一个包含新的 @use/@forward 语法的文件,那么只导入公共成员,没有命名空间。

  • 如果我们@use 或@forward一个包含遗留 @import语法的文件,我们将以单个命名空间访问所有嵌套的导入。

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

迁移工具

如果我们使用Jennifer Thakar构建的Migration Tool,升级应该不会花很长时间。它可以通过 Node, 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

默认情况下,迁移工具将只更新单个文件,但在大多数情况下,我们希望更新主文件及其所有依赖项importforwarduse的任何 partials 。我们可以通过单独指定每个文件,或者添加 --migrate-deps标记来做到这一点:

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

对于测试程序,我们可以添加--dry-run --verbose(或简写为 -nv),并在不更改任何文件的情况下查看结果。我们可以使用许多其他选项来定制迁移——甚至有一个专门用于帮助库作者删除旧的手动命名空间——但是我不会在这里全部介绍。在Sass网站上可以找到迁移工具的完整文档。

更新已发布的库

我在库方面遇到了一些问题,特别是试图让用户跨文件访问用户配置,以及处理缺少的链式配置。顺序错误可能很难调试,但是结果表明花这些工夫是值得的,我认为我们很快就会看到一些额外的补丁。我仍然需要在复杂的包上试验迁移工具,并可能为库作者撰写后续文章。

现在要知道的重要的事情是,在过渡期,Sass已经替我们解决了大部分问题。不仅import 和 module 可以一起使用,而且我们可以创建“只有import”的文件,为仍然用 @import方式使用库的老用户提供更好的体验。在大多数情况下,这将是主包文件的另一个版本,你可能希望同时使用它们:为模块用户提供<name>.scss,为遗留用户提供<name>.import.scss。当用户调用@import <name>时,它将加载文件的.import版本。

// load _forms.scss
@use 'forms';// load _forms.input.scss
@import 'forms';

这对于为非模块用户添加前缀特别有用:

// _forms.import.scss
// Forward the main module, while adding a prefix
@forward "forms" as forms-*;

升级Sass

你可能还记得,几年前Sass有一个特性冻结,以使各种实现(LibSass、Node Sass、Dart Sass)都跟上开发节奏,并最终废弃了原来的Ruby实现。这一冻结在去年结束了,在GitHub上推出了一些新功能和活跃的讨论与开发,但并没有大张旗鼓。如果你错过了这些发布,你可以在Sass博客上找到:

  • CSS Imports 与 CSS 兼容性 (Dart Sass v1.11)

  • 内容参数与颜色函数 (Dart Sass v1.15)

Dart Sass现在是标准实现,并且通常是第一个实现新特性的。如果你想要最新的,我建议你切换过去。可以使用Node、Chocolatey或Homebrew安装Dart Sass。它还可以与现有的gulp-sass构建步骤一起工作。

跟CSS(从CSS3开始)很像,新的发布不再有一个统一的版本号。所有的Sass实现都遵循相同的规范,但是每个都有一个独特的发布时间表和版本号,这反映在Jina设计的新文档中。

本文已经获得李中凯老师授权转发,其他人若有兴趣转载,请直接联系作者授权。

作者简介:
李中凯老师,8年前端开发,前端负责人,擅长JavaScript/Vue。
公众号:1024译站
掘金文章专栏:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/posts
主要分享:Vue.js, JavaScript,CSS

Sass Module 介绍相关推荐

  1. Http Module 介绍[转]

    Http Module 介绍[转] Http Module 介绍 引言 Http 请求处理流程 和 Http Handler 介绍 这两篇文章里,我们首先了解了Http请求在服务器端的处理流程,随后我 ...

  2. Http Module 介绍(转)

    引言 Http 请求处理流程 和 Http Handler 介绍 这两篇文章里,我们首先了解了Http请求在服务器端的处理流程,随后我们知道Http请求最终会由实现了IHttpHandler接口的类进 ...

  3. Http Module 介绍

    Http 请求处理流程 和 Http Handler 介绍 这两篇文章里,我们首先了解了Http请求在服务器端的处理流程,随后我们知道Http请求最终会由实现了IHttpHandler接口的类进行处理 ...

  4. (转载)Http Module 介绍

    引言 Http 请求处理流程 和 Http Handler 介绍 这两篇文章里,我们首先了解了Http请求在服务器端的处理流程,随后我们知道Http请求最终会由实现了IHttpHandler接口的类进 ...

  5. python模块编程教程_python进阶教程之模块(module)介绍

    我们之前看到了函数和对象.从本质上来说,它们都是为了更好的组织已经有的程序,以方便重复利用. 模块(module)也是为了同样的目的.在Python中,一个.py文件就构成一个模块.通过模块,你可以调 ...

  6. 43_pytorch nn.Module,模型的创建,构建子模块,API介绍,Sequential(序号),ModuleList,ParameterList,案例等(学习笔记)

    1.40.PyTorch nn.Module 1.40.1.模型的创建 1.40.2.构建子模块 1.40.3.nn.Module API介绍 1.40.3.1.核心功能 1.40.3.2.查看模块 ...

  7. CSS day_13(6.28) Boot常用组件(nav、tab、分页)Sass介绍

    一.组件 nav导航 .nav整个导航的外层,flex属性和去掉标识符的属性 .nav-item细微的间距调整 .nav-link每一个项之间大部分样式内容的调整 .active当前被激活的导航签 & ...

  8. IntelliJ IDEA 项目相关的几个重要概念介绍

    IntelliJ IDEA 项目相关的几个重要概念介绍 发布于 2015-09-23 23:02:48 | 11 次阅读 | 评论: 0 | 来源: 网络整理 本篇内容为大家提供的是IntelliJ ...

  9. alibaba-COLA框架module分析

    概览 COLA-framework的module如下: cola-common cola-core cola-test 用maven-archetype生成的代码例子的module情况: demo-a ...

  10. sass教程之--sass的安装

    Sass 安装 本章节我们主要介绍 Sass 的安装与使用. NPM 安装 我们可以使用 npm(NPM 使用介绍)来安装 Sass. npm install -g sass 注:国内 npm 建议使 ...

最新文章

  1. ipvsadm使用简介
  2. php websocket
  3. 记一次CPU持续100%及分析方法
  4. 银行营业网点管理系统——implt包(CityAreaDaoImpl )
  5. NetBSD Make源代码阅读二:链表之创建与销毁
  6. 数值溢出(arithmetic overflow)问题与解决方案
  7. zoj 1718 poj 2031 Building a Space Station
  8. php in_array性能优化
  9. Atitit 返回http500返回码,以及自定义返回提示 目录 1. 可以看到从php发送http响应代码的三种方法: 1 1.1. Header(HTTP/1.1 404 Not Found
  10. ASP.NET读取Word文档转换为PDF文件的方法
  11. python对接60码平台
  12. 64位Linux下安装iNode客户端
  13. 联想G480安装CentOS有线驱动
  14. 如何更改XP系统默认字体 讨论话题……
  15. 苹果最新框架教程之 ProximityReader是什么
  16. 简述docx文档格式-CTF竞赛专用
  17. VMware9虚拟机和Fedora12安装-实现Windows和Linux文件共享
  18. Python3 创建文件夹
  19. c语言lcm函数的头文件,LCM中C++的API介绍
  20. 互联网晚报 | 10月20日 星期三 | 小米汽车预计2024年量产;阿里发布自研CPU芯片倚天710;《长津湖》票房破50亿元...

热门文章

  1. 跨考计算机无法调剂,考研调剂又出新变化:“不能跨学科门类调剂”!
  2. googleseo只做内容不做外链行不行?(e6zzseo)
  3. tungsten mysql_ETL之Tungsten Replicator
  4. GAPP添加overlay
  5. Python连接redis实现有序队列queue先进先出/后进先出
  6. 复杂网络作业四:第三题——随机图、小世界网络和真实网络的度分布
  7. 无根树的计数——prufer序列
  8. 正规手游代理该怎么选?
  9. 如何提高深度睡眠质量,科学解决睡眠问题
  10. 1125 Chain the Ropes