microsoft / xaml-standard

XAML Standard : a set of principles that drive XAML dialect alignment
Other
804 stars 50 forks source link

Proposal CSS inline style linking and or in separate file #99

Open insinfo opened 7 years ago

insinfo commented 7 years ago

CSS inline style linking and or in separate file

Instead:

 <link rel="stylesheet" type="text/css" href="theme.css">

Can be it:

<StyleSheet URI="../theme.css"/>

<Window or Page...>
    <Stylesheet URI="../theme.css"/>
    <Button FontWeight="Bold">
        <WrapPanel>
            <TextBlock Foreground="Blue">Multi</TextBlock>
            <TextBlock Foreground="Red">Color</TextBlock>
            <TextBlock>Button</TextBlock>
         </WrapPanel>
     </Button>
</Window or Page...>

Or XAML

<ContentPage StyleSheet="page.css">
    <StackLayout>
        <Label Text="Foo" StyleClass="test" />
        <Label Text="Bar" />
        <ContentView>
            <Label Text="Baz" StyleClass="test" />
        </ContentView>
    </StackLayout>
</ContentPage>

CSS

label {
    background-color: green;
    font-size: 12pt;
}

label.test {
    background-color: yellow;
    color: grey;
}

StackLayout>label.test {
    background-color: purple;
}

https://forums.xamarin.com/discussion/88452/css-styling-and-flexbox/p1

mossyblog commented 7 years ago

Which CSS? and moving back towards a JSON style syntax (which is essentially how CSS and JSON keep the peace) is problematic for platform/tooling implementation(s). As with duck typing syntax you're always in need of a rules dictionary to support it and that would effectively move outside the XAML scope would it not?

insinfo commented 7 years ago

@mossyblog What I wanted to say is that sometimes you have a control that has certain properties and you want to change the values in a simple and fast way, then in this case I enter CSS, that is, it is faster to type a theme or Style in CSS than in XAML

In other words, if XAML supports CSS binding as it does in HTML, it would be much easier to create themes and styles for ready-made applications

The pepiline would look like this C# (Logic) XAML (UI Structure) CSS (UI Style and Theme)

For example, see the amount of thing in XAML and the difficulty of reading, already in the CSS reading is much easier and much less typing:

<!-- Default style for Windows.UI.Xaml.Controls.Button -->
<Style TargetType="Button">
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
<Setter Property="Foreground" Value="{ThemeResource SystemControlForegroundBaseHighBrush}"/>
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundTransparentBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}" />
<Setter Property="Padding" Value="8,4,8,4" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="Template">
  <Setter.Value>
    <ControlTemplate TargetType="Button">
      <Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
        <VisualStateManager.VisualStateGroups>
          <VisualStateGroup x:Name="CommonStates">
            <VisualState x:Name="Normal">
              <Storyboard>
                <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
              </Storyboard>
            </VisualState>
            <VisualState x:Name="PointerOver">
              <Storyboard>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                   Storyboard.TargetProperty="BorderBrush">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseMediumLowBrush}" />
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                   Storyboard.TargetProperty="Foreground">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                </ObjectAnimationUsingKeyFrames>
                <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
              </Storyboard>
            </VisualState>
            <VisualState x:Name="Pressed">
              <Storyboard>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid"
                                                   Storyboard.TargetProperty="Background">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseMediumLowBrush}" />
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                   Storyboard.TargetProperty="BorderBrush">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightTransparentBrush}" />
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                   Storyboard.TargetProperty="Foreground">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlHighlightBaseHighBrush}" />
                </ObjectAnimationUsingKeyFrames>
                <PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
              </Storyboard>
            </VisualState>
            <VisualState x:Name="Disabled">
              <Storyboard>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid"
                                                   Storyboard.TargetProperty="Background">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlBackgroundBaseLowBrush}" />
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                   Storyboard.TargetProperty="Foreground">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledBaseMediumLowBrush}" />
                </ObjectAnimationUsingKeyFrames>
                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                   Storyboard.TargetProperty="BorderBrush">
                  <DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource SystemControlDisabledTransparentBrush}" />
                </ObjectAnimationUsingKeyFrames>
              </Storyboard>
            </VisualState>
          </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <ContentPresenter x:Name="ContentPresenter"
                          BorderBrush="{TemplateBinding BorderBrush}"
                          BorderThickness="{TemplateBinding BorderThickness}"
                          Content="{TemplateBinding Content}"
                          ContentTransitions="{TemplateBinding ContentTransitions}"
                          ContentTemplate="{TemplateBinding ContentTemplate}"
                          Padding="{TemplateBinding Padding}"
                          HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                          VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                          AutomationProperties.AccessibilityView="Raw"/>
      </Grid>
    </ControlTemplate>
  </Setter.Value>
</Setter>
</Style>
body
{
    padding: 50px;
}

.animate
{
    transition: all 0.1s;
    -webkit-transition: all 0.1s;
}

.action-button
{
    position: relative;
    padding: 10px 40px;
  margin: 0px 10px 10px 0px;
  float: left;
    border-radius: 10px;
    font-family: 'Pacifico', cursive;
    font-size: 25px;
    color: #FFF;
    text-decoration: none;  
}

.blue
{
    background-color: #3498DB;
    border-bottom: 5px solid #2980B9;
    text-shadow: 0px -2px #2980B9;
}

.red
{
    background-color: #E74C3C;
    border-bottom: 5px solid #BD3E31;
    text-shadow: 0px -2px #BD3E31;
}

.green
{
    background-color: #82BF56;
    border-bottom: 5px solid #669644;
    text-shadow: 0px -2px #669644;
}

.yellow
{
    background-color: #F2CF66;
    border-bottom: 5px solid #D1B358;
    text-shadow: 0px -2px #D1B358;
}

.action-button:active
{
    transform: translate(0px,5px);
  -webkit-transform: translate(0px,5px);
    border-bottom: 1px solid;
}
mossyblog commented 7 years ago

Disagree, this is what the ResourceDictionary route is designed for. Issue with CSS is it's really about defining a scriptable state in a JSOn style notation (see my concern with Duck Typing vs XML).

The ability in ResourceDictionary is to describe in a isolated state what a Control can leverage in terms of Data template vs Style Templates. CSS mixes the two metaphors and when the initial design for XAML was done this issue was raised for these specific reasons at the time.

Granted Blend when it implemented the Resource Dictionary confused the living crap out of everyone with its poor UX around this but none the less when the rhythms were identified you'd soon be able to make re-useable declarative style / data template matrix - combined with Visual State Management you also had further power.

Point is defining a color over and over is redundant and why limit it to just color why not a brush or dynamic line Expression() logic

<palette name="foo" color="#FFFFFFF" rgb="0,0,0" rgba="0,0,0,0">
<palette name="bar" color="{foo.color + 20% white}" rgb="0,0,0" rgba="0,0,0,0">

Moving to a JSON/HSON or whatever format isn't declarative its just scriptable state used to define the "standard" implementation and would regard that as being the role of the "implementation" of XAML's problem to solve.

insinfo commented 7 years ago

@mossyblog I agree that writing XML tags by hand is a problem of tooling. But the idea is not to transform XAML into HTML. Just because an HTML feature is attractive and you follow it to XAML this does not mean that you will turn "XAML into HTML". In addition certain things may exist in a specification more not nessessarily the developer is obliged to use, and in addition it may not be attractive to you most certainly will be for millions of developers to use CSS in the creation of themes for applications based on XAML

But I agree that this is one of the things that has to aver enough discussion, and the very idea is not to be inline, but rather as an external file

warappa commented 7 years ago

@insinfo @mossyblog I'm currently developing XamlCSS, an already working (s)css-library for WPF, Xamarin.Forms and UWP, so I'm in favor of css.

It converts css into native Style-instances based on selectors and updates matching when something changes (control added/removed, dependency-property changed,...).

You can use markup-extensions as you would in xaml like Background: #StaticResource backgroundImageBrush; - so xaml's ResourceDictionary and css work hand in hand. You can also declare variables in css (scss-like), i.e. $primaryBackground: #333333;, and use it throughout the css-file. It uses original xaml property names like Background, not background-color known from web-css. I'm no fan of such mappings.

Features

It supports:

Currently, I'm fixing some bugs and getting a new release ready, but with 2.0.0-pre1 you can get a taste of what it's like to use (s)css in xaml apps (see the docs and the sample projects in the source).

Nuget

https://www.nuget.org/packages/XamlCSS.XamarinForms/2.0.0-pre1 https://www.nuget.org/packages/XamlCSS.WPF/2.0.0-pre1 https://www.nuget.org/packages/XamlCSS.UWP/2.0.0-pre1

More Information

https://github.com/warappa/XamlCSS/wiki http://forums.dotnetfoundation.org/t/xaml-css-xamlcss-wpf-uwp-xamarin-forms/ (with some images)

insinfo commented 7 years ago

@warappa It's great work and I'm very interested, support the CSS binding natively in the XAML standard by giving a +1 in my post And I loved its approach of keeping the original names of the XAML properties

monkeynoises commented 7 years ago

@insinfo

Watch: https://channel9.msdn.com/Events/Build/2017/B8099

There's going to be some CSS based styling in Xamarin.Forms.....maybe make it into Standard...

https://forums.xamarin.com/discussion/88452/css-styling-and-flexbox

There's some interesting viewpoints on whether it's a good or bad idea.

If they did it, I would at least like to see the XAML styling equivalent being generated e.g. say something equivalent to a "generated" .designer file....i.e. autogenerated.

mossyblog commented 7 years ago

@warappa why? Where are the gaps between CSS and ResourceDictionary ..

insinfo commented 7 years ago

@monkeynoises I've also heard about it, it sounds interesting if it's done right.

warappa commented 7 years ago

@mossyblog Xaml styling offers nothing like selectors.

Take a primary button in a warning dialog.

In xaml you can

With css you can that plus

In an upcoming XamlCSS release there will be a WPF sample where you can live-edit the current visible style and get error messages.

mossyblog commented 7 years ago

@warappa which version of XAML... as you can set visual state management in styles and you can also set styles based on dynamicresources (also variables which Blend wont show you out of the box but its possible)... are you comparing WPF XAML or UWP/Xamarin XAML?

warappa commented 7 years ago

@mossyblog I speak of WPF, UWP and Xamarin.Forms.

You're right, styles and visual state manager (or more broadly templates) with dynamic resources, can get you pretty far. But UWP has no DynamicResource, Xamarin.Forms does but has no visual state manager.

I tried to come up with a simple equivalent of the following scss in WPF with type-styles, BasedOn and - explicitly - dynamic style-resources, but I failed. It is verbose, complicated and the designer can't handle the named style overriding right. Still, maybe someone else like you could come up with a cleaner xaml solution. (I took the simplest thing that came to my mind - setting a background-color)

Not great work, but here's a copy and paste gist for a new WPF application: https://gist.github.com/warappa/9a8810d8cc6ee2d96eee15af037c3321

Xaml

<Application.Resources>
        <!-- base colors -->
        <SolidColorBrush x:Key="buttonBackground" Color="#ff00ff"></SolidColorBrush>

        <!-- base button style -->
        <Style x:Key="baseButtonStyle" TargetType="Button">
            <Setter Property="Margin" Value="10,10,10,10"></Setter>
            <Setter Property="Background" Value="{DynamicResource buttonBackground}"></Setter>
        </Style>

        <!-- automatically style all buttons -->
        <Style TargetType="Button" BasedOn="{StaticResource baseButtonStyle}">            
        </Style>

        <!-- Window style -->
        <Style x:Key="window">
            <Style.Resources>
                <ResourceDictionary>
                    <SolidColorBrush x:Key="buttonBackground">Aqua</SolidColorBrush>
                </ResourceDictionary>
            </Style.Resources>
        </Style>

        <!-- normal primary button style -->
        <Style x:Key="primaryButton" TargetType="Button" BasedOn="{StaticResource baseButtonStyle}">
            <Style.Resources>
                <ResourceDictionary>
                    <SolidColorBrush x:Key="buttonBackground">Blue</SolidColorBrush>
                </ResourceDictionary>
            </Style.Resources>
        </Style>

        <!-- normal secondary button style -->
        <Style x:Key="secondaryButton" TargetType="Button" BasedOn="{StaticResource baseButtonStyle}">
            <Style.Resources>
                <ResourceDictionary>
                    <SolidColorBrush x:Key="buttonBackground">#ffaaaa</SolidColorBrush>
                </ResourceDictionary>
            </Style.Resources>
        </Style>

        <!-- warning dialog with overrides -->
        <Style x:Key="warning" TargetType="StackPanel">
            <Setter Property="Margin" Value="10"></Setter>
            <Setter Property="Background" Value="#ee7600"></Setter>

            <Style.Resources>
                <ResourceDictionary>
                    <!-- warning primary button style -->
                    <Style x:Key="primaryButton" TargetType="Button" BasedOn="{StaticResource primaryButton}">
                        <Style.Resources>
                            <SolidColorBrush x:Key="buttonBackground" Color="#660033"></SolidColorBrush>
                        </Style.Resources>
                    </Style>
                    <Style x:Key="secondaryButton" TargetType="Button" BasedOn="{StaticResource secondaryButton}">
                        <Style.Resources>
                            <SolidColorBrush x:Key="buttonBackground" Color="#aa0099"></SolidColorBrush>
                        </Style.Resources>
                        <Setter Property="Margin" Value="10,10,10,10"></Setter>
                    </Style>
                </ResourceDictionary>
            </Style.Resources>
        </Style>
    </Application.Resources>

(S)Css

In (s)css you can achieve just the same output and get designer-support with these lines (also in gist):

/* default styles */
Button {
       Background: #ff00ff;
       &.primary {
            Background: Blue;
        }
        &.secondary {
            Background: #ffaaaa;
        }
}
/* default window style */
Window {
    Button: {
        Background: Aqua;
    }
}
/* styles in a warning dialog */
.warning {
    Margin: 10;
    Background: #ee7600;

    Button {
        &.primary {
            Background: Orange;
        }
        &.secondary {
            Background: #aa0099;
        }
    }
}

I hope it is a sufficient comparison regarding overriding properties depending on its place in ui-hierarchy.

insinfo commented 7 years ago

@Warappa @monkeynoises Very good example, I wanted to have done a demonstration like this, except that I was short on time. I updated the post with an example of syntax, feel free to contribute with it

birbilis commented 7 years ago

@warappa VisualStateManager should be coming to Xamarin.Forms I guess sooner or later, judging from what was said at a relevant panel at recent Build. Not sure about DynamicResource on UWP. Why don't you log those as issues if not already logged and also any other shortcomings you found when trying to implement your CSS-like selectors?

BTW, why stick to the CSS syntax for those implementation-wise and not have some proposed XAML syntax/extensions with the CSS one used as an alternative that translates to XAML via tooling?

warappa commented 7 years ago

VisualStateManager is already proposed and DynamicResource is something I think everyone knows needs to be in the standard.

Actually css gets parsed to Stylesheet instances, which could already be expressed as xaml. A blog post, which inspired me to do XamlCSS, did use this aproach and reads very similar for XamlCSS stylesheets. So yes, css could be transformed into this representation at compile-time, reducing startup-time.

With Xamarin.Forms 3 announcements in mind I think styles with selectors will become part of the standard someday and css-syntax is also on the table. "Native" tooling should not be too far away after that.