Blog

State of Sass support in Vaadin 7 Today

By  
Jouni Koivuviita
Jouni Koivuviita
·
On Sep 6, 2012 1:01:00 PM
·

I'm writing a few articles about the new theme features in Vaadin 7, mainly Sass and the new layouting and how those affect theme development.

As you might have read from our newsletter or from various tweets, Vaadin 7 will include support for Sass (short for Syntactically Awesome Style Sheets). As a recap, Sass is an extension to CSS3, making CSS authoring more productive and less painful to maintain.

You're probably wondering what this means in practice – how does this affect your workflow and theming of your Vaadin apps? Well, let's go through the features that are currently supported in the nightly build, with practical examples.

Getting Up and Running

In order to start using Sass in our themes, we need to rename our styles.css file into styles.scss. This allows the Sass servlet to automatically find the Sass file and turn it into CSS for the browser.

Since the Sass servlet, which would automatically compile your Sass to CSS, is not yet implemented (#9222), we need to run the Sass to CSS compilation manually for now. The basic command would be in the lines of:

java -cp path/to/vaadin-theme-compiler-*.jar com.vaadin.sass.SassCompiler path/to/theme/input.scss path/to/theme/output.css

Since this can be a bit clunky to type into your terminal each time, below is a handy bash-script that you can copy and paste into a compile-sass.sh on your own POSIX-compatible computer, and run it in your project's root directory. Creating a similar .bat file should be pretty analogous, but unfortunately I don't have a Windows-machine to create and test one with.

#!/bin/bash

# usage:
# ./compile-sass.sh [scss-input] [css-output]
# - scss-input:  default is "styles.scss"
# - scss-output: default is using the same filename as 
#                scss-input, but instead with .css extension.

# change this to your theme name
THEMENAME="mytheme"

# change if your configuration differs from the default Eclipse project
THEMEDIR="WebContent/VAADIN/themes"
VAADIN_DIR="WebContent/WEB-INF/lib"

if [ -z "$1" ] 
then
	THEMEFILE="styles.scss"
else
	THEMEFILE="$1"
fi;

if [ -z "$2" ]
then
	TARGETFILE=${THEMEFILE/\.scss/\.css}
else
	TARGETFILE="$2"
fi;
	
echo "Compiling, theme: $THEMENAME, source: $THEMEFILE, target: $TARGETFILE"
java -cp $VAADIN_DIR/vaadin-theme-compiler-7*.jar com.vaadin.sass.SassCompiler $THEMEDIR/$THEMENAME/$THEMEFILE $THEMEDIR/$THEMENAME/$TARGETFILE && echo "done!"

You need to run this after each change to the .scss file in order for them to show up in the browser.

Now, let's get to the actual features then!

1. Style Sheet Concatenation

As with any programming language, a large codebase should be split up into easily maintainable pieces. With CSS that means using separate files for styles that affect different parts of the UI – split for instance by component type or by application view – which are then collected into a whole theme by using the @import declarations in the main style sheet:

# VAADIN/themes/mytheme/styles.scss
@import "../reindeer/styles.css";

@import "button/button.css";
@import "combobox/combobox.css";
...

But as you know, browsers need to fetch each of those style sheets individually, creating a bunch of HTTP requests in order to get them.

By using Sass, we can get rid of those extra requests, and concatenate the imports automatically already on the server, so the browser only needs to load one CSS file. The relative paths are resolved correctly, so if you have nested imports or you reference any images/resources in the imported style sheets those references will still be correct after the concatenation. You can import both .css or .scss files, and you can even leave the file extension out, the compiler checks for both .scss and .css files.

Importing also helps when using variables and mixins (we'll get to those features in a moment), as you can define your variables and mixins in a separate file and use those across the other imported style sheets.

2. Variables

This is probably the most self-explanatory of the features, a no-brainer even. You can define variables in your CSS, which makes maintenance and small changes that affect a lot of places a lot less of a hassle.

/* Sass */
$var: red;

.my-style {
  color: $var;
}

/* Compiled CSS */
.my-style {
  color: red;
}

We have plans to define a common set of variables that can be used across themes (#9381), which will make creating add-ons that support multiple themes much easier, since you can just refer to those variables and trust that the main theme will provide the actual values for you.

3. Nesting & Parent Referencing

Nesting makes structuring your styles easier. Instead of declaring a parent class in each selector, you can just declare that parent once, and nest all the child selectors inside it. This will make sand-boxing styles a lot easier, since you can provide a scope with a single declaration. Combine this with the parent reference, and you can start building quite flexible reusable styles.

Nesting:

/* Sass */
.v-reindeer {
  .v-button {
    ...
  }
  
  .v-button:hover {
    ...
  }
}

/* Compiled CSS */
.v-reindeer .v-button {
  ...
}

.v-reindeer .v-button:hover {
  ...
}

Parent referencing:

/* Sass */
.v-reindeer {
  &.v-button {
    ...
  }
  
  &.v-button:hover {
    ...
  }
}

/* Compiled CSS */
.v-reindeer.v-button {
  ...
}
.v-reindeer.v-button:hover {
  ...
}

There's a subtle difference in the examples, in the way the parent and child selectors are joined (space vs. no space). The parent reference can be placed anywhere in the selector, not just at the beginning.

We plan to reuse individual component styles across different themes easier with this feature, so you can for example use the Reindeer theme but replace the button theme from Runo.

4. Mixins

This is a big one. Quoting from the Sass documentation:

"Mixins allow you to define styles that can be re-used throughout the stylesheet. Mixins can also contain full CSS rules, and anything else allowed elsewhere in a Sass document. They can even take arguments which allows you to produce a wide variety of styles with very few mixins."

In short, mixins help you abstract certain parts of complex CSS code into re-usable "black boxes", which can be used all around your style sheets.

Suitable candidates for abstraction are all properties which require vendor prefixes, such as border-radius, gradients, transition and transforms – all the newfangled CSS3 goodness basically.

/* Sass*/

/* Define a mixin. This won't produce anything in the compiled CSS yet. */
@mixin border-radius($radii) {
  -webkit-border-radius: $radii;
     -moz-border-radius: $radii;
          border-radius: $radii;
}

/* Use the mixin */
.my-style {
  @include border-radius(4px);
}

/* Compiled CSS */
.my-style {
  -webkit-border-radius: 4px;
     -moz-border-radius: 4px;
          border-radius: 4px;
}

Another higher level use case for mixins are customizable component styles. The Vaadin Button is a prime example in that many times you have buttons that resemble each other in style but differ in their color. You could then abstract the button as a mixin with a color parameter, and create as many button styles using that mixin as you wish.

We also have plans to include a suitable set of mixins in the Base theme for the lower level vendor-prefixed CSS3 properties and higher level component mixins in the core themes. These won't probably materialize in the 7.0 release, however we might find some initial support for these in 7.1.

5. Color Functions

Sass has many built-in functions for color manipulation, but currently Vaadin only has two implemented for you to test: lighten and darken.

Lighten does pretty much what you expect: it lightens the color you pass it as a parameter. This is useful when building a set of styles based on the same color, but when you need to adjust the color slightly e.g. to make color gradients.

/* Sass */
$blue: rgb(0, 180, 240);
$light-blue: lighten($blue);

.my-style {
  border: 1px solid $blue;
  background-color: $light-blue;
}

/* Compiled CSS */
.my-style {
  border: 1px solid rgb(0, 180, 240);
  background-color: rgb(36, 200, 255);
}

You can pass the function another parameter, specifying the amount of lightness you wish to apply to the color. The default value is 10%.

$light-blue: lighten($blue, 5%);

/* Compiled CSS */
background-color: rgb(10, 194, 255);

The darken function does the exact opposite of lighten, as you might have guessed. They're basically the same function, you can even use lighten to make colors darken by passing in a negative percentage value as the second parameter.

The Missing Pieces

There's a lot of functionality in Sass that we haven't yet implemented. The missing features haven't been prioritized in any clear way, so if you have wishes what we should add next, feel free to either comment here or on the existing Trac tickets, or create new tickets.

Below is a list of features we are currently missing (with links to their documentation on the Sass website):

Test, Test and Feedback

Since all of this functionality is rather new in Vaadin, it needs loads of testing before we can say for sure it works 100%. So if you're responsible for theming Vaadin apps, or are at least interested in getting to know the new features, download the latest nightly and start testing. And be sure to report any issues you encounter and provide feedback on the features you wish to see implemented.

Jouni Koivuviita
Jouni Koivuviita
Hi! I’m a long time Vaadiner since 2006. My goal has always been to provide you with the best UI components in the world for mobile and desktop web applications. Still hoping to get there eventually :D
Other posts by Jouni Koivuviita