Sass Module 介紹

作者簡介:
李中凱老師,8年前端開發(fā),前端負(fù)責(zé)人,擅長JavaScript/Vue。
公眾號(hào):1024譯站
掘金文章專欄:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/posts
主要分享:Vue.js, JavaScript,CSS

Sass剛剛發(fā)布了一個(gè)你可能從其他語言中認(rèn)識(shí)的主要新功能:模塊系統(tǒng)。這是最常用的Sass功能之一@import向前邁出的一大步。雖然當(dāng)前的@import規(guī)則允許引入第三方包,并將Sass分成可管理的多個(gè)“partials”,但它有一些限制:

@import 也是一個(gè)CSS特性,兩者之間的區(qū)別可能會(huì)讓人感到困惑

如果多次@import相同的文件,它會(huì)降低編譯速度,導(dǎo)致覆蓋沖突,并生成重復(fù)的輸出。

所有東西都在全局命名空間中,包括第三方包——所以我的color()函數(shù)可能會(huì)覆蓋你現(xiàn)有的color()函數(shù),反之亦然。

當(dāng)你使用像color()這樣的函數(shù)時(shí),很難確切地知道它是在哪定義的。它來自哪個(gè)@import?

Sass包的作者(像我一樣)試圖通過手動(dòng)為變量和函數(shù)添加前綴來解決命名空間問題,但是Sass模塊是一個(gè)更強(qiáng)大的解決方案。簡而言之,@import被更明確的@use和@forward規(guī)則所取代。在接下來的幾年里,Sass@import將被棄用,然后被刪除。你仍然可以使用CSS import,但是它們不會(huì)被Sass編譯。別擔(dān)心,有一個(gè)遷移工具可以幫助你升級(jí)!

使用@use導(dǎo)入文件
@use 'buttons';
新的@use 類似于@import。但有一些明顯的區(qū)別:

該文件只導(dǎo)入一次,不管在項(xiàng)目中@use它多少次。

以下劃線(_)或連字符(-)開頭的變量、mixin 和函數(shù)(Sass稱為"成員變量")被認(rèn)為是私有的,不會(huì)被導(dǎo)入。

導(dǎo)入的文件(這里即buttons.scss)中的成員變量只在局部可用,而不會(huì)傳遞到未來的導(dǎo)入結(jié)果中。

類似地,@extends將只應(yīng)用于上游鏈——即只擴(kuò)展被導(dǎo)入的文件中的選擇器,而不是執(zhí)行導(dǎo)入命令的文件。

所有導(dǎo)入的成員變量默認(rèn)擁有命名空間

當(dāng)我們@use 一個(gè)文件時(shí),Sass會(huì)根據(jù)文件名自動(dòng)生成一個(gè)命名空間:

@use 'buttons'; // 生成了一個(gè)buttons 命名空間
@use 'forms'; // 生成了一個(gè) forms 命名空間
我們現(xiàn)在可以同時(shí)訪問buttons.scss 和forms.scss中的成員變量。但是這兩個(gè)文件之間并不能互相訪問變量。由于導(dǎo)入的特性是帶命名空間的,所以我們必須使用一個(gè)新的點(diǎn)號(hào)分割語法來訪問它們:

// variables: <namespace>.variablebtn-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();
我們可以在導(dǎo)入時(shí)添加as <name>來改變或刪除默認(rèn)的命名空間:

@use 'buttons' as *; // 星號(hào)會(huì)刪除所有命名空間
@use 'forms' as 'f';

btn-color:color; // 不帶命名空間的buttons.colorform-border: f.input-border; // 帶有自定義命名空間的forms.input-border
使用as *將模塊添加到根名稱空間,因此不需要前綴,但這些成員仍然在當(dāng)前文檔的本地作用域內(nèi)。

導(dǎo)入內(nèi)置的Sass模塊
內(nèi)部的Sass特性也已經(jīng)轉(zhuǎn)移到模塊系統(tǒng)中,因此我們可以完全控制全局命名空間。有幾個(gè)內(nèi)置的模塊:math, color, string, list, map, selector和meta ,這些模塊必須在使用之前顯式地導(dǎo)入到文件中:

@use 'sass:math';
$half: math.percentage(1/2);
Sass模塊也可以導(dǎo)入到全局命名空間中:

@use 'sass:math' as *;
$half: percentage(1/2);
已經(jīng)有前綴名稱的內(nèi)部函數(shù),如map-get或str-index可以不加前綴直接使用:

@use 'sass:map';
@use 'sass:string';
map-get: map.get(('key': 'value'), 'key');str-index: string.index('string', 'i');
你可以在Sass模塊規(guī)范中找到內(nèi)置模塊、函數(shù)和名稱更改的完整列表

新的和改變的核心功能
作為一個(gè)附帶好處,這意味著Sass可以安全地添加新的內(nèi)部mixin和函數(shù),而不會(huì)引起命名沖突。這個(gè)版本中最激動(dòng)人心的例子是一個(gè)名為load-css()的sass:meta mixin。跟@use 類似 ,但它只返回轉(zhuǎn)換后的CSS輸出,我們可以在代碼中的任何地方動(dòng)態(tài)使用:

@use 'sass:meta';
$theme-name: 'dark';

[data-theme='#{theme-name}'] { @include meta.load-css(theme-name);
}
第一個(gè)參數(shù)是一個(gè)模塊URL(類似@use),但是它可以被變量動(dòng)態(tài)更改,甚至包括插值表達(dá)式,如theme-#{$name}。第二個(gè)(可選)參數(shù)接受配置值項(xiàng)鍵值對(duì):

// 在加載之前設(shè)置'theme/dark' 中的 base-color 變量 @include meta.load-css( 'theme/dark',with: ('base-color': rebeccapurple)
);
參數(shù) $with接受被加載模塊中的任何變量的鍵和值:

不以_或-開頭的全局變量(現(xiàn)在用于表示私有)

標(biāo)記為 !default 的可配置值

// theme/_dark.scss
base-color: black !default; // 可被配置_private: true !default; // 不可被配置,因?yàn)槭撬接械?br> config: false; // 不可被配置,因?yàn)闆]有被標(biāo)記為 !default 請(qǐng)注意,'base-color' 鍵將設(shè)置base-color 變量。

還有兩個(gè)新的sass:meta函數(shù)module-variables()和module-functions()。每個(gè)函數(shù)返回被導(dǎo)入模塊中的成員名和值的鍵值對(duì)。它們接受一個(gè)與模塊命名空間匹配的參數(shù):

@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'), // ) 其他幾個(gè)sass:meta函數(shù)global-variable-exists(), function-exists(), mixin-exists() 和 get-function() 有額外的module參數(shù),允許我們顯式地檢查每個(gè)命名空間。

調(diào)整和縮放顏色
sass:color 模塊也有一些有趣的注意事項(xiàng),因?yàn)槲覀冊(cè)噲D擺脫一些遺留問題。許多遺留的快捷方式如lighten()或者adjust-hue()現(xiàn)在被棄用,改為顯式的 color.adjust() 和color.scale()函數(shù):

// 原來的 lighten(red, 20%)
light-red: color.adjust(red,lightness: 20%);

// 原來的 adjust-hue(red, 180deg)
complement: color.adjust(red,hue: 180deg);
其中一些舊的函數(shù)(如 adjust-hue)變得多余和不必要了。其他的比如lighten, darken,saturate等等,需要用更好的內(nèi)部邏輯重新構(gòu)建。原來的函數(shù)是基于adjust()的,它利用了線性數(shù)學(xué):在上面的例子中,給當(dāng)前red 變淺20%。在大多數(shù)情況下,我們實(shí)際上想要相對(duì)于當(dāng)前值縮放(scale())顏色深淺的百分比:

// 跟white相差20%,而不是在當(dāng)前深淺度上增加20%
light-red: color.scale(red,lightness: 20%);
一旦完全棄用并刪除,這些快捷函數(shù)最終將以color.scale()而不是color.adjust()為基礎(chǔ)重新出現(xiàn)在sass:color 中。這是分階段進(jìn)行的,以避免出現(xiàn)突然的向后不兼容的變化。與此同時(shí),我建議你手動(dòng)檢查你的代碼,看看color.scale() 在什么地方更適合你。

配置導(dǎo)入的庫
第三方或可重用的庫通常帶有默認(rèn)的全局配置變量可供覆蓋。我們通常在導(dǎo)入之前對(duì)變量進(jìn)行這樣的操作:

// _buttons.scss
$color: blue !default;

// old.scss
$color: red;
@import 'buttons';
由于使用過的模塊不能夠再訪問本地變量,我們需要一種新的方法來設(shè)置這些默認(rèn)值。我們可以通過給@use添加配置鍵值對(duì)來實(shí)現(xiàn):

@use 'buttons' with (
color: red,style: 'flat',
);
這類似于load-css()中的with 參數(shù)。但是我們不使用變量名作為鍵,而是使用變量本身,以開頭。

我喜歡這種顯式的配置方式,但是有一條規(guī)則讓我犯了好幾次錯(cuò)誤:一個(gè)模塊只能配置一次,即第一次使用它時(shí)。導(dǎo)入順序?qū)ass來說一直很重要,即便@import也是如此。但這些問題總是靜默地失敗?,F(xiàn)在我們得到一個(gè)明確的錯(cuò)誤,這是好事,有時(shí)也令人驚訝。
確保使用@use時(shí)在“入口”文件(導(dǎo)入所有部分的中心文檔)中首先配置庫,以便在其他地方@use庫之前編譯這些配置。

(目前來說)不可能在保持可編輯的同時(shí)將配置“鏈接”在一起,但是你可以將已配置的模塊與擴(kuò)展打包,并將其作為新模塊傳遞。

用@forward傳遞文件
我們并不總是需要使用一個(gè)文件,并訪問它的成員。有時(shí)我們只是想把它傳給未來的導(dǎo)入操作。假設(shè)我們有多個(gè)與表單相關(guān)的partials,我們希望將它們?nèi)繉?dǎo)入為一個(gè)命名空間。我們可以用 @forward來實(shí)現(xiàn):

// forms/_index.scss
@forward 'input';
@forward 'textarea';
@forward 'select';
@forward 'buttons';
被轉(zhuǎn)發(fā)的文件的成員在當(dāng)前文檔中不可訪問,也沒有創(chuàng)建命名空間,但是當(dāng)另一個(gè)文件想要@use 或@forward 整個(gè)集合時(shí),這些變量、函數(shù)和mixin 就是可訪問的。如果轉(zhuǎn)發(fā)的部分包含實(shí)際的CSS,那么在使用包之前,它也不會(huì)生成輸出。在這一點(diǎn)上,它將被視為單個(gè)模塊與單個(gè)命名空間:

// styles.scss
@use 'forms'; // 導(dǎo)入forms 命名空間下的所有被轉(zhuǎn)發(fā)的成員
注:如果你要求Sass導(dǎo)入一個(gè)目錄,它會(huì)尋找一個(gè)名為index或_index的文件)

默認(rèn)情況下,所有公共成員將使用一個(gè)模塊進(jìn)行轉(zhuǎn)發(fā)。但我們可以更有選擇性地添加show 或hide語句,來包含或排除指定的成員:

// 只轉(zhuǎn)發(fā)'input' 中的 border() mixin 和 border-color 變量 @forward 'input' show border,border-color;

// 轉(zhuǎn)發(fā)'buttons' 里的所有成員, gradient() 函數(shù)除外
@forward 'buttons' hide gradient;
注意:當(dāng)函數(shù)和mixin共享一個(gè)名稱時(shí),它們會(huì)一起顯示和隱藏。

為了區(qū)分來源,或避免轉(zhuǎn)發(fā)模塊之間的命名沖突,我們可以在轉(zhuǎn)發(fā)時(shí)對(duì)模塊成員使用as 前綴:

// forms/_index.scss
// @forward "<url>" as <prefix>-;
// 假設(shè)兩個(gè)模塊都有一個(gè)background() mixin
@forward 'input' as input-
;
@forward 'buttons' as btn-*;

// style.scss
@use 'forms';
@include forms.input-background();
@include forms.btn-background();
而且,如果需要,我們可以對(duì)同一模塊同時(shí)使用 @use和@forward :

@forward 'forms';
@use 'forms';
如果你希望在將庫傳遞給其他文件之前,用配置或任何其他工具包裝庫,那么這一點(diǎn)特別有用。它甚至可以幫助簡化導(dǎo)入路徑:

// _tools.scss
// 只使用該庫一次,并帶有配置參數(shù)
@use 'accoutrement/sass/tools' with (
$font-path: '../fonts/',
);
// 隨即轉(zhuǎn)發(fā)配置后的庫
@forward 'accoutrement/sass/tools';

// 在這里添加其他擴(kuò)展…

// _anywhere-else.scss
// import the wrapped-and-extended library, already configured
@use 'tools';
@use和@forward必須在(非嵌套的)文檔的根部和文件的開頭聲明。只有@charset和簡單的變量定義可以出現(xiàn)在導(dǎo)入指令之前。

維護(hù)和編寫樣式
在網(wǎng)站上使用模塊非常有趣。新的語法鼓勵(lì)我已經(jīng)在使用的代碼結(jié)構(gòu)。我所有的全局配置和工具導(dǎo)入都在一個(gè)目錄中(我稱之為 config),其中有一個(gè)索引文件,可以轉(zhuǎn)發(fā)我需要的所有內(nèi)容:

// config/_index.scss
@forward 'tools';
@forward 'fonts';
@forward 'scale';
@forward 'colors';
在我構(gòu)建網(wǎng)站的其他部分時(shí),我可以在任何需要的地方導(dǎo)入這些工具和配置:

// layout/_banner.scss
@use '../config';

.page-title {
@include config.font-family('header');
}
這甚至適用于我現(xiàn)有的Sass庫,比如accout和Herman,它們?nèi)匀皇褂门f的@import語法。由于@import規(guī)則不會(huì)在一夜之間被全部替換,所以Sass提供了一個(gè)過渡期?,F(xiàn)在就可以使用模塊功能,但是@import在一兩年后才會(huì)被棄用,并且在一年后才會(huì)從語言中刪除。在此期間,這兩個(gè)系統(tǒng)將朝兩個(gè)方向共同努力:

如果我們 @import一個(gè)包含新的 @use/@forward 語法的文件,那么只導(dǎo)入公共成員,沒有命名空間。

如果我們@use 或@forward一個(gè)包含遺留 @import語法的文件,我們將以單個(gè)命名空間訪問所有嵌套的導(dǎo)入。

這意味著您可以立即開始使用新的模塊語法,而不必等待你喜歡的庫的新版本:而且我可以花一些時(shí)間來更新我的所有庫!

遷移工具
如果我們使用Jennifer Thakar構(gòu)建的Migration Tool,升級(jí)應(yīng)該不會(huì)花很長時(shí)間。它可以通過 Node, Chocolatey, 或 Homebrew 安裝:

npm install -g sass-migrator
choco install sass-migrator
brew install sass/sass/migrator
這不是遷移到模塊系統(tǒng)的一次性工具。既然Sass已經(jīng)回到了活躍的開發(fā)階段(參見下面),那么遷移工具也將得到定期更新,以幫助遷移每個(gè)新特性。全局安裝它是個(gè)好主意,并保留它以備將來使用。

遷移工具可以從命令行運(yùn)行,并有望跟CodeKit和Scout一樣添加到第三方應(yīng)用程序集。將它指向一個(gè)Sass文件,比如style.scss,并告訴它應(yīng)該遷移什么內(nèi)容。在這里,只有一個(gè)名為module的遷移:

sass-migrator <migration> <entrypoint.scss...>

sass-migrator module style.scss
默認(rèn)情況下,遷移工具將只更新單個(gè)文件,但在大多數(shù)情況下,我們希望更新主文件及其所有依賴項(xiàng):import、forward或use的任何 partials 。我們可以通過單獨(dú)指定每個(gè)文件,或者添加 --migrate-deps標(biāo)記來做到這一點(diǎn):

sass-migrator --migrate-deps module style.scss
對(duì)于測(cè)試程序,我們可以添加--dry-run --verbose(或簡寫為 -nv),并在不更改任何文件的情況下查看結(jié)果。我們可以使用許多其他選項(xiàng)來定制遷移——甚至有一個(gè)專門用于幫助庫作者刪除舊的手動(dòng)命名空間——但是我不會(huì)在這里全部介紹。在Sass網(wǎng)站上可以找到遷移工具的完整文檔。

更新已發(fā)布的庫
我在庫方面遇到了一些問題,特別是試圖讓用戶跨文件訪問用戶配置,以及處理缺少的鏈?zhǔn)脚渲?。順序錯(cuò)誤可能很難調(diào)試,但是結(jié)果表明花這些工夫是值得的,我認(rèn)為我們很快就會(huì)看到一些額外的補(bǔ)丁。我仍然需要在復(fù)雜的包上試驗(yàn)遷移工具,并可能為庫作者撰寫后續(xù)文章。

現(xiàn)在要知道的重要的事情是,在過渡期,Sass已經(jīng)替我們解決了大部分問題。不僅import 和 module 可以一起使用,而且我們可以創(chuàng)建“只有import”的文件,為仍然用 @import方式使用庫的老用戶提供更好的體驗(yàn)。在大多數(shù)情況下,這將是主包文件的另一個(gè)版本,你可能希望同時(shí)使用它們:為模塊用戶提供<name>.scss,為遺留用戶提供<name>.import.scss。當(dāng)用戶調(diào)用@import <name>時(shí),它將加載文件的.import版本。

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

// load _forms.input.scss
@import 'forms';
這對(duì)于為非模塊用戶添加前綴特別有用:

// _forms.import.scss
// Forward the main module, while adding a prefix
@forward "forms" as forms-*;
升級(jí)Sass
你可能還記得,幾年前Sass有一個(gè)特性凍結(jié),以使各種實(shí)現(xiàn)(LibSass、Node Sass、Dart Sass)都跟上開發(fā)節(jié)奏,并最終廢棄了原來的Ruby實(shí)現(xiàn)。這一凍結(jié)在去年結(jié)束了,在GitHub上推出了一些新功能和活躍的討論與開發(fā),但并沒有大張旗鼓。如果你錯(cuò)過了這些發(fā)布,你可以在Sass博客上找到:

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

內(nèi)容參數(shù)與顏色函數(shù) (Dart Sass v1.15)

Dart Sass現(xiàn)在是標(biāo)準(zhǔn)實(shí)現(xiàn),并且通常是第一個(gè)實(shí)現(xiàn)新特性的。如果你想要最新的,我建議你切換過去。可以使用Node、Chocolatey或Homebrew安裝Dart Sass。它還可以與現(xiàn)有的gulp-sass構(gòu)建步驟一起工作。

跟CSS(從CSS3開始)很像,新的發(fā)布不再有一個(gè)統(tǒng)一的版本號(hào)。所有的Sass實(shí)現(xiàn)都遵循相同的規(guī)范,但是每個(gè)都有一個(gè)獨(dú)特的發(fā)布時(shí)間表和版本號(hào),這反映在Jina設(shè)計(jì)的新文檔中。

本文已經(jīng)獲得李中凱老師授權(quán)轉(zhuǎn)發(fā),其他人若有興趣轉(zhuǎn)載,請(qǐng)直接聯(lián)系作者授權(quán)。

作者簡介:
李中凱老師,8年前端開發(fā),前端負(fù)責(zé)人,擅長JavaScript/Vue。
公眾號(hào):1024譯站
掘金文章專欄:https://juejin.im/user/57c7cb8a0a2b58006b1b8666/posts
主要分享:Vue.js, JavaScript,CSS

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 當(dāng)聽到王寶強(qiáng),你在想什么?想到了《天下無賊》的傻根?想到了《士兵突擊》里的許三多?想到了《泰囧》里的寶寶?抑或想到...
    樂言樂語樂生活閱讀 246評(píng)論 0 0
  • 1 .銃星系聯(lián)盟 七個(gè)種族 2 .低級(jí)世界以球命名(土球)星系是高級(jí)世界,土球上的人類想尋找自己所在的世界中和他們...
    每天都要寫點(diǎn)東西的CZ君閱讀 259評(píng)論 0 0
  • 一、為什么要學(xué)習(xí)設(shè)計(jì)模式 設(shè)計(jì)模式一定要區(qū)分廣義的定義和狹義的定義,廣義上講,設(shè)計(jì)模式包含所有軟件工程中的設(shè)計(jì)模式...
    gofun成都技術(shù)中心閱讀 2,047評(píng)論 0 0
  • 文/流上云間 黎明來了 黎明來了啊 看似又是一輪希望 實(shí)則只是又一輪蒼白的輪回 她哆嗦在角落里 用雙手捂住臉 無聲...
    荊棘紫閱讀 128評(píng)論 0 1

友情鏈接更多精彩內(nèi)容