使用级联样式表为应用程序设置样式

.NET 多平台应用 UI (.NET MAUI) 应用可以使用级联样式表(CSS)进行样式设置。 样式表由规则列表组成,每个规则由一个或多个选择器和声明块组成。 声明块由大括号中的声明列表组成,每个声明由属性、冒号和值组成。 当块中有多个声明时,分号将作为分隔符插入。

以下示例演示了一些符合 .NET MAUI 的 CSS:

navigationpage {
    -maui-bar-background-color: lightgray;
}

^contentpage {
    background-color: lightgray;
}

#listView {
    background-color: lightgray;
}

stacklayout {
    margin: 20;
    -maui-spacing: 6;
}

grid {
    row-gap: 6;
    column-gap: 6;
}
.mainPageTitle {
    font-style: bold;
    font-size: 14;
}

.mainPageSubtitle {
    margin-top: 15;
}

.detailPageTitle {
    font-style: bold;
    font-size: 14;
    text-align: center;
}

.detailPageSubtitle {
    text-align: center;
    font-style: italic;
}

listview image {
    height: 60;
    width: 60;
}

stacklayout>image {
    height: 200;
    width: 200;
}

在 .NET MAUI 中,CSS 样式表在运行时进行分析和评估,而不是编译时,样式表将在使用时重新分析。

重要

无法使用 CSS 完全设置 .NET MAUI 应用的样式。 但是,XAML 样式可用于补充 CSS。 有关 XAML 样式的详细信息,请参阅 使用 XAML 样式应用

使用样式表

将样式表添加到 .NET MAUI 应用的过程如下所示:

  1. 将空 CSS 文件添加到 .NET MAUI 应用项目。 CSS 文件可以放置在任何文件夹中,资源 文件夹是推荐的位置。
  2. 将 CSS 文件的生成操作设置为 MauiCss

加载样式表

有多种方法可用于加载样式表。

注意

无法在运行时更改样式表并应用新的样式表。

在 XAML 中加载样式表

在将样式表添加到 ResourceDictionary之前,可以先使用 StyleSheet 类加载并解析它。

<Application ...>
    <Application.Resources>
        <StyleSheet Source="/Resources/styles.css" />
    </Application.Resources>
</Application>

StyleSheet.Source 属性将样式表指定为相对于封闭 XAML 文件位置的 URI,或者如果 URI 以 /开头,则指定为相对于项目根目录的 URI。

警告

如果 CSS 文件的生成操作未设置为 MauiCss,则将无法加载。

在将样式表内联到 ResourceDictionary并添加之前,可以通过使用 StyleSheet 类加载和解析样式表的方式,放入 CDATA 节中:

<ContentPage ...>
    <ContentPage.Resources>
        <StyleSheet>
            <![CDATA[
            ^contentpage {
                background-color: lightgray;
            }
            ]]>
        </StyleSheet>
    </ContentPage.Resources>
    ...
</ContentPage>

有关资源字典的详细信息,请参阅 资源字典

在 C 中加载样式表#

在 C# 中,可以从 StringReader 加载样式表并将其添加到 ResourceDictionary

using Microsoft.Maui.Controls.StyleSheets;

public partial class MyPage : ContentPage
{
    public MyPage()
    {
        InitializeComponent();

        using (var reader = new StringReader("^contentpage { background-color: lightgray; }"))
        {
            this.Resources.Add(StyleSheet.FromReader(reader));
        }
    }
}

StyleSheet.FromReader 方法的参数是已读取样式表的 TextReader

选择元素并应用属性

CSS 使用选择器来确定要定位的元素。 按定义顺序连续应用具有匹配选择器的样式。 对特定项定义的样式始终最后应用。 有关支持的选择器的详细信息,请参阅 选择器参考

CSS 使用属性设置所选元素的样式。 每个属性都有一组可能的值,一些属性可能会影响任何类型的元素,而另一些属性则适用于元素组。 有关支持的属性的详细信息,请参阅 属性参考

如果子样式表和父样式表设置了相同的属性,子样式表将始终优先于父样式表。 因此,应用设置相同属性的样式时,将遵循以下优先规则:

  • 应用资源中定义的样式将被页面资源中定义的样式覆盖(如果它们设置了相同的属性)。
  • 如果页面资源中定义的样式与控件资源中定义的样式设置了相同的属性,那么页面资源中的样式将会被覆盖。
  • 如果控件资源中定义的样式与应用资源中定义的样式设置了相同的属性,应用资源中的样式将被覆盖。

注意

不支持 CSS 变量。

按类型选择元素

在可视化树中,可以使用不区分大小写的 element 选择器按类型选择元素。

stacklayout {
    margin: 20;
}

此选择器标识使用样式表的页面上的任何 StackLayout 元素,并将页边距设置为 20 的统一粗细。

注意

element 选择器不标识指定类型的子类。

按基类选择元素

可视化树中的元素可以通过不区分大小写的 ^base 选择器来选择基类。

^contentpage {
    background-color: lightgray;
}

此选择器标识使用样式表的任何 ContentPage 元素,并将其背景色设置为 lightgray

注意

^base 选择器特定于 .NET MAUI,不属于 CSS 规范。

按名称选择元素

可以使用区分大小写 #id 选择器选择可视化树中的单个元素:

#listView {
    background-color: lightgray;
}

此选择器标识其 StyleId 属性设置为 listView的元素。 但是,如果未设置 StyleId 属性,选择器将回退到使用元素 x:Name。 因此,在以下示例中,#listView 选择器将标识其 x:Name 属性设置为 listViewListView,并将其背景色设置为 lightgray

<ContentPage ...>
    <ContentPage.Resources>
        <StyleSheet Source="/Resources/styles.css" />
    </ContentPage.Resources>
    <StackLayout>
        <ListView x:Name="listView">
            ...
        </ListView>
    </StackLayout>
</ContentPage>

选择具有特定类属性的元素

可以使用区分大小写 .class 选择器选择具有特定类属性的元素:

.detailPageTitle {
    font-style: bold;
    font-size: 14;
    text-align: center;
}

.detailPageSubtitle {
    text-align: center;
    font-style: italic;
}

通过将元素的 StyleClass 属性设置为 CSS 类名称,可以将 CSS 类分配给 XAML 元素。 因此,在以下示例中,.detailPageTitle 类定义的样式将分配给第一个 Label,而 .detailPageSubtitle 类定义的样式则分配给第二个 Label

<ContentPage ...>
    <ContentPage.Resources>
        <StyleSheet Source="/Resources/styles.css" />
    </ContentPage.Resources>
    <ScrollView>
        <StackLayout>
            <Label ... StyleClass="detailPageTitle" />
            <Label ... StyleClass="detailPageSubtitle"/>
        </StackLayout>
    </ScrollView>
</ContentPage>

选择子元素

可以使用不区分大小写 element element 选择器选择可视化树中的子元素:

listview image {
    height: 60;
    width: 60;
}

此选择器标识 ListView 元素的任何 Image 子元素,并将其高度和宽度设置为 60 像素。 因此,在以下 XAML 示例中,listview image 选择器将标识 ListView的子级 Image,并将其高度和宽度设置为 60。

<ContentPage ...>
    <ContentPage.Resources>
        <StyleSheet Source="/Resources/styles.css" />
    </ContentPage.Resources>
    <StackLayout>
        <ListView ...>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid>
                            ...
                            <Image ... />
                            ...
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

注意事项

element element 选择器不要求子元素是父级的 直接 子元素,子元素可能具有不同的父元素。 当祖先是指定的第一个元素时,将会发生选择。

选择直接子元素

可以通过不区分大小写 element>element 选择器选择可视化树中的直接子元素:

stacklayout>image {
    height: 200;
    width: 200;
}

此选择器标识 StackLayout 元素的直接子级的任何 Image 元素,并将其高度和宽度设置为 200。 因此,在下面的示例中,stacklayout>image 选择器将标识 StackLayout的直接子级 Image,并将其高度和宽度设置为 200。

<ContentPage ...>
    <ContentPage.Resources>
        <StyleSheet Source="/Resources/styles.css" />
    </ContentPage.Resources>
    <ScrollView>
        <StackLayout>
            ...
            <Image ... />
            ...
        </StackLayout>
    </ScrollView>
</ContentPage>

注意

element>element 选择器要求子元素是父级的直接 子元素

选择器参考

.NET MAUI 支持以下 CSS 选择器:

选择器 描述
.class .header 选择包含“header”的 StyleClass 属性的所有元素。 此选择器区分大小写。
#id #email 选择所有 StyleId 被设置为 email的元素。 如果未设置 StyleId,则回退到 x:Name。 使用 XAML 时,首选 x:Name 而不是 StyleId。 此选择器区分大小写。
* * 选择所有元素。
element label 选择类型为 Label的所有元素,但不包括这些元素的子类。 此选择器不区分大小写。
^base ^contentpage 选择 ContentPage 作为基类的所有元素,包括 ContentPage 本身。 此选择器不区分大小写,不属于 CSS 规范。
element,element label,button 选择所有 Button 元素和所有 Label 元素。 此选择器不区分大小写。
element element stacklayout label 选择 StackLayout中的所有 Label 元素。 此选择器不区分大小写。
element>element stacklayout>label 选择所有直接父级为 StackLayoutLabel 元素。 此选择器不区分大小写。
element+element label+entry 直接在 Label之后选择所有 Entry 元素。 此选择器不区分大小写。
element~element label~entry 选择前面有 Label的所有 Entry 元素。 此选择器不区分大小写。

按定义顺序连续应用具有匹配选择器的样式。 对特定项定义的样式始终最后应用。

提示

选择器可以组合在一起,且不受限制,例如 StackLayout>ContentView>label.email

不支持以下选择器:

  • [attribute]
  • @media@supports
  • :::

注意

不支持特定性和特定性替代。

如果两个或多个 CSS 规则指向同一元素,则具有最高特定性的选择器将优先,其样式声明将应用于该元素。 特异性算法 计算 CSS 选择器的权重,以确定多个竞争的 CSS 声明中哪个规则被应用于元素。

属性引用

.NET MAUI 支持以下 CSS 属性(在 列中,类型 斜体,而字符串文本 gray):

财产 适用于 价值观
align-content FlexLayout stretch | center | start | end | spacebetween | spacearound | spaceevenly | flex-start | flex-end | space-between | space-around | initial align-content: space-between;
align-items FlexLayout stretch | center | start | end | flex-start | flex-end | initial align-items: flex-start;
align-self VisualElement auto | stretch | center | start | end | flex-start | flex-end | initial align-self: flex-end;
background-color VisualElement 颜色 | initial background-color: springgreen;
background-image Page 字符串 | initial background-image: bg.png;
border-color ButtonFrameImageButton 颜色 | initial border-color: #9acd32;
border-radius BoxViewButtonFrameImageButton | initial border-radius: 10;
border-width ButtonImageButton | initial border-width: .5;
color ActivityIndicatorBoxViewButtonCheckBoxDatePickerEditorEntryLabelPickerProgressBarSearchBarSwitchTimePicker 颜色 | initial color: rgba(255, 0, 0, 0.3);
column-gap Grid | initial column-gap: 9;
direction VisualElement ltr | rtl | inherit | initial direction: rtl;
flex-direction FlexLayout column | columnreverse | row | rowreverse | row-reverse | column-reverse | initial flex-direction: column-reverse;
flex-basis VisualElement 浮点 | auto | initial。 此外,可以使用 % 符号指定范围 0% 到 100% 中的百分比。 flex-basis: 25%;
flex-grow VisualElement 浮点 | initial flex-grow: 1.5;
flex-shrink VisualElement 浮点 | initial flex-shrink: 1;
flex-wrap VisualElement nowrap | wrap | reverse | wrap-reverse | initial flex-wrap: wrap-reverse;
font-family ButtonDatePickerEditorEntryLabelPickerSearchBarTimePickerSpan 字符串 | initial font-family: Consolas;
font-size ButtonDatePickerEditorEntryLabelPickerSearchBarTimePickerSpan | initial font-size: 12;
font-style ButtonDatePickerEditorEntryLabelPickerSearchBarTimePickerSpan bold | italic | initial font-style: bold;
height VisualElement | initial height: 250;
justify-content FlexLayout start | center | end | spacebetween | spacearound | spaceevenly | flex-start | flex-end | space-between | space-around | initial justify-content: flex-end;
letter-spacing ButtonDatePickerEditorEntryLabelPickerSearchBarSearchHandlerSpanTimePicker | initial letter-spacing: 2.5;
line-height LabelSpan | initial line-height: 1.8;
margin View 厚度 | initial margin: 6 12;
margin-left View 厚度 | initial margin-left: 3;
margin-top View 厚度 | initial margin-top: 2;
margin-right View 厚度 | initial margin-right: 1;
margin-bottom View 厚度 | initial margin-bottom: 6;
max-lines Label int | initial max-lines: 2;
min-height VisualElement | initial min-height: 50;
min-width VisualElement | initial min-width: 112;
opacity VisualElement | initial opacity: .3;
order VisualElement int | initial order: -1;
padding ButtonImageButtonLayoutPage 厚度 | initial padding: 6 12 12;
padding-left ButtonImageButtonLayoutPage | initial padding-left: 3;
padding-top ButtonImageButtonLayoutPage | initial padding-top: 4;
padding-right ButtonImageButtonLayoutPage | initial padding-right: 2;
padding-bottom ButtonImageButtonLayoutPage | initial padding-bottom: 6;
position FlexLayout relative | absolute | initial position: absolute;
row-gap Grid | initial row-gap: 12;
text-align EntryEntryCellLabelSearchBar left | top | right | bottom | start | center | middle | end | initial。 应在从右到左的环境中避免 leftright text-align: right;
text-decoration LabelSpan none | underline | strikethrough | line-through | initial text-decoration: underline, line-through;
text-transform ButtonEditorEntryLabelSearchBarSearchHandler none | default | uppercase | lowercase | initial text-transform: uppercase;
transform VisualElement nonerotaterotateXrotateYscalescaleXscaleYtranslatetranslateXtranslateYinitial transform: rotate(180), scaleX(2.5);
transform-origin VisualElement | initial transform-origin: 7.5, 12.5;
vertical-align Label left | top | right | bottom | start | center | middle | end | initial vertical-align: bottom;
visibility VisualElement true | visible | false | hidden | collapse | initial visibility: hidden;
width VisualElement | initial width: 320;

注意

initial 是所有属性的有效值。 它清除从另一种样式设置的值(重置为默认值)。

不支持以下属性:

  • all: initial
  • 布局属性(框或网格)。
  • 速记属性,如 fontborder

此外,没有 inherit 值,因此不支持继承。 因此,不能在布局上设置 font-size 属性,并期望布局中的所有 Label 实例继承该值。 一个例外是 direction 属性,该属性的默认值为 inherit

重要

Span 元素无法使用 CSS 进行定位。

.NET MAUI 特定属性

还支持以下特定于 .NET MAUI 的 CSS 属性(在 列中,类型 斜体,而字符串文本 gray):

财产 适用于 价值观
-maui-bar-background-color NavigationPageTabbedPage 颜色 | initial -maui-bar-background-color: teal;
-maui-bar-text-color NavigationPageTabbedPage 颜色 | initial -maui-bar-text-color: gray
-maui-horizontal-scroll-bar-visibility ScrollView default | always | never | initial -maui-horizontal-scroll-bar-visibility: never;
-maui-max-length EntryEditorSearchBar int | initial -maui-max-length: 20;
-maui-max-track-color Slider 颜色 | initial -maui-max-track-color: red;
-maui-min-track-color Slider 颜色 | initial -maui-min-track-color: yellow;
-maui-orientation ScrollViewStackLayout horizontal | vertical | both | initialboth 仅在 ScrollView上受支持。 -maui-orientation: horizontal;
-maui-placeholder EntryEditorSearchBar 引用的文本 | initial -maui-placeholder: Enter name;
-maui-placeholder-color EntryEditorSearchBar 颜色 | initial -maui-placeholder-color: green;
-maui-spacing StackLayout | initial -maui-spacing: 8;
-maui-shadow VisualElement 有效格式为:color、offsetX、offsetY | offsetX、offsetY、radius、color | offsetX、offsetY、radius、color、opacity -maui-shadow: #000000 4 4;
-maui-thumb-color SliderSwitch 颜色 | initial -maui-thumb-color: limegreen;
-maui-vertical-scroll-bar-visibility ScrollView default | always | never | initial -maui-vertical-scroll-bar-visibility: always;
-maui-vertical-text-alignment Label start | center | end | initial -maui-vertical-text-alignment: end;
-maui-visual VisualElement 字符串 | initial -maui-visual: material;

.NET MAUI Shell 特定属性

还支持以下特定于 .NET MAUI Shell 的 CSS 属性(在 列中,类型 斜体,而字符串文本 gray):

财产 适用于 价值观
-maui-flyout-background Shell 颜色: | initial -maui-flyout-background: red;
-maui-shell-background Element 颜色 | initial -maui-shell-background: green;
-maui-shell-disabled Element 颜色 | initial -maui-shell-disabled: blue;
-maui-shell-foreground Element 颜色 | initial -maui-shell-foreground: yellow;
-maui-shell-tabbar-background Element 颜色 | initial -maui-shell-tabbar-background: white;
-maui-shell-tabbar-disabled Element 颜色 | initial -maui-shell-tabbar-disabled: black;
-maui-shell-tabbar-foreground Element 颜色 | initial -maui-shell-tabbar-foreground: gray;
-maui-shell-tabbar-title Element 颜色 | initial -maui-shell-tabbar-title: lightgray;
-maui-shell-tabbar-unselected Element 颜色 | initial -maui-shell-tabbar-unselected: cyan;
-maui-shell-title Element 颜色 | initial -maui-shell-title: teal;
-maui-shell-unselected Element 颜色 | initial -maui-shell-unselected: limegreen;

颜色

支持以下 color 值:

  • X11 颜色,与 CSS 颜色和 .NET MAUI 颜色匹配。 这些颜色值不区分大小写。
  • 十六进制颜色:#rgb#argb#rrggbb#aarrggbb
  • rgb 颜色:rgb(255,0,0)rgb(100%,0%,0%)。 值为 0-255 或 0%-100%。
  • rgba 颜色:rgba(255, 0, 0, 0.8)rgba(100%, 0%, 0%, 0.8)。 不透明度值在 0.0-1.0 范围内。
  • hsl 颜色:hsl(120, 100%, 50%)。 h 值在 0-360 范围内,s 和 l 位于范围 0%-100%。
  • hsla 颜色:hsla(120, 100%, 50%, .8)。 不透明度值在 0.0-1.0 范围内。

厚度

支持一个、两个、三个或四个 thickness 值,每个值用空格分隔:

  • 单个值表示均匀的粗细。
  • 两个值指示垂直厚度和水平厚度。
  • 三个值分别指示顶部、左右水平,然后是底部的厚度。
  • 四个值分别表示上、右、下、左的厚度。

注意

CSS thickness 值不同于 XAML Thickness 值。 例如,在 XAML 中,双值 Thickness 表示水平和垂直厚度,而四值 Thickness 分别表示左、上、右、下厚度。 此外,XAML Thickness 值以逗号分隔。

功能

可以使用 linear-gradient()radial-gradient() CSS 函数分别指定线性和径向渐变。 这些函数的结果应分配给控件的 background 属性。