Style sets in H-SMILE core.

September 27, 2010

Filed under: HTML and CSS,HTMLayout,Sciter — Andrew @ 3:43 pm

HTMLayout and Sciter are both use H-SMILE core to render HTML/CSS. And so both of them support so called style sets.

In this article I’ll try to explain what style set is about and why I decided to introduce them.

First of all: Style set is a named block of style rules – definition of system of style declarations that are applied to some DOM sub-tree.

Style set declaration starts from @style-set at-keyword followed by the name of the style set and block of style rules enclosed in ‘{‘ and ‘}’ brackets:

Code Block A:

@style-set MyStyleSet 
{
   :root { font:12pt Verdana; margin:0; padding:0 }
   :root > li { font:12pt Verdana; display:block; }
   strong { color:red; }
}

As we see this style set is named as ‘MyStyleSet’ and contains three rules. Note the use of :root pseudo-class above – inside style set declaration the :root designates element to what this style set is applied. Such an element is a root of DOM sub-tree that uses this style set.

To apply such style set to particular DOM sub-tree we use style-set property in CSS as this:

Code Block B:

ul#my-list
{
   style-set: MyStyleSet;
}

This way we are telling our CSS engine that ul#my-list element and its all sub-elements will use styles from the set above.

Style sets allow to define system of related style declarations in single and compact block. If you have multiple style sets that can be applied to the same sub-tree it is enough to change name of the style set on single element – root element of the sub-tree:

Code Block C:

html[theme="MyCoolTheme"] ul#my-list {  style-set: MyStyleSet; }
html[theme="AnotherCoolTheme"] ul#my-list {  style-set: AnotherStyleSet; }

This way, by changing theme attribute on html element, we can apply two different and independent style sets to ul#my-list element and its children.

Without style sets (in conventional CSS) we will need to write bunch of rules like these:
Code Block D:

html[theme="MyCoolTheme"] ul#my-list { font:12pt Verdana; margin:0; padding:0 }
html[theme="MyCoolTheme"] ul#my-list > li { font:12pt Verdana; display:block; }
html[theme="MyCoolTheme"] ul#my-list strong { color:red; }
html[theme="AnotherCoolTheme"] ul#my-list { font:10pt Arial; margin:0; padding:0 }
html[theme="AnotherCoolTheme"] ul#my-list > li { font:10pt Arial; display:list-item; }
html[theme="AnotherCoolTheme"] ul#my-list strong { color:blue; }

that is not so pretty and quite error prone as any other cut-n-paste approach.

Another benefit of having style set is that they work great in cases when you need to have style libraries. Consider for example jQuery UI library or any other library of Web components. As an example Tabs UI Component may have all its styles defined as a style set:

@style-set Tabs {
   :root > ul.ui-tabs-nav { ... }
   :root > div.ui-tabs-panel { ...; display:none; }
   :root > div.ui-tabs-panel.current { ... ; display:block; }
}

and different theme style files of jQuery UI library might have different and independent declarations of the Tabs style set.

Styles sets are not only convenient and compact way of defining system of styles but they also is a great way to reduce computational complexity of resolving styles of DOM elements. Consider following markup and system of styles defined in Code Block D above:

   <ul id="my-list"><li>Item</li></ul>

To resolve style of the LI element above CSS processor shall scan all rules found in all style sheets (6 of them in this particular example).
For example to determine if this rule:

html[theme="MyCoolTheme"] ul#my-list > li

can be applied to the LI element or not the CSS processor should scan not only the element itself but also all its parents in order to find HTML element with theme attribute set. In general the computational complexity of the style resolution of the DOM having N elements and with S number of style rules is O(N*S).

With style sets the complexity is significantly less because number of styles rules needs to be resolved is less. There are 6 rules in Code Block D (conventional CSS) versus 2 rulers in Code Block C (style sets). Style rules in particular style set will be scanned only for elements that have corresponding style-set property defined.
The style-set property is an inheritable one so any element in sub-tree of “styled root” element will have the same value of the style-set.
In practice this means for example that your UI may have many themes that can be switched in runtime and adding new theme will not slow down style resolution.
You can also create libraries of styles of your components that can be applied to your components by simply defining style-set property in CSS.

More about computational complexity of CSS selectors.

Resolution of styles with style sets of DOM elements

Under the hood resolution of styles is using following steps:

  1. For each particular element styles are getting resolved as usual. Styles inside style-set blocks are not considered at all at this step.
  2. If after step #1 the element gets some value in its style-set property then and only then system is trying to find defined style block. If such block is found then rules from the block are applied on top of properties resolved in step 1 according to specificity of CSS selectors in that style block.

As you see weight of rules defined in style-sets is greater than conventional CSS rules. To override property defined in style set by conventional style rule the later one shall use !important modifier, like this:

ul#my-list 
{ 
   style-set: MyStyleSet; 
} 
ul#my-list strong 
{  
   color: yellow !important; /*overriding color set by strong { color:red; } in MyStyleSet */
} 

Style sets and OOP

To make style-sets even more modular and reusable I’ve added inheritance in style-sets – you can define new style set that will inherit all rules from the base one.

@style-set Tabs {
   :root > ul.ui-tabs-nav { display: block; margin:Xpx; ... }
   /* all other rules that define layout properties */
}
@style-set BlueTabs < Tabs /* inherits all rules from Tabs set */
{
   :root > ul.ui-tabs-nav { color: blue; }
   /* other "color" rules */
}
@style-set RedTabs < Tabs /* also inherits all rules from Tabs set */
{
   :root > ul.ui-tabs-nav { color: red; }
   /* other "color" rules */
}

The declaration above introduces three style sets that can be used independently and yet RedTabs and BlueTabs use the same shareable prototype – the Tab set.

Style sets are used a lot in so called Master CSS (UA default style sheet) by H-SMILE core engine to give default styling of DOM elements and inputs. Styles sets there allow to minimize time needed for resolution of default styles.

2 Comments

  1. This is absolutely great!
    Would you recommend using style-sets to modify the displayed contents of the DOM.?
    For instance by hiding / showing child branches according to a ‘state’ attribute in the root?

    Comment by yonatan — October 7, 2010 @ 1:08 am

  2. To Yonatan about “Would you recommend using …”

    If you understand the idea then “yes”, you can use it and benefit from them.

    Style-sets in H-SMILE core are working even you are not using them explicitly. Master CSS file is just a set of style-sets at the end.

    Comment by Andrew — October 14, 2010 @ 8:43 pm

RSS feed for comments on this post. TrackBack URI

Sorry, the comment form is closed at this time.