SPFxではスタイルシートを使って独自のデザインを実現することができますが、背景色や文字色を固定してしまうとSharePointサイトの「外観の変更」機能でテーマを変更した時に文字が見えなくなってしまうなどの弊害を伴う可能性があります。SPFx開発の際は固定の色を指定せず、サイトのテーマを反映するようにしましょう。
サイトのテーマを反映したWebパーツの例
下図はサイトのテーマを反映するように開発したWebパーツの例です。テーマの変更に伴って背景色や文字色が変わっていることが確認できます。
実現方法
実現方法は簡単です。以下2パターンの方法を組み合わせます。
2つの基本原則に従えば8割方は大丈夫
まず、SPFx開発では以下2つの原則を守るようにします。これで8割方はサイトのテーマを反映するようになります。
- scssやstyleで色を固定しない(color: black;などを書かない)
- できるだけOffice UI Fabricを用いる
はい、シンプルですね。当然ですが色を指定しなければ上位の構造から色を継承します。また、Office UI FabricコンポーネントもきちんとSharePointのテーマを継承してくれます。
残り2割はトークンを使った指定で実現
本稿執筆時点ではaタグなど一部のHTMLタグは基本原則に従ってもテーマが反映されません。こういった場合には自前のスタイルを適用して該当要素をサイトのテーマに従わせる必要があります。SharePoint側で用意されているトークンを使うことでこれを実現することができます。
a { & :hover { color: "[theme: linkHovered]" } color: "[theme: link]" }
上記の例では"[theme:link]"と"[theme:linkHovered]"がトークンに当たります。利用可能なトークンについては次章に記載します。
トークン一覧
SPFxで利用可能なトークンは、JavaScriptをデバッグしてwindowオブジェクト内を覗くと分かります。具体的にはwindow.__themeState__.themeプロパティにトークンが列挙されています。2019年10月8日時点では以下の情報が格納されていました。jsonプロパティがトークンで、jsonプロパティの値は現在のテーマの値です。
{ "themeDarker": "#014446", "themeDark": "#025c5f", "themeDarkAlt": "#026d70", "themePrimary": "#03787c", "themeSecondary": "#13898d", "themeTertiary": "#49aeb1", "themeLight": "#98d6d8", "themeLighter": "#c5e9ea", "themeLighterAlt": "#f0f9fa", "black": "#000000", "blackTranslucent40": "rgba(0,0,0,.4)", "neutralDark": "#212121", "neutralPrimary": "#333333", "neutralPrimaryAlt": "#3c3c3c", "neutralSecondary": "#666666", "neutralSecondaryAlt": "#767676", "neutralTertiary": "#a6a6a6", "neutralTertiaryAlt": "#c8c8c8", "neutralQuaternary": "#d0d0d0", "neutralQuaternaryAlt": "#dadada", "neutralLight": "#eaeaea", "neutralLighter": "#f4f4f4", "neutralLighterAlt": "#f8f8f8", "accent": "#4f6bed", "white": "#ffffff", "whiteTranslucent40": "rgba(255,255,255,.4)", "yellowDark": "#d29200", "yellow": "#ffb900", "yellowLight": "#fff100", "orange": "#d83b01", "orangeLight": "#ea4300", "orangeLighter": "#ff8c00", "redDark": "#a80000", "red": "#e81123", "magentaDark": "#5c005c", "magenta": "#b4009e", "magentaLight": "#e3008c", "purpleDark": "#32145a", "purple": "#5c2d91", "purpleLight": "#b4a0ff", "blueDark": "#002050", "blueMid": "#00188f", "blue": "#0078d4", "blueLight": "#00bcf2", "tealDark": "#004b50", "teal": "#008272", "tealLight": "#00b294", "greenDark": "#004b1c", "green": "#107c10", "greenLight": "#bad80a", "primaryBackground": "#ffffff", "primaryText": "#333333", "bodyBackground": "#ffffff", "bodyStandoutBackground": "#f8f8f8", "bodyFrameBackground": "#ffffff", "bodyFrameDivider": "#eaeaea", "bodyText": "#333333", "bodyTextChecked": "#000000", "bodySubtext": "#666666", "bodyDivider": "#eaeaea", "disabledBackground": "#f4f4f4", "disabledText": "#a6a6a6", "disabledBodyText": "#a6a6a6", "disabledSubtext": "#d0d0d0", "disabledBodySubtext": "#c8c8c8", "focusBorder": "#666666", "variantBorder": "#eaeaea", "variantBorderHovered": "#a6a6a6", "defaultStateBackground": "#f8f8f8", "errorText": "#a80000", "warningText": "#333333", "successText": "#107C10", "errorBackground": "rgba(232, 17, 35, .2)", "blockingBackground": "rgba(234, 67, 0, .2)", "warningBackground": "rgba(255, 185, 0, .2)", "warningHighlight": "#ffb900", "successBackground": "rgba(186, 216, 10, .2)", "inputBorder": "#a6a6a6", "inputBorderHovered": "#333333", "inputBackground": "#ffffff", "inputBackgroundChecked": "#03787c", "inputBackgroundCheckedHovered": "#026d70", "inputForegroundChecked": "#ffffff", "inputFocusBorderAlt": "#03787c", "smallInputBorder": "#666666", "inputText": "#333333", "inputTextHovered": "#212121", "inputPlaceholderText": "#666666", "buttonBackground": "#f4f4f4", "buttonBackgroundChecked": "#c8c8c8", "buttonBackgroundHovered": "#eaeaea", "buttonBackgroundCheckedHovered": "#eaeaea", "buttonBackgroundPressed": "#eaeaea", "buttonBackgroundDisabled": "#f4f4f4", "buttonBorder": "transparent", "buttonText": "#333333", "buttonTextHovered": "#212121", "buttonTextChecked": "#212121", "buttonTextCheckedHovered": "#000000", "buttonTextPressed": "#212121", "buttonTextDisabled": "#a6a6a6", "buttonBorderDisabled": "transparent", "primaryButtonBackground": "#03787c", "primaryButtonBackgroundHovered": "#026d70", "primaryButtonBackgroundPressed": "#025c5f", "primaryButtonBackgroundDisabled": "#f4f4f4", "primaryButtonBorder": "transparent", "primaryButtonText": "#ffffff", "primaryButtonTextHovered": "#ffffff", "primaryButtonTextPressed": "#ffffff", "primaryButtonTextDisabled": "#d0d0d0", "accentButtonBackground": "#4f6bed", "accentButtonText": "#ffffff", "menuBackground": "#ffffff", "menuDivider": "#c8c8c8", "menuIcon": "#03787c", "menuHeader": "#03787c", "menuItemBackgroundHovered": "#f4f4f4", "menuItemBackgroundPressed": "#eaeaea", "menuItemText": "#333333", "menuItemTextHovered": "#212121", "listBackground": "#ffffff", "listText": "#333333", "listItemBackgroundHovered": "#f4f4f4", "listItemBackgroundChecked": "#eaeaea", "listItemBackgroundCheckedHovered": "#dadada", "listHeaderBackgroundHovered": "#f4f4f4", "listHeaderBackgroundPressed": "#eaeaea", "actionLink": "#333333", "actionLinkHovered": "#212121", "link": "#03787c", "linkHovered": "#014446", "listTextColor": "#333333", "menuItemBackgroundChecked": "#eaeaea", "elevation4": "0 0 5px 0 rgba(0,0,0,.4)", "elevation8": "0 0 5px 0 rgba(0,0,0,.4)", "elevation16": "0 0 5px 0 rgba(0,0,0,.4)", "elevation64": "0 0 5px 0 rgba(0,0,0,.4)", "roundedCorner2": "0px", "tinyFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "tinyMozOsxFontSmoothing": "grayscale", "tinyWebkitFontSmoothing": "antialiased", "tinyFontSize": "10px", "tinyFontWeight": 600, "xSmallFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "xSmallMozOsxFontSmoothing": "grayscale", "xSmallWebkitFontSmoothing": "antialiased", "xSmallFontSize": "11px", "xSmallFontWeight": 400, "smallFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "smallMozOsxFontSmoothing": "grayscale", "smallWebkitFontSmoothing": "antialiased", "smallFontSize": "12px", "smallFontWeight": 400, "smallPlusFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "smallPlusMozOsxFontSmoothing": "grayscale", "smallPlusWebkitFontSmoothing": "antialiased", "smallPlusFontSize": "13px", "smallPlusFontWeight": 400, "mediumFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "mediumMozOsxFontSmoothing": "grayscale", "mediumWebkitFontSmoothing": "antialiased", "mediumFontSize": "14px", "mediumFontWeight": 400, "mediumPlusFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "mediumPlusMozOsxFontSmoothing": "grayscale", "mediumPlusWebkitFontSmoothing": "antialiased", "mediumPlusFontSize": "15px", "mediumPlusFontWeight": 400, "largeFontFamily": "'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "largeMozOsxFontSmoothing": "grayscale", "largeWebkitFontSmoothing": "antialiased", "largeFontSize": "17px", "largeFontWeight": 300, "xLargeFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "xLargeMozOsxFontSmoothing": "grayscale", "xLargeWebkitFontSmoothing": "antialiased", "xLargeFontSize": "21px", "xLargeFontWeight": 100, "xLargePlusFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "xLargePlusMozOsxFontSmoothing": "grayscale", "xLargePlusWebkitFontSmoothing": "antialiased", "xLargePlusFontSize": "21px", "xLargePlusFontWeight": 100, "xxLargeFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "xxLargeMozOsxFontSmoothing": "grayscale", "xxLargeWebkitFontSmoothing": "antialiased", "xxLargeFontSize": "28px", "xxLargeFontWeight": 100, "xxLargePlusFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "xxLargePlusMozOsxFontSmoothing": "grayscale", "xxLargePlusWebkitFontSmoothing": "antialiased", "xxLargePlusFontSize": "28px", "xxLargePlusFontWeight": 100, "superLargeFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "superLargeMozOsxFontSmoothing": "grayscale", "superLargeWebkitFontSmoothing": "antialiased", "superLargeFontSize": "42px", "superLargeFontWeight": 100, "megaFontFamily": "'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Roboto', 'Helvetica Neue', sans-serif", "megaMozOsxFontSmoothing": "grayscale", "megaWebkitFontSmoothing": "antialiased", "megaFontSize": "72px", "megaFontWeight": 100 }
以上、参考になれば幸いです。