現(xiàn) M3 設(shè)計(jì)系統(tǒng))
Angular Material 主題定制完全指南基于 Sass 的mat.themeAPI 實(shí)現(xiàn) M3 設(shè)計(jì)系統(tǒng)【免費(fèi)下載鏈接】componentsComponent infrastructure and Material Design components for Angular項(xiàng)目地址: https://gitcode.com/GitHub_Trending/co/componentsAngular Material 的主題系統(tǒng)借鑒了 Google Material DesignM3的設(shè)計(jì)理念允許你通過(guò)定義自定義主題來(lái)全面控制組件外觀。本文基于官方 主題指南系統(tǒng)講解 Angular Material v19 起引入的全新 Sass 主題 API如何編寫主題文件、配置色彩/排版/密度、使用預(yù)構(gòu)建主題與內(nèi)置色板、實(shí)現(xiàn)亮暗模式切換與多主題共存并深入倉(cāng)庫(kù)源碼tokens/_system.scss、theming/_definition.scss 等揭示其底層實(shí)現(xiàn)原理。讀完本文你將能夠從零搭建一套支持 Material 3、可切換亮暗模式、可細(xì)粒度覆蓋 Design Token 的完整應(yīng)用主題方案。快速上手創(chuàng)建你的第一個(gè)主題文件Angular Material 的主題定制從一份 Sass主題文件開(kāi)始該文件必須引入mat.thememixin。這個(gè) mixin 接收一個(gè)包含 color、typography、density 三類配置的 map并輸出一組控制組件外觀與布局的CSS 變量Design Tokens。顏色類變量使用 CSSlight-dark()顏色函數(shù)定義因此主題可以借助color-schemeCSS 屬性在亮色與暗色模式之間自由切換。下面是一份最簡(jiǎn)主題文件應(yīng)用 violet 色板、Roboto 字體和標(biāo)準(zhǔn)密度。它作用于html選擇器確保 CSS 變量覆蓋整個(gè)應(yīng)用color-scheme顯式設(shè)置為light dark讓最終亮暗模式由用戶系統(tǒng)偏好決定use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); }為讓應(yīng)用默認(rèn)使用主題的 surface 背景與 on-surface 文本色可以補(bǔ)充如下全局樣式body { background: var(--mat-sys-surface); color: var(--mat-sys-on-surface); }也可以借助mat.system-classes()生成一組 CSS 工具類直接在組件模板中套用主題樣式html { ... include mat.system-classes(); }body classmat-bg-surface mat-text-on-surface需要特別注意的是mat.thememixin 只為輸入 map 中包含的類別聲明 CSS 變量。例如未提供typography時(shí)輸出的 CSS 中不會(huì)包含排版相關(guān)變量。這一點(diǎn)在源碼中得到印證——tokens/_system.scss 中排版變量的發(fā)射邏輯被包裹在if ($typography)分支內(nèi)色彩、排版、密度三部分各自獨(dú)立判斷。主題配置的默認(rèn)值與數(shù)據(jù)結(jié)構(gòu)從 theming/_definition.scss 中define-theme函數(shù)的實(shí)現(xiàn)可以確認(rèn)各配置項(xiàng)的默認(rèn)值配置項(xiàng)默認(rèn)值說(shuō)明color.theme-typelight顏色取值類型color.primary$violet-palette主色板color.tertiary同 primary三級(jí)色板缺省時(shí)復(fù)用主色板typography.plain-family(Roboto, sans-serif)正文plain字體typography.brand-family同 plain品牌brand字體typography.bold-weight700粗體字重typography.medium-weight500中等字重typography.regular-weight400常規(guī)字重density.scale0密度等級(jí)主題對(duì)象內(nèi)部由_mat-system系統(tǒng)級(jí)變量與_mat-theming-internals-do-not-access內(nèi)部結(jié)構(gòu)兩部分組成其中系統(tǒng)變量通過(guò)m3-tokens模塊按 M3 規(guī)范生成涵蓋了顏色、排版、形狀、狀態(tài)、高度elevation等全套 Design Token。配置色彩Color主題的色彩決定了組件的顏色樣式例如復(fù)選框的填充色、按鈕的漣漪顏色等。色彩依賴一組色調(diào)漸變的色板Color Palette來(lái)構(gòu)建完整的配色方案。設(shè)置顏色有兩種方式單一色板或顏色 map。方式一單一色板直接傳入一個(gè)色板Angular Material 會(huì)將其用作主題的 primary、secondary 和 tertiary 顏色。此時(shí)顏色值使用light-dark()CSS 函數(shù)定義因此應(yīng)用樣式必須顯式聲明color-scheme屬性否則無(wú)法觸發(fā)亮暗切換use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); }方式二顏色 map傳入顏色 map 可以將 tertiary 色板與 primary 色板分開(kāi)配置。tertiary 色板常用來(lái)為部分組件提供獨(dú)特的強(qiáng)調(diào)色。同時(shí)可以通過(guò)theme-type控制顏色值的定義方式color-scheme使用light-dark()CSS 函數(shù)同時(shí)包含亮、暗兩套顏色值默認(rèn)行為light僅定義亮色顏色值dark僅定義暗色顏色值。light-dark()已得到所有主流瀏覽器的廣泛支持但若應(yīng)用需要兼容較舊瀏覽器或非主流瀏覽器建議顯式將theme-type設(shè)為light或dark。下面示例應(yīng)用 violet 主色與 orange 三級(jí)色theme-type為light即只為應(yīng)用定義亮色顏色值use angular/material as mat; html { include mat.theme(( color: ( primary: mat.$violet-palette, tertiary: mat.$orange-palette, theme-type: light, ), typography: Roboto, density: 0 )); }底層實(shí)現(xiàn)theme-type 如何決定輸出在 tokens/_system.scss 的_generate-sys-colors函數(shù)中可以看到三種theme-type的完整分支light直接返回 M3 亮色系統(tǒng)色dark返回暗色系統(tǒng)色color-scheme則對(duì)每一對(duì)亮/暗顏色值調(diào)用light-dark($light-value, $dark-value)生成可切換變量。此外如果傳入的是單一色板而非 maptheme mixin 會(huì)自動(dòng)把tertiary指向同一色板并將theme-type默認(rèn)置為color-scheme——這與文檔描述的行為完全一致。配置排版Typography排版決定組件內(nèi)的文本樣式例如對(duì)話框標(biāo)題或菜單列表項(xiàng)的字體。同樣有兩種配置方式。方式一單一字體族直接傳入字體族字符串Angular Material 會(huì)將其應(yīng)用于組件所有文本。組件中使用的字重固定為粗體 700、中等 500、常規(guī) 400。方式二排版 map傳入排版 map 可為plain正文與brand品牌文本設(shè)置不同字體族plain 字體用于應(yīng)用大部分正文brand 字體通常用于標(biāo)題與題名。map 中還可分別指定 bold、medium、regular 字重。下面示例正文使用 Roboto、品牌文本使用 Open Sans粗體 900、中等 500、常規(guī) 300色彩為 violet 色板、標(biāo)準(zhǔn)密度use angular/material as mat; html { include mat.theme(( color: mat.$violet-palette, typography: ( plain-family: Roboto, brand-family: Open Sans, bold-weight: 900, medium-weight: 500, regular-weight: 300, ), density: 0, )); }從源碼看theme mixin 處理排版時(shí)若值是字符串則 plain 與 brand 共用若值是 map 則分別讀取plain-family、brand-family與三個(gè)字重鍵最終經(jīng)由system-level-typography調(diào)用m3.md-sys-typescale-values生成--mat-sys-*排版變量如--mat-sys-body-large等字體快捷變量。配置密度Density密度值決定組件內(nèi)部間距例如按鈕文字周圍的內(nèi)邊距、表單字段的高度。密度值接受0 到 -5的整數(shù)0 為默認(rèn)間距-5 為最緊湊布局。每下降一個(gè)整數(shù)值-1、-2……受影響尺寸減少 4px直到組件能正常渲染所需的最小尺寸為止。下面示例將密度設(shè)為 -2使大部分組件減少留白、布局更緊湊use angular/material as mat; html { include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: -2, )); }兩點(diǎn)重要提醒密度低于 0 可能降低可訪問(wèn)性給使用輔助技術(shù)的用戶帶來(lái)導(dǎo)航困難密度自定義不影響出現(xiàn)在任務(wù)型或彈出型上下文中的組件如日期選擇器。Material Design 密度規(guī)范明確不建議改變此類交互的密度因?yàn)樗鼈儾⒉慌c應(yīng)用布局爭(zhēng)搶空間。源碼佐證在 tokens/_system.scss 中只有當(dāng)$scale ! 0時(shí)才會(huì)輸出組件級(jí)密度 Token且這些 Token如 checkbox、button、form-field 等各組件的密度變量不會(huì)回退到系統(tǒng)級(jí)值必須由 mixin 直接定義。使用預(yù)構(gòu)建主題Prebuilt Themes如果不想通過(guò) Sass 自定義主題Angular Material 提供了8 個(gè)預(yù)構(gòu)建主題 CSS 文件其中 4 個(gè)基于現(xiàn)代 Material 3 設(shè)計(jì)系統(tǒng)另外 4 個(gè)基于舊的 Material 2 設(shè)計(jì)系統(tǒng)。若希望應(yīng)用遵循 M3 設(shè)計(jì)語(yǔ)言務(wù)必選用 M3 主題M2 主題僅為向后兼容而保留將在未來(lái)版本中移除。主題設(shè)計(jì)系統(tǒng)亮/暗色板primary, tertiaryazure-blue.cssM3亮azure, bluerose-red.cssM3亮rose, redcyan-orange.cssM3暗cyan, orangemagenta-violet.cssM3暗magenta, violetdeeppurple-amber.cssM2亮deep-purple, amberindigo-pink.cssM2亮indigo, pinkpink-bluegrey.cssM2暗pink, blue-greypurple-green.cssM2暗purple, green預(yù)構(gòu)建主題文件位于 Angular Material npm 包的prebuilt-themes目錄即angular/material/prebuilt-themes。在項(xiàng)目angular.json的styles數(shù)組中引入所選 CSS 文件即可styles: [ angular/material/prebuilt-themes/azure-blue.css ]這些預(yù)構(gòu)建主題的源碼就存放在本倉(cāng)庫(kù)的 src/material/core/theming/prebuilt 目錄下是學(xué)習(xí)完整主題定義的絕佳范例。例如 azure-blue.scss 的實(shí)現(xiàn)正是調(diào)用system.theme傳入theme-type: light、azure 主色板、blue 三級(jí)色板與 Roboto 字體html { include system.theme(( color: ( theme-type: light, primary: palettes.$azure-palette, tertiary: palettes.$blue-palette, ), typography: Roboto, density: 0, )); }色板Color Palettes色板是一組色調(diào)相近、明度由淺到深的顏色集合。Angular Material 主題借助色板構(gòu)建配色方案以傳達(dá)應(yīng)用的層級(jí)hierarchy、狀態(tài)state與品牌brand信息。內(nèi)置色板Angular Material 提供了12 個(gè)預(yù)構(gòu)建色板可直接用于應(yīng)用主題$red-palette$green-palette$blue-palette$yellow-palette$cyan-palette$magenta-palette$orange-palette$chartreuse-palette$spring-green-palette$azure-palette$violet-palette$rose-palette這些色板全部定義在 src/material/core/theming/_palettes.scss 中。以$violet-palette為例它包含 0~100 的色調(diào)梯度如40: #7d00fa、80: #d5baff并且通過(guò)_patch-error-palette為每個(gè)色板補(bǔ)充了獨(dú)立的error色階如40: #ba1a1a同時(shí)每個(gè)色板都內(nèi)置secondary次要、neutral中性、neutral-variant中性變體子色板這些子色板會(huì)隨主題自動(dòng)參與 M3 系統(tǒng)色的構(gòu)建見(jiàn) theming/_definition.scss 中 primary/secondary/tertiary/neutral/neutral-variant/error 六類色板的組裝邏輯。自定義色板Angular Material 提供了色板生成 schematic基于單個(gè)主色輸入構(gòu)建自定義色板并可選擇性輸入更多顏色以進(jìn)一步定制 secondary、tertiary 與 neutral 色板ng generate angular/material:theme-color該 schematic 的詳細(xì)說(shuō)明見(jiàn) src/material/schematics/ng-generate/theme-color/README.md其支持primaryColor、tertiaryColor、neutralColor、neutralVariantColor等選項(xiàng)未指定時(shí)由 Material 基于主色自動(dòng)推導(dǎo)生成的$primary-palette、$tertiary-palette可直接接入mat.theme使用并額外提供高對(duì)比度prefers-contrast覆蓋方案。加載字體Loading FontsGoogle Fonts 是加載字體的常用選項(xiàng)之一。例如下面的代碼放在應(yīng)用head中即可加載 Roboto400/500/700與 Open Sans300..800字體族link relpreconnect hrefhttps://fonts.googleapis.com link relpreconnect hrefhttps://fonts.gstatic.com crossorigin link hrefhttps://fonts.googleapis.com/css2?familyOpenSans:ital,wght0,300..800;1,300..800familyRoboto:wght400;500;700displayswap relstylesheet注意默認(rèn)情況下使用 Angular CLI 創(chuàng)建的項(xiàng)目被配置為內(nèi)聯(lián)來(lái)自 Google Fonts 的資源以減少阻塞渲染的請(qǐng)求。這也解釋了為什么上面的加載示例要在head中顯式使用preconnect——自行引入字體時(shí)可以通過(guò)預(yù)連接減少加載延遲。支持亮色與暗色模式默認(rèn)情況下mat.thememixin 使用light-dark()CSS 顏色函數(shù)定義顏色使應(yīng)用能夠輕松地在亮暗模式間切換。light-dark()函數(shù)依賴全局樣式中聲明的color-scheme值若應(yīng)用未定義color-scheme則始終應(yīng)用亮色??赏ㄟ^(guò)color-scheme: light或color-scheme: dark顯式指定模式要跟隨用戶系統(tǒng)偏好則使用color-scheme: light darkuse angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); }另一種常見(jiàn)策略是把color-scheme定義在某個(gè) CSS 選擇器下使模式取決于該 class 是否被應(yīng)用。下面示例中應(yīng)用默認(rèn)始終顯示亮色主題除非給body添加dark-mode類use angular/material as mat; html { color-scheme: light; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); } body.dark-mode { color-scheme: dark; }Angular Material 不會(huì)根據(jù)prefers-color-scheme、prefers-contrast等用戶偏好媒體查詢自動(dòng)應(yīng)用不同樣式或主題。它刻意把靈活性留給你可以依賴color-scheme: light dark也可以自定義媒體查詢或讀取已保存的用戶偏好來(lái)應(yīng)用樣式。多主題Multiple Themesmat.thememixin 可以被調(diào)用多次以在應(yīng)用中應(yīng)用多套不同的配色方案。上下文專屬主題下面的示例按上下文定制組件主題為一段刪除數(shù)據(jù)提示的容器應(yīng)用 cyan 色板使其中的按鈕等組件獲得獨(dú)特、醒目的強(qiáng)調(diào)樣式use angular/material as mat; html { include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0, )); } .example-bright-container { include mat.theme(( color: mat.$cyan-palette, )); }這種做法的底層機(jī)制是每次調(diào)用 mixin 都會(huì)在當(dāng)前選擇器下重新發(fā)射一組--mat-sys-*CSS 變量見(jiàn) tokens/_system.scss 中current-selector-or-root的變量輸出邏輯子容器內(nèi)組件讀取到的變量因此被局部覆蓋從而實(shí)現(xiàn)局部換膚。使用主題樣式Using Theme Styles應(yīng)用的自定義組件可以直接使用mat.theme定義的 CSS 變量來(lái)應(yīng)用主題的顏色與排版顏色變量適合強(qiáng)調(diào)重要文本與操作、強(qiáng)化應(yīng)用品牌、確保 surface 與 on-surface 元素間有足夠的對(duì)比度排版變量適合在整個(gè)應(yīng)用中建立清晰的信息層級(jí)與文本一致性。下面示例演示組件使用顏色與排版變量實(shí)現(xiàn)一個(gè)向用戶呈現(xiàn)重要信息的全寬橫幅.my-component { background: var(--mat-sys-primary-container); color: var(--mat-sys-on-primary-container); border: 1px solid var(--mat-sys-outline-variant); font: var(--mat-sys-body-large); }也可以改用工具類達(dá)到同樣的效果div classmat-bg-primary-container mat-text-on-primary-container mat-border-variant mat-font-body-lg/div這些變量與工具類的完整清單、使用場(chǎng)景以及組件對(duì)它們的依賴方式可參閱同倉(cāng)庫(kù)的 Theming your components 指南。自定義 Design TokensCustomizing TokensAngular Material 組件還允許通過(guò)overrides mixin對(duì)特定 Token 進(jìn)行精準(zhǔn)定制實(shí)現(xiàn)細(xì)粒度的調(diào)整——既可修改系統(tǒng)級(jí)主題 CSS 變量也可修改單個(gè)組件的 Token如組件邊框顏色或標(biāo)題字號(hào)。overrides API 會(huì)校驗(yàn)自定義 Token 的拼寫是否正確并可在未來(lái)版本 Token 被新增、移動(dòng)或重命名時(shí)用于保證向后兼容。系統(tǒng)級(jí) TokenSystem Tokens通過(guò)mat.theme-overridesmixin 可更改系統(tǒng)級(jí) Token它會(huì)重新定義應(yīng)用中使用到的 CSS 變量。下面示例為應(yīng)用應(yīng)用 violet 色板但把primary-containerToken 改為特定藍(lán)色調(diào)use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); .example-orange-primary-container { include mat.theme-overrides(( primary-container: #84ffff )); } }另一種方式在mat.thememixin 中傳入可選的override map直接替換 mixin 應(yīng)用的值use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 ), $overrides: ( primary-container: orange, )); }從源碼看theme-overrides mixin 會(huì)先合并 M3 的 color/typography/elevation/shape/state 全量系統(tǒng)變量名然后逐個(gè)校驗(yàn)傳入的 override 鍵是否存在于系統(tǒng)變量名集合中不存在則被忽略再以--mat-sys-*前綴輸出覆蓋值。同時(shí)mat.theme的$overrides參數(shù)在發(fā)射顏色、排版、高度、形狀、狀態(tài)各系統(tǒng)變量時(shí)都會(huì)優(yōu)先使用 override 值如map.get($overrides, $name) or $value見(jiàn) tokens/_system.scss。組件級(jí) TokenComponent Tokens每個(gè) Angular Material 組件都定義了各自的overridesmixin用于定制其顏色、排版與密度相關(guān)的 Token。各組件可用 Token 的完整清單可在其文檔頁(yè)面的Styling標(biāo)簽下查看。下面示例使用 Card 的overridesAPI 將背景改為紅色、增大圓角、并指定更大的標(biāo)題字號(hào)html { include mat.card-overrides(( elevated-container-color: red, elevated-container-shape: 32px, title-text-size: 2rem, )); }直接樣式覆蓋Direct Style OverridesAngular Material 支持上述方式定制顏色、排版與密度但強(qiáng)烈不鼓勵(lì)、也不直接支持在本主題 API 之外覆蓋組件 CSS。組件的 DOM 結(jié)構(gòu)與 CSS 類被視為私有實(shí)現(xiàn)細(xì)節(jié)隨時(shí)可能變化Angular Material 組件使用的 CSS 變量應(yīng)通過(guò)overridesAPI 定義而不是顯式自行定義。強(qiáng)焦點(diǎn)指示器Strong Focus Indicators默認(rèn)情況下大多數(shù)組件通過(guò)改變背景色來(lái)指示瀏覽器焦點(diǎn)符合 Material Design 規(guī)范。但這種行為可能無(wú)法滿足可訪問(wèn)性要求——例如 WCAG 4.5:1 要求對(duì)瀏覽器焦點(diǎn)給出更強(qiáng)的指示。Angular Material 支持在獲得焦點(diǎn)的元素上渲染高可見(jiàn)度輪廓。應(yīng)用通過(guò)調(diào)用mat.strong-focus-indicators()啟用use angular/material as mat; html { color-scheme: light dark; include mat.theme(( color: mat.$violet-palette, typography: Roboto, density: 0 )); include mat.strong-focus-indicators(); }默認(rèn)情況下焦點(diǎn)指示器使用主題的secondary 顏色可通過(guò)調(diào)用strong-focus-indicators-theme($color)mixin 自定義顏色也可在默認(rèn)顏色與背景對(duì)比度不足的場(chǎng)景下用它更換焦點(diǎn)指示器顏色。自定義強(qiáng)焦點(diǎn)指示器可以向strong-focus-indicators傳入配置 map 自定義指示器外觀支持border-color、border-style、border-width與border-radius四個(gè)配置項(xiàng)use angular/material as mat; include mat.strong-focus-indicators(( border-color: red, border-style: dotted, border-width: 4px, border-radius: 2px, ));源碼實(shí)現(xiàn)見(jiàn) focus-indicators/_private.scssmixin 的默認(rèn)配置為border-color: var(--mat-sys-secondary, black)與display: block用戶配置會(huì)與默認(rèn)配置合并同時(shí)該 mixin 還會(huì)為標(biāo)準(zhǔn) chips 的內(nèi)部結(jié)構(gòu)補(bǔ)上overflow: visible以避免與焦點(diǎn)指示器的渲染沖突。在 Shadow DOM 中使用主題Angular Material 默認(rèn)假設(shè)所有主題樣式以全局 CSS方式加載。如果應(yīng)用要使用 Shadow DOM則必須在每個(gè)包含 Angular Material 組件的 shadow root 內(nèi)加載主題樣式??梢酝ㄟ^(guò)兩種方式實(shí)現(xiàn)在每個(gè) shadow root 中手動(dòng)加載 CSS使用 Constructable Stylesheets 在 shadow root 間共享主題樣式??偨Y(jié)一套主題方案的完整決策路徑綜合全文搭建 Angular Material 主題的決策路徑可以歸納為四步選擇主題來(lái)源若追求開(kāi)箱即用直接在angular.json引入 預(yù)構(gòu)建主題推薦 M3 主題若需要品牌化定制則編寫 Sass 主題文件調(diào)用mat.theme確定配色從 12 個(gè)內(nèi)置色板 中選擇或通過(guò)ng generate angular/material:theme-color生成自定義色板并按需通過(guò)顏色 map 區(qū)分 primary/tertiary 與theme-type確定排版與密度選擇單一字體族或 plain/brand 雙字體方案權(quán)衡密度 0~-5 對(duì)布局緊湊度與可訪問(wèn)性的影響細(xì)化與兼容借助mat.theme-overrides與組件級(jí)overridesmixin 微調(diào) Token通過(guò)color-scheme實(shí)現(xiàn)亮暗模式調(diào)用strong-focus-indicators強(qiáng)化可訪問(wèn)性并在 Shadow DOM 場(chǎng)景下正確分發(fā)主題樣式。每一步的底層行為默認(rèn)值、light-dark()生成邏輯、Token 校驗(yàn)、密度變量發(fā)射等都可以在 tokens/_system.scss、theming/_definition.scss 與 focus-indicators/_private.scss 等源碼文件中找到對(duì)應(yīng)實(shí)現(xiàn)方便你在遇到邊界問(wèn)題時(shí)深入排查?!久赓M(fèi)下載鏈接】componentsComponent infrastructure and Material Design components for Angular項(xiàng)目地址: https://gitcode.com/GitHub_Trending/co/components創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考