Aplicar estilo a las aplicaciones mediante hojas de estilos en cascada

Las aplicaciones de interfaz de usuario de aplicaciones multiplataforma de .NET (.NET MAUI) se pueden aplicar estilos mediante hojas de estilos en cascada (CSS). Una hoja de estilos consta de una lista de reglas, con cada regla que consta de uno o varios selectores y un bloque de declaración. Un bloque de declaración consta de una lista de declaraciones entre llaves, con cada declaración que consta de una propiedad, dos puntos y un valor. Cuando hay varias declaraciones en un bloque, se inserta un punto y coma como separador.

En el ejemplo siguiente se muestran algunos CSS compatibles con MAUI de .NET:

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;
}

En .NET MAUI, las hojas de estilos CSS se analizan y evalúan en tiempo de ejecución, en lugar de tiempo de compilación, y las hojas de estilos se vuelven a analizar en uso.

Importante

No es posible aplicar un estilo completo a una aplicación MAUI de .NET mediante CSS. Sin embargo, los estilos XAML se pueden usar para complementar CSS. Para obtener más información sobre los estilos XAML, consulta Aplicaciones de estilo con XAML.

Consumo de una hoja de estilos

El proceso para agregar una hoja de estilos a una aplicación MAUI de .NET es el siguiente:

  1. Agregue un archivo CSS vacío al proyecto de aplicación MAUI de .NET. El archivo CSS se puede colocar en cualquier carpeta, y la carpeta Resources es la ubicación recomendada.
  2. Establezca la acción de compilación del archivo CSS en MauiCss.

Cargar una hoja de estilos

Hay varios enfoques que se pueden usar para cargar una hoja de estilos.

Nota:

No es posible cambiar una hoja de estilos en tiempo de ejecución y aplicar la nueva hoja de estilos.

Cargar una hoja de estilos en XAML

Se puede cargar y analizar una hoja de estilos con la StyleSheet clase antes de agregarse a :ResourceDictionary

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

La StyleSheet.Source propiedad especifica la hoja de estilos como un URI relativo a la ubicación del archivo XAML envolvente, o en relación con la raíz del proyecto si el URI comienza por un /.

Advertencia

El archivo CSS no se cargará si su acción de compilación no está establecida en MauiCss.

Como alternativa, se puede cargar y analizar una hoja de estilos con la StyleSheet clase , antes de agregarla a un ResourceDictionaryelemento , insertándola en una CDATA sección:

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

Para obtener más información sobre los diccionarios de recursos, consulte Diccionarios de recursos.

Cargar una hoja de estilos en C #

En C#, se puede cargar una hoja de estilos desde y StringReader agregarla a :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));
        }
    }
}

El argumento del StyleSheet.FromReader método es el TextReader que ha leído la hoja de estilos.

Seleccionar elementos y aplicar propiedades

CSS usa selectores para determinar qué elementos se van a establecer como destino. Los estilos con selectores coincidentes se aplican de forma consecutiva, en orden de definición. Los estilos definidos en un elemento específico siempre se aplican en último lugar. Para obtener más información sobre los selectores admitidos, vea Referencia del selector.

CSS usa propiedades para aplicar estilo a un elemento seleccionado. Cada propiedad tiene un conjunto de valores posibles y algunas propiedades pueden afectar a cualquier tipo de elemento, mientras que otras se aplican a grupos de elementos. Para obtener más información sobre las propiedades admitidas, vea Referencia de propiedades.

Las hojas de estilos secundarias siempre invalidan las hojas de estilos primarias si establecen las mismas propiedades. Por lo tanto, se siguen las siguientes reglas de precedencia al aplicar estilos que establecen las mismas propiedades:

  • Un estilo definido en los recursos de la aplicación se sobrescribirá mediante un estilo definido en los recursos de página, si establecen las mismas propiedades.
  • Un estilo definido en los recursos de página se sobrescribirá mediante un estilo definido en los recursos de control, si establecen las mismas propiedades.
  • Un estilo definido en los recursos de la aplicación se sobrescribirá mediante un estilo definido en los recursos de control, si establecen las mismas propiedades.

Nota:

Las variables CSS no son compatibles.

Seleccionar elementos por tipo

Los elementos del árbol visual se pueden seleccionar por tipo con el selector sin distinción entre mayúsculas y minúsculas element :

stacklayout {
    margin: 20;
}

Este selector identifica los StackLayout elementos de las páginas que consumen la hoja de estilos y establece sus márgenes en un grosor uniforme de 20.

Nota:

El element selector no identifica subclases del tipo especificado.

Selección de elementos por clase base

Los elementos del árbol visual se pueden seleccionar mediante la clase base con el selector sin distinción entre mayúsculas y minúsculas ^base :

^contentpage {
    background-color: lightgray;
}

Este selector identifica los ContentPage elementos que consumen la hoja de estilos y establece su color de fondo en lightgray.

Nota:

El ^base selector es específico de .NET MAUI y no forma parte de la especificación CSS.

Selección de un elemento por nombre

Los elementos individuales del árbol visual se pueden seleccionar con el selector de distinción entre mayúsculas y minúsculas #id :

#listView {
    background-color: lightgray;
}

Este selector identifica el elemento cuya StyleId propiedad se establece listViewen . Sin embargo, si la StyleId propiedad no está establecida, el selector volverá a usar el x:Name del elemento . Por lo tanto, en el ejemplo siguiente, el #listView selector identificará el ListView atributo cuyo x:Name atributo está establecido listViewen y establecerá el color de fondo en lightgray.

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

Seleccionar elementos con un atributo de clase específico

Los elementos con un atributo de clase específico se pueden seleccionar con el selector que distingue mayúsculas de minúsculas .class :

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

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

Una clase CSS se puede asignar a un elemento XAML estableciendo la StyleClass propiedad del elemento en el nombre de clase CSS. Por lo tanto, en el ejemplo siguiente, los estilos definidos por la .detailPageTitle clase se asignan al primer Label, mientras que los estilos definidos por la .detailPageSubtitle clase se asignan al segundo Label.

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

Seleccionar elementos secundarios

Los elementos secundarios del árbol visual se pueden seleccionar con el selector sin distinción entre mayúsculas y element element minúsculas:

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

Este selector identifica los Image elementos secundarios de ListView los elementos y establece su alto y ancho en 60. Por lo tanto, en el ejemplo XAML siguiente, el listview image selector identificará que Image es un elemento secundario de ListViewy establece su alto y ancho en 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>

Nota:

El element element selector no requiere que el elemento secundario sea un elemento secundario directo del elemento primario: el elemento secundario puede tener un elemento primario diferente. La selección se produce siempre que un antecesor sea el primer elemento especificado.

Selección de elementos secundarios directos

Los elementos secundarios directos del árbol visual se pueden seleccionar con el selector sin distinción entre mayúsculas y minúsculas element>element :

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

Este selector identifica los Image elementos que son elementos secundarios directos de StackLayout los elementos y establece su alto y ancho en 200. Por lo tanto, en el ejemplo siguiente, el stacklayout>image selector identificará que Image es un elemento secundario directo de StackLayouty establece su alto y ancho en 200.

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

Nota:

El element>element selector requiere que el elemento secundario sea un elemento secundario directo del elemento primario.

Referencia del selector

Los siguientes selectores CSS son compatibles con .NET MAUI:

Selector Ejemplo Descripción
.class .header Selecciona todos los elementos con la StyleClass propiedad que contiene "header". Este selector distingue mayúsculas de minúsculas.
#id #email Selecciona todos los elementos con StyleId establecido en email. Si StyleId no se establece, reserva en x:Name. Al usar XAML, x:Name se prefiere a StyleId. Este selector distingue mayúsculas de minúsculas.
* * Selecciona todos los elementos.
element label Selecciona todos los elementos de tipo Label, pero no subclases. Este selector no distingue mayúsculas de minúsculas.
^base ^contentpage Selecciona todos los elementos con ContentPage como clase base, incluido ContentPage a sí mismo. Este selector no distingue mayúsculas de minúsculas y no forma parte de la especificación CSS.
element,element label,button Selecciona todos los Button elementos y todos los Label elementos. Este selector no distingue mayúsculas de minúsculas.
element element stacklayout label Selecciona todos los Label elementos dentro de .StackLayout Este selector no distingue mayúsculas de minúsculas.
element>element stacklayout>label Selecciona todos los Label elementos con StackLayout como elemento primario directo. Este selector no distingue mayúsculas de minúsculas.
element+element label+entry Selecciona todos los Entry elementos directamente después de .Label Este selector no distingue mayúsculas de minúsculas.
element~element label~entry Selecciona todos los Entry elementos precedidos de .Label Este selector no distingue mayúsculas de minúsculas.

Los estilos con selectores coincidentes se aplican consecutivamente, en orden de definición. Los estilos definidos en un elemento específico siempre se aplican en último lugar.

Sugerencia

Los selectores se pueden combinar sin limitación, como StackLayout>ContentView>label.email.

No se admiten los siguientes selectores:

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

Nota:

La especificidad y las invalidaciones de especificidad no son compatibles.

Referencia de propiedades

.NET MAUI admite las siguientes propiedades CSS (en la columna Valores , los tipos son cursiva, mientras que los literales de cadena son gray):

Propiedad Se aplica a Valores Ejemplo
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 Color | initial background-color: springgreen;
background-image Page Cadena | initial background-image: bg.png;
border-color Button, Frame, ImageButton Color | initial border-color: #9acd32;
border-radius BoxView, Button, Frame, ImageButton Doble | initial border-radius: 10;
border-width Button, ImageButton Doble | initial border-width: .5;
color ActivityIndicator, BoxView, Button, CheckBox, DatePicker, Editor, Entry, Label, Picker, ProgressBar, SearchBar, Switch, TimePicker Color | initial color: rgba(255, 0, 0, 0.3);
column-gap Grid Doble | 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 float | auto | initial. Además, se puede especificar un porcentaje del intervalo del 0 % al 100 % con el % signo . flex-basis: 25%;
flex-grow VisualElement Flotador | initial flex-grow: 1.5;
flex-shrink VisualElement Flotador | initial flex-shrink: 1;
flex-wrap VisualElement nowrap | wrap | reverse | wrap-reverse | initial flex-wrap: wrap-reverse;
font-family Button, DatePicker, Editor, Entry, Label, Picker, SearchBar, TimePicker, Span Cadena | initial font-family: Consolas;
font-size Button, DatePicker, Editor, Entry, Label, Picker, SearchBar, TimePicker, Span Doble | initial font-size: 12;
font-style Button, DatePicker, Editor, Entry, Label, Picker, SearchBar, TimePicker, Span bold | italic | initial font-style: bold;
height VisualElement Doble | initial min-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 Button, DatePicker, Editor, Entry, Label, Picker, SearchBar, SearchHandler, Span, TimePicker Doble | initial letter-spacing: 2.5;
line-height Label, Span Doble | initial line-height: 1.8;
margin View Grueso | initial margin: 6 12;
margin-left View Grueso | initial margin-left: 3;
margin-top View Grueso | initial margin-top: 2;
margin-right View Grueso | initial margin-right: 1;
margin-bottom View Grueso | initial margin-bottom: 6;
max-lines Label Int | initial max-lines: 2;
min-height VisualElement Doble | initial min-height: 50;
min-width VisualElement Doble | initial min-width: 112;
opacity VisualElement Doble | initial opacity: .3;
order VisualElement Int | initial order: -1;
padding Button, ImageButton, Layout, Page Grueso | initial padding: 6 12 12;
padding-left Button, ImageButton, Layout, Page Doble | initial padding-left: 3;
padding-top Button, ImageButton, Layout, Page Doble | initial padding-top: 4;
padding-right Button, ImageButton, Layout, Page Doble | initial padding-right: 2;
padding-bottom Button, ImageButton, Layout, Page Doble | initial padding-bottom: 6;
position FlexLayout relative | absolute | initial position: absolute;
row-gap Grid Doble | initial row-gap: 12;
text-align Entry, EntryCell, Label, SearchBar left | top | right | bottom | start | center | middle | end | initial. left y right deben evitarse en entornos de derecha a izquierda. text-align: right;
text-decoration Label, Span none | underline | strikethrough | line-through | initial text-decoration: underline, line-through;
text-transform Button,Editor, Entry, Label, SearchBar, SearchHandler none | default | uppercase | lowercase | initial text-transform: uppercase;
transform VisualElement none, rotate, rotateX, rotateY, scale, scaleX, scaleY, translate, translateX, translateY, initial transform: rotate(180), scaleX(2.5);
transform-origin VisualElement double, double | 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 Doble | initial min-width: 320;

Nota:

initial es un valor válido para todas las propiedades. Borra el valor (se restablece de forma predeterminada) que se estableció a partir de otro estilo.

No se admiten las siguientes propiedades:

  • all: initial.
  • Propiedades de diseño (cuadro o cuadrícula).
  • Propiedades abreviadas, como font, y border.

Además, no hay ningún inherit valor y, por tanto, no se admite la herencia. Por lo tanto, no puede, por ejemplo, establecer la font-size propiedad en un diseño y esperar que todas las Label instancias del diseño hereden el valor. La única excepción es la direction propiedad , que tiene un valor predeterminado de inherit.

Importante

Span los elementos no se pueden establecer como destino mediante CSS.

Propiedades específicas de .NET MAUI

También se admiten las siguientes propiedades CSS específicas de .NET MAUI (en la columna Valores , los tipos son cursiva, mientras que los literales de cadena son gray):

Propiedad Se aplica a Valores Ejemplo
-maui-bar-background-color NavigationPage, TabbedPage Color | initial -xf-bar-background-color: teal;
-maui-bar-text-color NavigationPage, TabbedPage Color | initial -xf-bar-text-color: gray
-maui-horizontal-scroll-bar-visibility ScrollView default | always | never | initial -xf-horizontal-scroll-bar-visibility: never;
-maui-max-length Entry, Editor, SearchBar Int | initial -xf-max-length: 20;
-maui-max-track-color Slider Color | initial -xf-max-track-color: red;
-maui-min-track-color Slider Color | initial -xf-min-track-color: yellow;
-maui-orientation ScrollView, StackLayout horizontal | vertical | both | initial. bothsolo se admite en .ScrollView -xf-orientation: horizontal;
-maui-placeholder Entry, Editor, SearchBar texto entre comillas | initial -xf-placeholder: Enter name;
-maui-placeholder-color Entry, Editor, SearchBar Color | initial -xf-placeholder-color: green;
-maui-spacing StackLayout Doble | initial -xf-spacing: 8;
-maui-thumb-color Slider, Switch Color | initial -xf-thumb-color: limegreen;
-maui-vertical-scroll-bar-visibility ScrollView default | always | never | initial -xf-vertical-scroll-bar-visibility: always;
-maui-vertical-text-alignment Label start | center | end | initial -xf-vertical-text-alignment: end;
-maui-visual VisualElement Cadena | initial -xf-visual: material;

Propiedades específicas del shell de .NET MAUI

También se admiten las siguientes propiedades CSS específicas del shell maui de .NET (en la columna Valores , los tipos son cursiva, mientras que los literales de cadena son gray):

Propiedad Se aplica a Valores Ejemplo
-maui-flyout-background Shell Color | initial -xf-flyout-background: red;
-maui-shell-background Element Color | initial -xf-shell-background: green;
-maui-shell-disabled Element Color | initial -xf-shell-disabled: blue;
-maui-shell-foreground Element Color | initial -xf-shell-foreground: yellow;
-maui-shell-tabbar-background Element Color | initial -xf-shell-tabbar-background: white;
-maui-shell-tabbar-disabled Element Color | initial -xf-shell-tabbar-disabled: black;
-maui-shell-tabbar-foreground Element Color | initial -xf-shell-tabbar-foreground: gray;
-maui-shell-tabbar-title Element Color | initial -xf-shell-tabbar-title: lightgray;
-maui-shell-tabbar-unselected Element Color | initial -xf-shell-tabbar-unselected: cyan;
-maui-shell-title Element Color | initial -xf-shell-title: teal;
-maui-shell-unselected Element Color | initial -xf-shell-unselected: limegreen;

Color

Se admiten los siguientes color valores:

  • X11colores, que coinciden con los colores CSS y los colores maui de .NET. Estos valores de color no distinguen mayúsculas de minúsculas.
  • colores hexadecimales: #rgb, #argb, #rrggbb, #aarrggbb
  • colores rgb: rgb(255,0,0), rgb(100%,0%,0%). Los valores están comprendidos entre 0 y 255 o 0%-100%.
  • colores rgba: rgba(255, 0, 0, 0.8), rgba(100%, 0%, 0%, 0.8). El valor de opacidad está en el intervalo 0,0-1,0.
  • Colores hsl: hsl(120, 100%, 50%). El valor h está en el intervalo 0-360, mientras que s y l están en el intervalo 0%-100%.
  • hsla colors: hsla(120, 100%, 50%, .8). El valor de opacidad está en el intervalo 0,0-1,0.

Thickness

Se admiten uno, dos, tres o cuatro thickness valores, cada uno separado por espacios en blanco:

  • Un valor único indica un grosor uniforme.
  • Dos valores indican el grosor vertical y horizontal.
  • Tres valores indican superior y horizontal (izquierda y derecha), después grosor inferior.
  • Cuatro valores indican la parte superior, la derecha, la parte inferior y el grosor izquierdo.

Nota:

Los valores CSS thickness difieren de los valores XAML Thickness . Por ejemplo, en XAML, un valor de dos valores Thickness indica el grosor horizontal y vertical, mientras que un valor Thickness de cuatro valores indica a la izquierda, a continuación, arriba, derecha y después grosor inferior. Además, los valores XAML Thickness están delimitados por comas.

Functions

Los degradados lineales y radiales se pueden especificar mediante las linear-gradient() funciones CSS y radial-gradient() , respectivamente. El resultado de estas funciones debe asignarse a la background propiedad de un control .