Styling Xamarin.Forms apps using Cascading Style Sheets (CSS)

Download Sample Download the sample

Xamarin.Forms supports styling visual elements using Cascading Style Sheets (CSS).

Xamarin.Forms applications can be styled using CSS. A style sheet consists of a list of rules, with each rule consisting of one or more selectors and a declaration block. A declaration block consists of a list of declarations in braces, with each declaration consisting of a property, a colon, and a value. When there are multiple declarations in a block, a semi-colon is inserted as a separator. The following code example shows some Xamarin.Forms compliant CSS:

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

In Xamarin.Forms, CSS style sheets are parsed and evaluated at runtime, rather than compile time, and style sheets are re-parsed on use.

Note

Currently, all of the styling that's possible with XAML styling cannot be performed with CSS. However, XAML styles can be used to supplement CSS for properties that are currently unsupported by Xamarin.Forms. For more information about XAML styles, see Styling Xamarin.Forms Apps using XAML Styles.

The MonkeyAppCSS sample demonstrates using CSS to style a simple app, and is shown in the following screenshots:

MonkeyApp Main Page with CSS styling

MonkeyApp Detail Page with CSS styling

Consuming a style sheet

The process for adding a style sheet to a solution is as follows:

  1. Add an empty CSS file to your .NET Standard library project.
  2. Set the build action of the CSS file to EmbeddedResource.

Loading a style sheet

There are a number of approaches that can be used to load a style sheet.

Note

It's not currently possible to change a style sheet at runtime and have the new style sheet applied.

XAML

A style sheet can be loaded and parsed with the StyleSheet class before being added to a ResourceDictionary:

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

The StyleSheet.Source property specifies the style sheet as a URI relative to the location of the enclosing XAML file, or relative to the project root if the URI starts with a /.

Warning

The CSS file will fail to load if its build action is not set to EmbeddedResource.

Alternatively, a style sheet can be loaded and parsed with the StyleSheet class, before being added to a ResourceDictionary, by inlining it in a CDATA section:

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

For more information about resource dictionaries, see Resource Dictionaries.

C#

In C#, a style sheet can be loaded from a StringReader and added to 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));
        }
    }
}

The argument to the StyleSheet.FromReader method is the TextReader that has read the style sheet.

Selecting elements and applying properties

CSS uses selectors to determine which elements to target. Styles with matching selectors are applied consecutively, in definition order. Styles defined on a specific item are always applied last. For more information about supported selectors, see Selector Reference.

CSS uses properties to style a selected element. Each property has a set of possible values, and some properties can affect any type of element, while others apply to groups of elements. For more information about supported properties, see Property Reference.

Child stylesheets always override parent stylesheets if they set the same properties. Therefore, the following precedence rules are followed when applying styles that set the same properties:

  • A style defined in the application resources will be overwritten by a style defined in the page resources, if they set the same properties.
  • A style defined in page resources will be overwritten by a style defined in the control resources, if they set the same properties.
  • A style defined in the application resources will be overwritten by a style defined in the control resources, if they set the same properties.

Important

CSS variables are unsupported.

Selecting elements by type

Elements in the visual tree can be selected by type with the case insensitive element selector:

stacklayout {
    margin: 20;
}

This selector identifies any StackLayout elements on pages that consume the style sheet, and sets their margins to a uniform thickness of 20.

Note

The element selector does not identify subclasses of the specified type.

Selecting elements by base class

Elements in the visual tree can be selected by base class with the case insensitive ^base selector:

^contentpage {
    background-color: lightgray;
}

This selector identifies any ContentPage elements that consume the style sheet, and sets their background color to lightgray.

Note

The ^base selector is specific to Xamarin.Forms, and isn't part of the CSS specification.

Selecting an element by name

Individual elements in the visual tree can be selected with the case sensitive #id selector:

#listView {
    background-color: lightgray;
}

This selector identifies the element whose StyleId property is set to listView. However, if the StyleId property is not set, the selector will fall back to using the x:Name of the element. Therefore, in the following XAML example, the #listView selector will identify the ListView whose x:Name attribute is set to listView, and will set it's background color to lightgray.

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

Selecting elements with a specific class attribute

Elements with a specific class attribute can be selected with the case sensitive .class selector:

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

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

A CSS class can be assigned to a XAML element by setting the StyleClass property of the element to the CSS class name. Therefore, in the following XAML example, the styles defined by the .detailPageTitle class are assigned to the first Label, while the styles defined by the .detailPageSubtitle class are assigned to the second Label.

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

Selecting child elements

Child elements in the visual tree can be selected with the case insensitive element element selector:

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

This selector identifies any Image elements that are children of ListView elements, and sets their height and width to 60. Therefore, in the following XAML example, the listview image selector will identify the Image that's a child of the ListView, and sets its height and width to 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>

Note

The element element selector does not require the child element to be a direct child of the parent – the child element may have a different parent. Selection occurs provided that an ancestor is the specified first element.

Selecting direct child elements

Direct child elements in the visual tree can be selected with the case insensitive element>element selector:

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

This selector identifies any Image elements that are direct children of StackLayout elements, and sets their height and width to 200. Therefore, in the following XAML example, the stacklayout>image selector will identify the Image that's a direct child of the StackLayout, and sets its height and width to 200.

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

Note

The element>element selector requires that the child element is a direct child of the parent.

Selector reference

The following CSS selectors are supported by Xamarin.Forms:

Selector Example Description
.class .header Selects all elements with the StyleClass property containing 'header'. Note that this selector is case sensitive.
#id #email Selects all elements with StyleId set to email. If StyleId is not set, fallback to x:Name. When using XAML, x:Name is preferred over StyleId. Note that this selector is case sensitive.
* * Selects all elements.
element label Selects all elements of type Label, but not subclasses. Note that this selector is case insensitive.
^base ^contentpage Selects all elements with ContentPage as the base class, including ContentPage itself. Note that this selector is case insensitive and isn't part of the CSS specification.
element,element label,button Selects all Button elements and all Label elements. Note that this selector is case insensitive.
element element stacklayout label Selects all Label elements inside a StackLayout. Note that this selector is case insensitive.
element>element stacklayout>label Selects all Label elements with StackLayout as a direct parent. Note that this selector is case insensitive.
element+element label+entry Selects all Entry elements directly after a Label. Note that this selector is case insensitive.
element~element label~entry Selects all Entry elements preceded by a Label. Note that this selector is case insensitive.

Styles with matching selectors are applied consecutively, in definition order. Styles defined on a specific item are always applied last.

Tip

Selectors can be combined without limitation, such as StackLayout>ContentView>label.email.

The following selectors are currently unsupported:

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

Note

Specificity, and specificity overrides are unsupported.

Property reference

The following CSS properties are supported by Xamarin.Forms (in the Values column, types are italic, while string literals are gray):

Property Applies to Values Example
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. In addition, a percentage in the range 0% to 100% can be specified with the % sign. 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 thickness | initial margin: 6 12;
margin-left View thickness | initial margin-left: 3;
margin-top View thickness | initial margin-top: 2;
margin-right View thickness | initial margin-right: 1;
margin-bottom View thickness | 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 thickness | 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 and right should be avoided in right-to-left environments. 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;

Note

initial is a valid value for all properties. It clears the value (resets to default) that was set from another style.

The following properties are currently unsupported:

  • all: initial.
  • Layout properties (box, or grid).
  • Shorthand properties, such as font, and border.

In addition, there's no inherit value and so inheritance isn't supported. Therefore you can't, for example, set the font-size property on a layout and expect all the Label instances in the layout to inherit the value. The one exception is the direction property, which has a default value of inherit.

Targeting Span elements has a known issue preventing spans from being the target of CSS styles by both element and name (using the # symbol). The Span element derives from GestureElement, which does not have the StyleClass property so spans do not support CSS class targeting. For more information, see Not able to apply CSS styling to Span control.

Xamarin.Forms specific properties

The following Xamarin.Forms specific CSS properties are also supported (in the Values column, types are italic, while string literals are gray):

Property Applies to Values Example
-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 is only supported on a 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;

Xamarin.Forms Shell specific properties

The following Xamarin.Forms Shell specific CSS properties are also supported (in the Values column, types are italic, while string literals are gray):

Property Applies to Values Example
-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

The following color values are supported:

  • X11 colors, which match CSS colors, UWP pre-defined colors, and Xamarin.Forms colors. Note that these color values are case insensitive.
  • hex colors: #rgb, #argb, #rrggbb, #aarrggbb
  • rgb colors: rgb(255,0,0), rgb(100%,0%,0%). Values are in the range 0-255, or 0%-100%.
  • rgba colors: rgba(255, 0, 0, 0.8), rgba(100%, 0%, 0%, 0.8). The opacity value is in the range 0.0-1.0.
  • hsl colors: hsl(120, 100%, 50%). The h value is in the range 0-360, while s and l are in the range 0%-100%.
  • hsla colors: hsla(120, 100%, 50%, .8). The opacity value is in the range 0.0-1.0.

Thickness

One, two, three, or four thickness values are supported, each separated by white space:

  • A single value indicates uniform thickness.
  • Two values indicate vertical then horizontal thickness.
  • Three values indicate top, then horizontal (left and right), then bottom thickness.
  • Four values indicate top, then right, then bottom, then left thickness.

Note

CSS thickness values differ from XAML Thickness values. For example, in XAML a two-value Thickness indicates horizontal then vertical thickness, while a four-value Thickness indicates left, then top, then right, then bottom thickness. In addition, XAML Thickness values are comma delimited.

NamedSize

The following case insensitive namedsize values are supported:

  • default
  • micro
  • small
  • medium
  • large

The exact meaning of each namedsize value is platform-dependent and view-dependent.

Functions

Linear and radial gradients can be specified using the linear-gradient() and radial-gradient() CSS functions, respectively. The result of these functions should be assigned to the background property of a control.

CSS in Xamarin.Forms with Xamarin.University

Xamarin.Forms 3.0 CSS video