Aplicar estilos a aplicaciones Xamarin.Forms mediante hojas de estilo CSS

Download SampleDescargar el ejemplo

Xamarin.Forms también admite aplicar estilo a los elementos visuales mediante hojas de estilo CSS.

Se puede aplicar estilo a aplicaciones Xamarin.Forms mediante CSS. Una hoja de estilos consta de una lista de reglas, con cada regla formada por 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 formada por 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 de código siguiente se muestran algunos CSS compatibles con Xamarin.Forms:

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

^contentpage {
    background-color: lightgray;
}

#listView {
    background-color: lightgray;
}

stacklayout {
    margin: 20;
}

.mainPageTitle {
    font-style: bold;
    font-size: medium;
}

.mainPageSubtitle {
    margin-top: 15;
}

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

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

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

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

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

Nota:

Actualmente, toda la aplicación de estilo que es posible con la aplicación de estilo XAML no se puede realizar con CSS. Sin embargo, los estilos XAML se pueden usar para complementar CSS para las propiedades que actualmente no son compatibles con Xamarin.Forms. Para obtener más información sobre los estilos XAML, vea Aplicación de estilo a aplicaciones Xamarin.Forms con estilos XAML.

El ejemplo MonkeyAppCSS muestra el uso de CSS para aplicar estilo a una aplicación sencilla y se muestra en las capturas de pantalla siguientes:

MonkeyApp Main Page with CSS styling

MonkeyApp Detail Page with CSS styling

Consumo de una hoja de estilo

El proceso para agregar una hoja de estilo a una solución es el siguiente:

  1. Agregue un archivo CSS vacío al proyecto de biblioteca de .NET Standard.
  2. Establezca la acción de compilación del archivo CSS en EmbeddedResource.

Carga de una hoja de estilos

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

Nota:

Actualmente no es posible cambiar una hoja de estilo en runtime y aplicar la nueva hoja de estilo.

XAML

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

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

La propiedad StyleSheet.Source 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 empieza por /.

Advertencia

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

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

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

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

C#

En C#, se puede cargar una hoja de estilos desde StringReader y agregarse a ResourceDictionary:

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 para el método StyleSheet.FromReader es TextReader que ha leído la hoja de estilos.

Selección de elementos y aplicación de propiedades

CSS usa selectores para determinar a qué elementos va dirigido. 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. 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:

  • Si se establecen las mismas propiedades, el estilo definido en los recursos de la aplicación se sobrescribirá mediante un estilo definido en los recursos de la página.
  • 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.
  • Si se establecen las mismas propiedades, el estilo definido en los recursos de la aplicación se sobrescribirá mediante un estilo definido en los recursos de control.

Importante

No se admiten variables CSS.

Selección de elementos por tipo

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

stacklayout {
    margin: 20;
}

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

Nota:

El selector element no identifica las 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 ^base sin distinción entre mayúsculas y minúsculas:

^contentpage {
    background-color: lightgray;
}

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

Nota:

El selector ^base es específico de Xamarin.Forms, 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 #id sin distinción entre mayúsculas y minúsculas:

#listView {
    background-color: lightgray;
}

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

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

Selección de elementos con un atributo de clase específico

Los elementos con un atributo de clase específico se pueden seleccionar con el selector .class sin distinción entre mayúsculas y mayúsculas:

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

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

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

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

Selección de elementos secundarios

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

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

Este selector identifica los elementos secundarios Image de los elementos ListView y establece su alto y ancho en 60. Por lo tanto, en el ejemplo de XAML siguiente, el selector listview image identificará que Image es un elemento secundario de ListView y establece su alto y ancho en 60.

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

Nota:

El selector element element 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 element>element sin distinción entre mayúsculas y minúsculas:

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

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

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

Nota:

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

Referencia del selector

Los siguientes selectores CSS son compatibles con Xamarin.Forms:

Selector Ejemplo Descripción
.class .header Selecciona todos los elementos con la propiedad StyleClass que contiene "header". Tenga en cuenta que este selector distingue mayúsculas de minúsculas.
#id #email Selecciona todos los elementos con StyleId establecido en email. Si StyleId no se establece, se usará x:Name. Al usar XAML, x:Name es preferible a StyleId. Tenga en cuenta que este selector distingue mayúsculas de minúsculas.
* * Selecciona todos los elementos.
element label Selecciona todos los elementos de tipo Label, pero no subclases. Tenga en cuenta que este selector no distingue mayúsculas de minúsculas.
^base ^contentpage Selecciona todos los elementos con ContentPage como clase base, incluido el propio elemento ContentPage. Tenga en cuenta que 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 elementos Button y todos los elementos Label. Tenga en cuenta que este selector no distingue mayúsculas de minúsculas.
element element stacklayout label Selecciona todos los elementos Label dentro de StackLayout. Tenga en cuenta que este selector no distingue mayúsculas de minúsculas.
element>element stacklayout>label Selecciona todos los elementos Label con StackLayout como elemento primario directo. Tenga en cuenta que este selector no distingue mayúsculas de minúsculas.
element+element label+entry Selecciona todos los elementos Entry directamente después de Label. Tenga en cuenta que este selector no distingue mayúsculas de minúsculas.
element~element label~entry Selecciona todos los elementos Entry precedidos de Label. Tenga en cuenta que 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.

Actualmente no se admiten los siguientes selectores:

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

Nota:

No se admiten la especificidad ni la anulación de especificidad.

Referencia de propiedades

Las siguientes propiedades CSS son compatibles con Xamarin.Forms (en la columna Valores, los tipos van en cursiva, mientras que los literales de cadena van en 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 string | initial background-image: bg.png;
border-color Button, Frame, ImageButton color | initial border-color: #9acd32;
border-radius BoxView, Button, Frame, ImageButton double | initial border-radius: 10;
border-width Button, ImageButton double | 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 double | 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 rango del 0 % al 100 % con el signo %. flex-basis: 25%;
flex-grow VisualElement float | initial flex-grow: 1.5;
flex-shrink VisualElement float | 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 string | initial font-family: Consolas;
font-size Button, DatePicker, Editor, Entry, Label, Picker, SearchBar, TimePicker, Span double | namedsize | initial font-size: 12;
font-style Button, DatePicker, Editor, Entry, Label, Picker, SearchBar, TimePicker, Span bold | italic | initial font-style: bold;
height VisualElement double | 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 double | initial letter-spacing: 2.5;
line-height Label, Span double | initial line-height: 1.8;
margin View grosor | initial margin: 6 12;
margin-left View grosor | initial margin-left: 3;
margin-top View grosor | initial margin-top: 2;
margin-right View grosor | initial margin-right: 1;
margin-bottom View grosor | initial margin-bottom: 6;
max-lines Label int | initial max-lines: 2;
min-height VisualElement double | initial min-height: 50;
min-width VisualElement double | initial min-width: 112;
opacity VisualElement double | initial opacity: .3;
order VisualElement int | initial order: -1;
padding Button, ImageButton, Layout, Page grosor | initial padding: 6 12 12;
padding-left Button, ImageButton, Layout, Page double | initial padding-left: 3;
padding-top Button, ImageButton, Layout, Page double | initial padding-top: 4;
padding-right Button, ImageButton, Layout, Page double | initial padding-right: 2;
padding-bottom Button, ImageButton, Layout, Page double | initial padding-bottom: 6;
position FlexLayout relative | absolute | initial position: absolute;
row-gap Grid double | 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 double | initial min-width: 320;

Nota:

initial es un valor válido para todas las propiedades. Borra el valor (se restablece al valor predeterminado) que se estableció desde otro estilo.

Actualmente 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 valor inherit y, por tanto, no se admite la herencia. Por lo tanto, no puedes, por ejemplo, establecer la propiedad font-size en un diseño y esperar que todas las instancias Label del diseño hereden el valor. La única excepción es la propiedad direction, que tiene un valor predeterminado de inherit.

Los elementos de destino Span tienen un problema conocido que impide que los intervalos sean el destino de los estilos CSS por elemento y nombre (mediante el símbolo #). El elemento Span deriva de GestureElement, que no tiene la propiedad StyleClass, por lo que los intervalos no admiten el destino de la clase CSS. Para obtener más información, consulte No se puede aplicar el estilo CSS al control Span.

Propiedades específicas de Xamarin.Forms

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

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

Propiedades específicas de Shell Xamarin.Forms

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

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

Color

Se admiten los valores color siguientes:

  • X11colores, que coinciden con colores CSS, colores predefinidos de UWP y colores Xamarin.Forms. Tenga en cuenta que 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 válidos están en el rango entre 0 y 255 o entre 0 % y 100 %.
  • colores rgba: rgba(255, 0, 0, 0.8), rgba(100%, 0%, 0%, 0.8). El valor de opacidad está en el rango 0,0-1,0.
  • Colores hsl: hsl(120, 100%, 50%). El valor h está en el rango entre 0 y 360, mientras que s y l están en el rango entre 0% y 100%.
  • colores hsla: hsla(120, 100%, 50%, .8). El valor de opacidad está en el rango 0,0-1,0.

Thickness

Se admiten uno, dos, tres o cuatro valores thickness, 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 el grosor superior, después horizontal (izquierda y derecha), después inferior.
  • Cuatro valores indican el grosor superior, después derecho, inferior e izquierdo.

Nota:

Los valores thickness CSS difieren de los valores Thickness XAML. Por ejemplo, en XAML, un valor Thickness de dos indica el grosor horizontal y vertical, mientras que un valor Thickness de cuatro indica el grosor izquierdo, después superior, derecho e inferior. Además, los valores Thickness XAML están delimitados por comas.

NamedSize

Se admiten los siguientes valores namedsize que no distinguen mayúsculas de minúsculas :

  • default
  • micro
  • small
  • medium
  • large

El significado exacto de cada valor namedsize es dependiente de la plataforma y de la vista.

Funciones

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

CSS en Xamarin.Forms con Xamarin.University

Xamarin.Forms Vídeo CSS 3.0