This entry is part 2 of 4 in the series Getting to Know xstyle

xstyle_transparentxstyle is a framework for extending CSS, which can be used to improve the quality, maintainability, and performance of your stylesheets. While xstyle can be used as a full framework for building applications with data bindings and UI generation, in this post we will focus on making progressive improvements to stylesheets within the traditional role played by CSS.

One of the most important principles of good code programming is to avoid duplication. This is also known as the DRY principle, and it applies to stylesheet rules just as much as it applies to imperative code like JavaScript. Code duplication is an anti-pattern for several reasons. First, it simply increases the size of your code, an important concern in the browser. Second, it makes code harder to read, as there simply is more to parse, and readers are constantly faced with trying to compare sections of code to see if there are intended differences, and mentally diff’ing sections of code. And finally, it is harder to maintain duplicated code, since we have to make sure changes are reflected in all copies, with failure to properly synchronize leading to unintended inconsistencies.

In this post we will introduce a few of the tools in xstyle for creating less redundant stylesheets. While features like mixins and variables are a common part of other CSS preprocessors, xstyle can function at run-time, as an AMD plugin, with build-time integration. In other posts we will explore the numerous other capabilities of xstyle that extend well beyond just eliminating duplication and rearranging CSS, but this should provide an introduction to some of the CSS extension basics.

First, CSS property definitions can easily be reused with xstyle. We can simply create a new mixin definition with the properties that we want to reuse, and then we can use it in any rule we want. First, to load xstyle, we include xstyle/main as a dependency in our application. Then, in our CSS, we can create a mixin by simply using the assignment operator, ‘=’ to give our mixin a name:

highlighted = {
    color: blue;
    background-color: yellow;
}

In xstyle, new definitions can now be used like regular properties. First, we can use this new mixin property with the values as defined in the mixin:

.my-rule {
    highlighted: defaults;
}

However, we often don’t want to only use the preset values of the mixin, but rather use mixins with our own adjustments. Naturally, we could simply override values by setting CSS properties after the mixin. Here we override the color of the text:

.my-rule {
    highlighted: defaults;
    color: light-blue;
}

However, as a mixin, the properties are implicitly parameters that can be modified when the mixin is used as a property. The properties are overwritten by their order of definition in the mixin. Therefore we could use the mixin, and change the color to light-blue by writing:

.my-other-rule {
    highlighted: light-blue;
}

xstyle’s mixin definitions not only allow us to reuse sets of properties, but it gives us the flexibility to easily treat these as parameterized sets to be adjusted and customized for different rules.

xstyle also gives us the ability to use variables in our CSS. This also helps to improve the re-usability of stylesheet rules, as it allows us to create a stylesheet that is parameterized and easily reuse different settings that may be tuned for color and sizing options. One of the advantages of xstyle is that it uses the standard W3C’s Cascading Variable syntax for referencing variables. If we want to create a rule that depends on a variable, we can write:

.my-rule {
    color: var(primary-color);
}

And then we can use the xstyle definition syntax to create the variable, by declaring a new definition as a var, and assigning it a value. Here we define the primary-color as “green”:

primary-color=var: green;

We could also use the features in conjunction to create more sophisticated paramaterized mixins. For example, let’s create a parameterized border for vertical and horizontal colors:

my-borders = {
    horizontal-border-color: yellow;
    vertical-border-color: green;
    border-top: 1px solid var(horizontal-border-color);
    border-bottom: 1px solid var(horizontal-border-color);
    border-left: 1px solid var(vertical-border-color);
    border-right: 1px solid var(vertical-border-color);
}

And now we could use this definition in a rule:

#target {
   my-borders: blue, black; /* assign blue horizontal borders and black vertical borders*/
}

Nesting Rules

Another beneficial feature of CSS extension is nested rules, where we can define a beginning portion of a CSS selector, and then child selectors can define the rest of the selector. This is particular useful if you have a set of selectors that should all be applied to children of a certain parent component. For example, if we wanted to define rules for “#parent .child-one” and “#parent .child-two” we could write:

#parent {
    .child-one {
        /* properties to be applied to #parent .child-one */
    }
    .child-two {
        /* properties to be applied to #parent .child-two */
    }
}

Within xstyle, a rule can serve as more than just a parent to children to reduce duplication in selectors, nesting also provides a mean for defining the scope of definitions. We can create a definition of a mixin or shim within a rule, and then it will be limited to the scope of that rule, a building block for creating encapsulated components.

Shims

One of the common challenges faced in writing stylesheets is dealing with missing features, or vendor-prefixed properties. It is common to see properties repeated several times with each possible different vendor prefix. xstyle makes it easy to avoid this type of duplication by shimming properties. The simplest shim covers the case of vendor prefix. We can create a property for that adds vendor prefixing, if the standard property is not present, by writing:

box-shadow =? prefix;

And then we can easily go on to use this property in our rules by simply using this property as if it were a standard property (which it may be in some browsers):

.my-rule {
    box-shadow: 4px 6px 6px #aaa;
}

And this will automatically alter the property to use the appropriate vendor prefixing when appropriate. If the browser supports this property, no changes will be applied.

xstyle provides a full API for creating your own shims, complete with the ability to report all the elements that match rules for the shimmed property, so virtually any CSS property can be shimmed.

When using shims, it may be desirable to only use the shims for certain stylesheets that will be upgraded, while leaving certain legacy CSS alone. This can easily be done by using the @style directive:

@xstyle start;
@import 'legacy.css';
@style end;

While again, much of what has been covered is available in other CSS preprocessors, xstyle allows us to go much further in creating and using shims that require dynamic interaction with the DOM rather simply some CSS rewriting, without requiring a different interface to use such shims. xstyle then seamlessly integrates with the module system without any extra server-side process required.

xstyle also includes build tools to concatenate and minify CSS, that can function on their own, or integrate with the Dojo build system. One of the unique capabilities of the build tools is the ability to additionally inline other media resources, like images and fonts, to reduce the number of requests. Especially for small resources, this can have a significant positive impact of page loading performance. With xstyle, we can specifically indicate which resources to inline during builds. Simply append #inline to the URLs of the resources that should be inlined (usually just the smaller resources):

.my-rule {
    background-image: url('image.png#inline');
}

The build system will then replace this URL with a base64 data URI, so the image can be displayed without any extra HTTP requests.

This post will hopefully give you some ideas of how you can start using xstyle to create efficient, easy-to-maintain stylesheets. In subsequent posts, we will look at how you can go even further with CSS extensions.