Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stylesheets #1207

Merged
merged 3 commits into from Dec 20, 2017
Merged

Stylesheets #1207

merged 3 commits into from Dec 20, 2017

Conversation

StephaneDelcroix
Copy link
Member

@StephaneDelcroix StephaneDelcroix commented Oct 18, 2017

Description of Change

Support cascading StyleSheets.
Support all selector (no media selectors)

Preliminary note

This code and feature is brand new. The API shouldn't change much, but some of the behaviors might be slightly altered in the future, depending on the feedback received.

Supported Selectors

Selector Example Description
.class .header Selects all elements with the StyleClass property containing 'header'
#id #email Selects all elements with StyleId set to email. If StyleId is not set, fallback to x:Name. When using Xaml, always prefer x:Name over StyleId.
* * Selects all elements
element label Selects all elements of type Label (but not subclasses). Case irrelevant.
^base ^contentpage Selects all elements with ContentPage as base class, including ContentPage itself. Case irrelevant. This selector isn't present in the CSS specification, and only applies to XF.
element,element label,button Selects all Buttons and all Labels
element element stacklayout label Selects all Labels inside of a StackLayout
element>element stacklayout>label Selects all Labels with StackLayout as a direct parent
element+element label+entry Selects all Entries directly after a Label
element~element label~entry Selects all Entries preceded by a Label

Unsupported Selectors (for this version)

  • [attribute] selectors
  • @media or @supportsselectors
  • : or :: selectors

Selector combinations

Selectors can be combined without limitation, like in StackLayout > ContentView > label.email. But keep it sane !

Precedence

Styles with matching selectors are all applied, one by one, in definition order. Styles defined on the item itself is always applied last.

This is the expected behavior in most cases, even if doesn't 100% match common CSS implementations.

Specificity, and specificity overrides (!important) are not supported. This is a known issue.

Supported properties

Property Applies to Values (string literals are grayed, while types are italic) Example
background-color VisualElement color (see Colors) | initial background-color: springgreen;
background-image Page string | initial background-image: bg.png;
border-color Button, Frame color (see Colors) | initial border-color: #9acd32;
border-width Button double | initial border-width: .5;
color Button, DatePicker, Editor, Entry, Label, Picker, SearchBar, TimePicker color (see Colors) | initial color: rgba(255, 0, 0, 0.3);
direction VisualElement ltr | rtl | inherit, initial direction: rtl;
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 (see 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;
margin View thickness (see Thickness) | initial margin: 6 12;
margin-left View thickness (see Thickness) | initial margin-left: 3;
margin-top View thickness (see Thickness) | initial margin-top: 2;
margin-right View thickness (see Thickness) | initial margin-right: 1;
margin-bottom View thickness (see Thickness) | initial margin-bottom: 6;
min-height VisualElement double | initial `min-height: 50;
min-width VisualElement double | initial `min-width: 112;
opacity VisualElement double | initial opacity: .3;
padding Layout, Page thickness (see Thickness) | initial padding: 6 12 12;
padding-left Layout, Page double | initial padding-left: 3;
padding-top Layout, Page double | initial padding-top: 4;
padding-right Layout, Page double | initial padding-right: 2;
padding-bottom Layout, Page double | initial padding-bottom: 6;
text-align Entry, EntryCell, Label, SearchBar left | right | center | start | end | initial . It is recommended to avoid left and right in non-ltr environments text-align: right;
visibility VisualElement true | visible | false | hidden | collapse | initial visibility: hidden;
width VisualElement double | initial `min-width: 320;

Unsupported Common Properties

  • all: initial,
  • layout properties (box, or grid). FlexLayout is coming, and it'll be CSS stylable,
  • shorthand properties, like font, border

Colors

  • one of the 140 X11 color (https://en.wikipedia.org/wiki/X11_color_names), which happens to match CSS Colors, UWP predefined colors and XF Colors. Case insensitive
  • HEX: #rgb, #argb, #rrggbb, #aarrggbb
  • RGB: rgb(255,0,0), rgb(100%,0%,0%) => values in range 0-255 or 0%-100%
  • RGBA: rgba(255, 0, 0, 0.8), rgba(100%, 0%, 0%, 0.8) => opacity is 0.0-1.0
  • HSL: hsl(120, 100%, 50%) => h is 0-360, s and l are 0%-100%
  • HSLA: hsla(120, 100%, 50%, .8) => opacity is 0.0-1.0

Thickness

One, two, three or four values, separated by white spaces.

  • a single value indicates uniform thickness
  • two values indicates (resp.) vertical and horizontal thickness
  • three values indicates (resp.) top, horizontal (left and right) and bottom thickness
  • when using four values, they are top, right, bottom, left

IMPORTANT: This differs from Xaml thickness definitions, which are

  1. separated by commas (,),
  2. are in the form of uniform, horizontal, vertical or left, top, right, bottom.

NamedSize

One of the following value, case insensitive. Exact meaning depends of the platform and the control

  • default,
  • micro,
  • small,
  • medium,
  • large

Initial

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

Additional remarks

  • no inheritance supported, meaning no inherit value and that you can't set the font-size to a layout, and expect all the labels in that layout to inherit the value. The only exception is the direction property, which supports inherit, and that's the default value.
  • element are matched by name, no support for xmlns

Usage

XAML (preferred)
<ContentPage x:Class="...">
  <ContentPage.Resources>
    <StyleSheet Source="appresources/style.css" />
  </ContentPage.Resources>
</ContentPage>

the Source argument takes an Uri relative to the current xaml control, or relative to the application root if it starts with a /. The style.css has to be an EmbeddedResource.

alternatively, you can inline your style in a CDATA Section

<ContentPage x:Class="...">
  <ContentPage.Resources>
    <StyleSheet>
<![CDATA[
^contentpage {
    background-color: orange;
    padding: 20;
}

stacklayout > * {
    margin: 3;
}
]]>
    </StyleSheet>
  </ContentPage.Resources>
</ContentPage>

do not abuse of that second syntax.

in C#

From an embedded resource:

myPage.Resources.Add(StyleSheet.FromAssemblyResource(this.GetType().Assembly, "resource.id.of.the.css"));

or from a TextReader:

using (var reader = new StringReader(my_css_string))
    myPage.Resources.Add(StyleSheet.FromReader(reader));

StyleSheet, XamlC and other potential optimizations

At this time, CSS StyleSheets are parsed and evaluated at runtime. That aren't compiled. Every time a StyleSheet is used, it's reparsed again. If parsing time is an issue, enabling caching is trivial, but comes at memory cost.

Bugs Fixed

None. but It'll introduce some new ones

API Changes

Added

Not that much new API...

namespace Xamarin.Forms.StyleSheets{
    public sealed class StyleSheet {
        public static StyleSheet FromAssemblyResource(Assembly assembly, string resourceId, IXmlLineInfo lineInfo = null);
        public static StyleSheet FromReader(TextReader reader);
    }
}
namespace Xamarin.Forms {
    public class ResourceDictionary {
        void Add(StyleSheet);
    }

    public class Frame {
        public static readonly BindableProperty BorderColorProperty;
        public Color BorderColor { get; set; }
    }
}

Obsoleted

Frame.OutlineColor { get; set; }
Frame.OutlineColorProperty;

Behavioral Changes

/

PR Checklist

  • Has tests (if omitted, state reason in description)
  • Rebased on top of master at time of PR
  • Changes adhere to coding standard
  • Consolidate commits as makes sense

@StephaneDelcroix StephaneDelcroix added the DO-NOT-MERGE-!!! 🛑 This is in progress and needs to be updated before it can be merged. label Oct 18, 2017
</CoreCompileDependsOn>
</PropertyGroup>

<Target Name="CssG">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the new CssG task is responsible for creating XamlResourceIdAttributes for Css file


[assembly: StyleProperty("color", typeof(ITextElement), nameof(TextElement.TextColorProperty))]
[assembly: StyleProperty("background-color", typeof(VisualElement), nameof(VisualElement.BackgroundColorProperty))]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the mapping table to be completed, matching css property names to XF properties

propertyChanged: (bp, o, n) => ((VisualElement)bp).OnStyleSheetChanged((StyleSheet)o, (StyleSheet)n));

[TypeConverter(typeof(StyleSheetConverter))]
public StyleSheet StyleSheet {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no actual public way to create a StyleSheet, so this expects a string uri in Xaml and the StyleSheet will be generated

@StephaneDelcroix StephaneDelcroix removed the DO-NOT-MERGE-!!! 🛑 This is in progress and needs to be updated before it can be merged. label Nov 3, 2017
[assembly: StyleProperty("border-width", typeof(Button), nameof(Button.BorderWidth))]
[assembly: StyleProperty("color", typeof(ITextElement), nameof(TextElement.TextColorProperty))]
//[assembly:StyleProperty("direction", .., ..)]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@samhouts your help is needed here

</CoreCompileDependsOn>
</PropertyGroup>

<Target Name="CssG">
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change it to BeforeTarget="BeforeCompile" and remove the property group

[TestCase("page>stacklayout>contentview>label", false, false, true, false, false, false)]
[TestCase("visualelement", false, false, false, false, false, false)]
[TestCase("^visualelement", true, true, true, true, true, true)]
[TestCase("^layout", false, false, false, false, false, true)]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is how me make CSS support language with inheritance

@@ -1156,6 +1156,9 @@ static bool CanAddToResourceDictionary(TypeReference collectionType, IElementNod
if (node.XmlType.Name == "ResourceDictionary")
return true;

if (node.XmlType.Name == "StyleSheet")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace those 3 checks by a single reflection based one (see AddToRD below)

v3.1.0 automation moved this from In Review to Done Dec 20, 2017
@StephaneDelcroix StephaneDelcroix deleted the StyleSheet branch December 20, 2017 09:47
jsuarezruiz added a commit to jsuarezruiz/Xamarin.Forms that referenced this pull request Dec 21, 2017
* 'master' of https://github.com/xamarin/Xamarin.Forms: (53 commits)
  Add implicit color conversion to .NET Standard's System.Drawing.Color (xamarin#1359)
  [WPF, GTK, TIZEN] Replace obsolete OutlineColor by BorderColor (xamarin#1443)
  Stylesheets (xamarin#1207)
  [WPF] Add Deserializer implementation (xamarin#1411)
  [Build]Update provisioning submodule
  [Build] Update provisioning
  [UWP] Optimized ZIndexing for a thirty-nine percent speed boot on loa… (xamarin#1196)
  [Xaml] execute XamlG and XamlC on UWP SAP (xamarin#1391)
  [iOS] Update status bar color while page is appearing (xamarin#1288)
  Add condition SdkInt >= JellyBeanMr1 for set flow direction (xamarin#1388)
  Use GlobalAssemblyInfo on tizen backend (xamarin#1397)
  [Build] Bump to 15.5.2
  revert part of xamarin#1370. keep the test project out of netstandard for now (xamarin#1402)
  fix typo in csproj
  Fix for netstandard projects (xamarin#1382)
  [Xaml] open the api for loading xaml from string (xamarin#1394)
  [Android] Prevent a custom Entry/Editor Drawable from modifying non-custom ones (xamarin#1197)
  [build] force build on vs2015
  Add Xamarin.Forms.ControlGallery.Tizen project (xamarin#1389)
  Move XF.Build.Tasks to nestandard2.0 (xamarin#1370)
  ...
{
public static readonly BindableProperty OutlineColorProperty = BindableProperty.Create("OutlineColor", typeof(Color), typeof(Frame), Color.Default);
[Obsolete("OutlineColorProperty is obsolete as of version 3.0.0. Please use BorderColorProperty instead.")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this change caused #1566

@samhouts samhouts added API-change Heads-up to reviewers that this PR may contain an API change breaking Changes behavior or appearance deprecation Public API has been deprecated and removed breaking Changes behavior or appearance labels Apr 2, 2018
@ali-h2010
Copy link

ali-h2010 commented Apr 17, 2018

I am not sure if someone already asked about this before but if someone did, please guide me to the answer.

How to add different CSS for tablets like the iPad or android tablets in general?
Currently , if you run the app in a big screen device , everything will be stretched and most of the time will not be acceptable in a professional environment.

so, I had to do many steps to solve this issue such as:

  • bind the padding values and width of some views
  • use this condition checking to check if device is a phone or tablet

`if (Device.Idiom == TargetIdiom.Phone)
{
HomeIconWidth = 70;
HomeIconHeight = 70;

            HomeIconFrameWidth = 160;
            HomeIconFrameHeight = 160;

            NumberOfApprovalsLayout = new Rectangle(120, 10, 30, 30);
        }
        else
        {
            HomeIconWidth = 110;
            HomeIconHeight = 110;

            HomeIconFrameWidth = 200;
            HomeIconFrameHeight = 200;

            NumberOfApprovalsLayout = new Rectangle(160, 10, 30, 30);
        }`

As you can see it's a lot of variables and conditions to set for every page.
Even if I use styles , I couldn't find a way to check the display in Xaml and apply the correct style.

Is this issue still there or does CSS provide a solution to that?
if there is a solution ,from the look of it it won't be like the web development CSS since @media is not supported like the one that bootstrap uses.

UPDATE:

NeverMind that long post
I found this:

<StackLayout.Orientation> <OnIdiom x:TypeArguments="StackOrientation"> <OnIdiom.Phone>Vertical</OnIdiom.Phone> <OnIdiom.Tablet>Horizontal</OnIdiom.Tablet> </OnIdiom> </StackLayout.Orientation>

@samhouts samhouts added this to the 3.0.0 milestone May 5, 2018
@samhouts samhouts removed this from Done in v3.1.0 May 8, 2018
@mmacneil
Copy link

mmacneil commented May 11, 2018

Can styles on an element be changed at runtime? They are applied as expected on initial load but I seem unable to dynamically change them at runtime based on some event. For example, in a page code-behind this scenario:

void ButtonClick() { myPage.MyCoolLabel.StyleClass = new List<string> { "someNewStyle" }; }

This has no effect, and does not update MyCoolLabel with new styling.

@StephaneDelcroix
Copy link
Member Author

StephaneDelcroix commented May 11, 2018

@mmacneil please open an issue, we will discuss that over there

@mmacneil
Copy link

Done: 2678

Thanks Stephane

@samhouts samhouts modified the milestones: 3.0.0, 2.3.0 Jun 27, 2018
@shivendramca10
Copy link

Will width work in percentage.

@samhouts samhouts modified the milestones: 3.0.0, 2.5.0 Aug 23, 2019
@samhouts samhouts modified the milestones: 3.0.0, 2.5.0 Oct 29, 2019
mattleibow pushed a commit that referenced this pull request Jan 28, 2021
* try to do a type of to see if this fixes it

* Update TextToSpeech.ios.tvos.watchos.cs

* Update TextToSpeech.ios.tvos.watchos.cs

* Fix formatting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a/CSS API-change Heads-up to reviewers that this PR may contain an API change deprecation Public API has been deprecated t/enhancement ➕
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants