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