Google analytics script

Latest jQuery CDN with code tiggling.

Sunday, 29 January 2012

CSS3 cross browser SASS... no, SCSS mixins

I like automation that eliminates human factor of forgetting of doing something. Happens to me just like it most likely happens to you. Especially when we do repetitive things. That's why I've written a few posts that are direct result of me striving for automation. May it be the post about NUnit test project settings in Visual Studio that starts NUnit test runner by simply pressing F5 button or the additional file editor that automatically executes batch (*.bat) files from within Visual Studio. Never mind. This one's related to simplicity, versatility and automation. And CSS3 stylesheets of course.

Actually it's about the extended CSS syntax that we get by writing SCSS stylesheets (similar to LESS, but more on it later on). SCSS used to be called SASS with its own syntax but now uses CSS syntax hence changed its name. I will be using SCSS acronym from now on because that's what my following code example uses. If you've ever used any of these two you'll know the benefits of simplified, easier to handle and more powerful style sheets. I have been flirting with this couple for some time now, but on this last project of mine, my flirting became a serious relationship. I started using SCSS. What I will share with you here are a few common mixins that are usable to any web developer.

Where's the automation here?

Well the automation part comes in in a form of a Visual Studio extension. Mindscape's Web Workbench free Visual Studio extension. Although buggy it gives you support for LESS, SCSS as well as CoffeeScript syntax highlighting and intellisense (which is the main buggy part, so don't expect too much of intellisense at this point in time).

There's also a Pro version that by my opinion doesn't offer any particularly useful features:

  • it adds LESS server side compilation - this actually contradicts what LESS is all about; LESS should always be compiled on the client because it can also have Javascript evaluated styles;
  • LESS and SCSS minification - as I will show you later on, you can set the level of minification for SCSS files without upgrading to Pro version;
  • Javascript minification - this one may be useful if you write CoffeeScript files, but can be resolved by some other extension or most likely build step;
  • Intellisense for SCSS and LESS functions - this may be handy but since there aren't that many, you can look them all up once, get acquainted with them and then when you'll need them look up their syntax if you need to; I know this takes more time, but since Intellisense is very buggy I wouldn't risk those $ to get Pro version when a similar feature already has bugs; Thanks, but no thanks;
  • document formatting for LESS and SCSS files - I write perfectly formatted styles (beauty is in the eye of the beholder) so I don't need any automatic formatter;
  • keyboard shortcuts to comment/uncomment individual lines or blocks of lines - pay for this? seriously?
Anyways. Even without the added sarcasm I think that these features alone don't convince me enough to go Pro. They may convince you of which I'm not going to be the judge.

Apart from this Pro version and even though intellisense is buggy I find this free Visual Studio extension still extremely useful. I know CSS settings and their possible values through and through, so intellisense is not missed too much. The automation on the other hand would be greatly missed. What this extension provides is automatic conversion of SCSS files to CSS ones on file save. Great! I don't have to set up any additional build steps that would run some console app to do the conversion. Nor do I have to manually execute some T4 templates to do the conversion. I simply save a file and refresh my page in the browser. This makes my development much faster. And by automating syntax conversion I can easily forget about doing some manual work. This way I know that I'm always working with the latest CSS files on the client as long as I've edited and saved my SCSS file on the server.

How about those mixins I bragged about

The moment I started writing some SCSS styles that included special per-browser settings I knew I could simplify them by a single line. Which ones would those be? Well box-shadow for instance. You have to write few lines for CSS3 rule, then add a Mozilla line, WebKit one etc... Using a mixin I can easily just put all those in and then use the mixin instead in a single line. They work similarly to macros that we used to write decades ago.

So here go these mixins that I'm currently using. Majority of them is CSS3 related, but some are not:

   1:  // Global reusable mixins
   2:   
   3:  /*
   4:   * Version: 2.0 (2 Feb 2012)
   5:   * 
   6:   * Copyright (c) 2011 Robert Koritnik
   7:   * Licensed under the terms of the MIT license
   8:   * http://www.opensource.org/licenses/mit-license.php
   9:   */
  10:   
  11:  @mixin noOuterDimensions {
  12:      margin: 0;
  13:      border: 0 none;
  14:      outline: 0 none;
  15:      padding: 0;
  16:  }
  17:   
  18:  @mixin resetList($display: block) {
  19:      @include noOuterDimensions;
  20:      display: $display;
  21:      list-style: none;
  22:  }
  23:   
  24:  @mixin roundedCorners($radius: 5px) {
  25:      border-radius: $radius;
  26:      -moz-border-radius: $radius;
  27:      -webkit-border-radius: $radius;
  28:      background-clip: padding-box;
  29:      -moz-background-clip: padding-box;
  30:      -webkit-background-clip: padding-box;
  31:  }
  32:   
  33:  @mixin shadow($settings) {
  34:      box-shadow: $settings;
  35:      -moz-box-shadow: $settings;
  36:      -webkit-box-shadow: $settings;
  37:  }
  38:   
  39:  @mixin backgroundGradient($settings) {
  40:      background-image: linear-gradient($settings);
  41:      background-image: -o-linear-gradient($settings);
  42:      background-image: -ms-linear-gradient($settings);
  43:      background-image: -moz-linear-gradient($settings);
  44:      background-image: -webkit-linear-gradient($settings);
  45:  }
  46:   
  47:  @mixin opacity($value) {
  48:      opacity: $value;
  49:      filter: unquote("alpha(opacity=#{($value * 100)})");
  50:  }
  51:   
  52:  @mixin transition($property: all, $time: .5s) {
  53:      // transition times
  54:      transition-duration: $time;
  55:      -o-transition-duration: $time;
  56:      -ms-transition-duration: $time;
  57:      -moz-transition-duration: $time;
  58:      -webkit-transition-duration: $time;
  59:      // transition properties
  60:      transition-property: $property;
  61:      -o-transition-property: $property;
  62:      -ms-transition-property: $property;
  63:      -moz-transition-property: $property;
  64:      -webkit-transition-property: $property;
  65:      // transition function
  66:      transition-timing-function: ease-in-out;
  67:      -o-transition-timing-function: ease-in-out;
  68:      -ms-transition-timing-function: ease-in-out;
  69:      -moz-transition-timing-function: ease-in-out;
  70:      -webkit-transition-timing-function: ease-in-out;
  71:  }
  72:   
  73:  @mixin backgroundSize($tuplePercent) {
  74:      background-size: $tuplePercent;
  75:      -moz-background-size: $tuplePercent;
  76:      -webkit-background-size: $tuplePercent;
  77:  }

Simplified usage example

As you can see some of the upper mixins use parameters, some don't, some have default values applied to them, some don't. Change defaults to accommodate your needs so you won't have to provide same values over and over again. Here's a very simplified example of an SCSS file that uses these mixins (supposedly in a file called Mixins.scss):

   1:  //* scss-compile-options: :style => :compressed
   2:   
   3:  // import global mixins
   4:  @import "Mixins.scss";
   5:   
   6:  body {
   7:      @include noOuterDimensions;
   8:      /* unquote workaround for arbitrary number of parameters */
   9:      @include backgroundGradient(unquote("#ccc, #fff 50%"));
  10:  }
  11:   
  12:  ul.menu {
  13:      @include resetList;
  14:      li {
  15:          @include resetList;
  16:          float: left;
  17:      }
  18:  }
  19:   
  20:  input[type=text] {
  21:      @include roundedCorners;
  22:  }
  23:   
  24:  button {
  25:      &:hover {
  26:          @include shadow(0 1px 2px rgba(#000, .15));
  27:      }
  28:  }
  29:   
  30:  .someElement {
  31:      @include opacity(.5);
  32:      @include transition;
  33:      &:hover {
  34:          @include opacity(1);
  35:      }
  36:  }
I've provided a public Gist to access both of these files directly so you don't have to copy and paste any code here (althout it would probably be faster since you're already here).

What's with that first line?

You may find the first line in the upper example a bit strange because you won't find this in SCSS documentation nor on Web Workbench's product description pages. //* scss-compile-options: :style => :compressed Actually I ran against it on Mindscape's support forum. I was wondering whether I could format/minify my CSS output the way that original Rails compiler does. It turned out I can. Mindscape's put this functionality to give us a way to add SCSS compiler options. YOu can actually provide more than just one option: //* scss-compile-options: [options] where you can enter several comma separated options. There're not many that you can use here. One of them is style (which can be used for minification as used here), the other may be to include original SCSS file line numbers that get added into CSS file. Using this option will give you the ability to easily locate particular incorrect style definition within your SCSS file. I can see this one being handy when SCSS file gets big thus harder to handle/maintain.

What about that unquote workaround?

It's a problem defining a mixin with an arbitrary number of parameters/arguments where delimiter is a comma character. Now you can see that certain style definitions in CSS3 require you to add multiple separate settings (as is always true with gradients). That's why we have a problem with mixins that take only one style definition but because it has a comma within it looks like several parameters. SCSS compiler would report an error and your CSS generation would fail. That's why we can use the unquote workaround where we put all those settings inside a single string and then simply unquote it which converts the string back to several style settings. SCSS compiler will now see this as a single parameter (unquoted string) and our styles will get as many settings as we need. Simple as that.

LESS has a bit of an advantage here because you can access all parameters by using $arguments which unfortunately doesn't exist in SCSS. At least not in the current version but I suppose they'll add this support especially because CSS3 has several settings that have several arbitrary style settings separated by commas. Background gradients are one that always use at least two settings (otherwise we wouldn't have any gradient in the first place), shadows are another one (some of you don't even know that you can provide several here) because CSS definition goes like this: box-shadow: none | [ , ]*

SCSS is still arguably better than LESS

It is of course arguable whether SCSS is better than LESS and vice-versa. When there was SASS instead of SCSS I could argue that for everyday web developers not bound to any server side technology or language LESS was a much better choice. But since SASS transitioned to SCSS which is just extended syntax of the usual CSS (writing everyday CSS styles and saving them as SCSS files would therefore work without a problem) I'd rather argue that SCSS is a better option than LESS. Here's why:

  1. SCSS is intended to be compiled on the server LESS on the client; there are of course tools to do both on either side but LESS does support Javascript evaluations which (when used) must be compiled on the client;
  2. client-compiled LESS files actually get compiled on every page load using client browser resources and that's a lot of unnecessary compiles if you ask me; especially if they don't have any Javascript evaluations;
  3. styles usually don't change between versions at all after they've been deployed which means it's much better to compile them once on the server and then simply serve static CSS files to the client saving server as well as client resources;
  4. client expression-like styles have been considered bad since IE supported them (at least since version 6 if not older) but they've always been a feature to be avoided; Microsoft has actually discarded them since IE8 for the same reason; LESS client side Javascript evaluations are arguably similar;
  5. SCSS supports more built-in functions then LESS; this is arguable whether we'd be using those additional ones and whether we can't accomplish the same thing with less LESS functions, but there are more at your disposal;
  6. if nothing else LESS name implies that you can do less with it than with SCSS (not arguing about this one of course);
  7. but both (including SCSS) require you to write less lines of code and arguably more readable than plain old CSS;

Hope all these helps a bit. If you think I've missed some other commonly used mixin let me know about it and we'll discuss it.

2 comments:

  1. Just regarding your 6th argument in SCSS v. LESS comparison: the 'less' in the name may as well imply (and it likely does) that you write less CSS for the same effect. :)

    ReplyDelete
    Replies
    1. It's my typo. I should write SCSS in place of CSS. LESS of course does much more than CSS but less than SCSS.

      Delete