Open insinfo opened 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?
@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;
}
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.
@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
@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.
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).
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
https://github.com/warappa/XamlCSS/wiki http://forums.dotnetfoundation.org/t/xaml-css-xamlcss-wpf-uwp-xamarin-forms/ (with some images)
@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
@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.
@warappa why? Where are the gaps between CSS and ResourceDictionary ..
@monkeynoises I've also heard about it, it sounds interesting if it's done right.
@mossyblog Xaml styling offers nothing like selectors.
Take a primary button in a warning dialog.
In xaml you can
primaryWarningButton
and set it on the button directlyPrimaryWarningButton
(subclassed from Button
)With css you can that plus
if a button is in a dialog, make it orange
primary
, warning
, header
, icon
, hidden
and apply them to ui-elements - no matter what type this element is.
I.e. if a button has the role primary, make background color blue
, or if a button has the role primary and is in a dialog with the role warning, make background color orange
.a button with the roles primary and jumbo
In an upcoming XamlCSS release there will be a WPF sample where you can live-edit the current visible style and get error messages.
@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?
@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
<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>
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.
@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
@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?
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.
CSS inline style linking and or in separate file
Instead:
Can be it:
Or XAML
CSS
https://forums.xamarin.com/discussion/88452/css-styling-and-flexbox/p1