Is it good to enforce a CSS code style guide?

The goal

Have SCSS stylesheets that look as if there written by 1 developer while working in a team.

Is this even an issue to begin with?

Frontend developers tend to be strict on the way they write CSS/JS but that’s not the main reason. Having organized and clean code is key for fast iterations. Everyone wants to be Agile these days.

If all the files look the same it’s easy to read and easy to pick up again in the future should the project require more phases.

How did we do it?

All recent projects at TBSCG have a build process (Grunt) to compile SCSS, JS, HTML, etc. So we simply included a linter task in that process.

We created a rules file to specify what want we wanted to enforce. Things like:

  • HEX color codes should be in variables. And even better, all in 1 file.
  • Spaces between brackets and class names.
  • Break lines between rules.
  • No !important anywhere 😎
  • Leading zero ( .5 vs 0.5 )
  • Order of the properties (did you know ordering the properties generates smaller gziped files than unordered?)

We only add this linter task to the dev build, so it will never crash in production should we commit a file with errors.
However, with the dev task Grunt will stop as we configured this to be errors not warnings.

Alright, I know what you must be thinking. In some cases hacks might be necessary (we all know how pesky CSS can be), there is a special markup to bypass the enforced rules. It should be used in very special cases. Otherwise the linter makes no sense.

Examples

Because code speaks better than me. Here are some examples of what I mean.

The following code fails to comply with the linter rules. Thankfully Atom knows that and highlights the problems even before I run my Grunt task, so I can fix them as I go.

linter-scss-errors

When running the Grunt task (in case your IDE does not warn you). Here’s the output:

SpaceBeforeBrace: Opening curly brace `{` should be preceded by one space

PropertySortOrder: Properties should be ordered bottom, display, position, width, z-index

DuplicateProperty: Property `bottom` already defined on line 4

SpaceBeforeBrace: Opening curly brace `{` should be preceded by one space

DeclarationOrder: Expected item on line 14 to appear before line 12. Rule sets should be ordered as follows: `@extends`, `@includes` without `@content`, properties, `@includes` with `@content`, nested rule sets

Now here’s the code fixed to pass the linter. Looks better, doesn’t it?

linter-valid-scss

Using it in a real project

Everything is great and all but can this be used in a real project? Does it make sense? Is it productive?

I won’t deny there’s a learning curve for those developers who are used to write code without any strict code style. I truly believe this is good in the long run. Once you get used to the rules, you’ll use them as you type.
The IDE is also important, you need to install the proper plugins to detect the linter config file, so it warns you without the need to run Grunt. In our case Grunt is our second line of defense. Your own editor should be the first to let you know.

Here’s the opinion of Artur Spulnik a Web Developer at TBSCG who worked with me on this real experiment:

Thanks to these principles code was much easier to read and maintain. I had to summon all my knowledge about the alphabet to correctly queue all definitions. There was a lot of pain in the beginning with operators order, and those wild spaces (or lack of them). But with practice comes success and I felt boost of productivity. Especially in terms of teamwork.

Have you ever written code this way? If you haven’t, will you give it a try?

Can we have cleaner HTML with Bootstrap?

The other day a colleague consulted me about CSS frameworks:

The client doesn’t want to pollute the HTML with those Bootstrap classes

I understand. If you ever used Bootstrap you know each HTML element might have 3, 4 or more classes. For columns, colors, custom styles…

Can we use custom classes with Bootstrap features?

Yes! You can have clean HTML. Only adding your own more-semantic classes while using the power of bootstrap buttons, grid and all its other features.

I’ve created an example achieving the same result one with core Bootstrap Classes and the other with Custom Classes. Stick with me until the end for the conclusions.

twitter-widget-demo

HTML with Custom Classes

The code below might be more readable, you can understand what the element does or contains.

<section class="container">
 <div class="twitter-widget">

 <div class="twitter-header">
 <div class="twitter-header-content">
 <h2>My Twitter Widget</h2>
 </div>
 </div>
 <!-- /.twitter-header -->

 <div class="twitter-actions">
 <div class="twitter-buttons">
 <!-- /.twitter-buttons -->
 <a href="#" class="twitter-button"><i class="fa fa-twitter"></i> Tweet this</a>
 </div> 
 </div>
 <!-- /.twitter-actions -->

 <div class="twitter-content">
 <p class="twitter-content-image">
 <img src="https://placehold.it/800x400/" alt="" class="img-responsive" />
 </p>
 <p class="twitter-content-text">
 Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. <br><br>

 It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. <br><br>

 It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
 </p>
 </div>
 <!-- /.twitter-content -->
 </div>
</section>

SCSS with custom Classes

Here’s all the SCSS you have to write to make your classes behave like Bootstrap components. It’s not pretty.

@import "../vendor/bootstrap-3.3.6/bootstrap/_mixins";
@import "../vendor/bootstrap-3.3.6/bootstrap/_buttons";

.twitter-header {
 @include make-row;
}

.twitter-header-content {
 @include make-xs-column(12);
}

.twitter-content {
 background: $brand-primary;
 color: white;

 @include make-row;
}

.twitter-content-image {
 @include make-xs-column(12);
 @include make-sm-column(6);
 @include make-md-column(3);
}

.twitter-content-image,
.twitter-content-text,
.twitter-content {
 margin-top: 1.5rem;
}


.twitter-content-text {
 @include make-xs-column(12);
 @include make-sm-column(6);
 @include make-md-column(9);
}

.twitter-actions {
 @include make-row;
}

.twitter-buttons {
 @include make-xs-column(12);
 @include make-sm-column(3);
 @include make-md-column(2);
}

.twitter-button {
 @extend .btn;
 @extend .btn-primary;
 @extend .btn-block;
}

devices

HTML with Bootstrap Classes

Now I’m going to use all core classes and 1 custom.

If you’re comfortable with Bootstrap you’ll identify them and know what’s going on without having to look at the rendered page.

<section class="container">
 <div class="row">
 <div class="col-xs-12">
 <h2>My Twitter Widget</h2>
 </div>
 <!-- .col-xs-12 -->
 </div>
 <!-- .row -->

 <div class="row">
 <div class="col-xs-12 col-sm-3 col-md-2">
 <a href="#" class="btn btn-primary btn-block"><i class="fa fa-twitter"></i> Tweet this</a>
 </div>
 </div>

 <div class="row bg-primary margin-top-1-5">
 <p class="col-xs-12 col-sm-6 col-md-3 margin-top-1-5">
 <img src="https://placehold.it/800x400/" alt="" class="img-responsive" />
 </p>
 <p class="col-xs-12 col-sm-6 col-md-9 margin-top-1-5">
 Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. <br><br>

 It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. <br><br>

 It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
 </p>
 </div>
 <!-- .row -->
</section>

It could be worse than the example above, I’ll give you that. We could have even more classes and “polluted” HTML. However, by using the core classes in my example I just had to write a single CSS class!

SCSS using Bootstrap Classes in HTML

I needed a custom margin on some elements, so I created a generic class for it.

.margin-top-1-5 {
 margin-top: 1.5rem;
}

bootstrap

Conclusions

The client shouldn’t care about the HTML

That’s our job, we as developers, can find the middle ground where the HTML is readable while keeping the CSS as performant as possible.

From the developer point of view

It’s a hassle for Frontend and Backend developers. If they’re already familiar with the core Bootstrap classes they can create components without any new CSS.

On the other hand, if you only use custom classes you’ll need someone to create all the new component custom classes, add it to the CSS pack and then build the HTML for it.

CSS footprint

It’s obviously heavier to have all those styles for each component. Here’s the result of my testing:

  • 309kb with this custom component using Bootstrap includes.
  • 289kb using Bootstrap Classes.

How much weight would we add with 10 or 20 custom components?

The Future of Icons is SVG

Scalable Vector Graphics (SVG) is an XML-based vector image format for two-dimensional graphics with support for interactivity and animation.

At this point I’m sure you have heard about font icons. You know, these icons everybody uses nowadays for social networks or just about anything a designer can think of.

font-icons-set

On our website we use them too, they’re great. Lightweight, easily customizable with CSS and specially retina ready. They will look good on any device.

tbscg-font-icons

They have some issues

Font Icons are not all that great. The styling can be tricky in some situations, they depend on styles such as:

font-size, line-height, vertical-align, letter-spacing, word-spacing

Also, in some cases they might look different depending on the client browser. As the font icons are treated as text.

Let’s kick it up a notch

On the scale of cool-web-tricks regarding graphics we have the following:

  1. Images: stay away from me.
  2. Font Icons: we’ve had a good time.
  3. SVG Icons: hello, gorgeous!

Some font icon packs already include an SVG version of the font that will be served to compatible browsers. That’s not what I want to introduce today though, I’d like to show you a more manual control over those SVG’s. Simply throwing a bunch of fonts into the project is not how the cool kids do it.

Take a look at what’s possible:

svg-vs-font

More love from SVG’s

Regarding accessibility SVG support you can use title and desc tags:

<svg xmlns=http://www.w3.org/2000/svg>
 <title>Circle</title>
 <desc>Large red circle with a black border</desc>
 <circle cy="60" r="55" stroke="black" stroke-width="2" fill="red" />
</svg>

Also, the compression by gzipping SVG’s is better than compressing fonts. However, SVG’s tend to be bigger. You’ll have to take decisions when using large set of icons, it will depend on the project and requirements.

Hang on to something, here comes your first SVG

Because I don’t want to go easy on you we’ll start with a big fat SVG:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" xml:space="preserve" 
 width="200px" height="200px" viewBox="0 0 200 200" style="enable-background:new 0 0 200 200;">
 <g>
 <g>

 <path class="first" d="M50.077,98.919l-2.78-1.024c0.219-2.027,0.147-4.093-0.234-6.146l2.684-1.237c1.677-0.771,2.412-2.765,1.639-4.441
 l-1.567-3.4c-0.772-1.676-2.763-2.413-4.437-1.641l-2.688,1.239c-1.313-1.627-2.837-3.023-4.519-4.176l1.026-2.775
 c0.638-1.731-0.25-3.661-1.98-4.301l-3.515-1.298c-1.677-0.617-3.68,0.305-4.298,1.979l-1.025,2.778
 c-2.025-0.216-4.091-0.146-6.146,0.233L21,72.024c-0.772-1.676-2.765-2.412-4.439-1.641l-3.403,1.565
 c-1.676,0.773-2.41,2.768-1.64,4.441l1.237,2.684c-1.624,1.315-3.023,2.839-4.174,4.523l-2.774-1.026
 c-1.675-0.624-3.681,0.3-4.302,1.979l-1.297,3.515c-0.309,0.84-0.273,1.749,0.1,2.561c0.376,0.812,1.044,1.43,1.88,1.735
 l2.78,1.028c-0.22,2.024-0.148,4.094,0.234,6.146l-2.687,1.237c-1.676,0.771-2.41,2.763-1.639,4.438l1.568,3.404
 c0.772,1.675,2.763,2.411,4.438,1.638l2.687-1.235c1.313,1.626,2.836,3.021,4.52,4.174l-1.026,2.777
 c-0.312,0.838-0.276,1.745,0.1,2.559c0.371,0.812,1.041,1.432,1.879,1.743l3.515,1.296c0.836,0.31,1.747,0.273,2.559-0.099
 c0.813-0.375,1.43-1.043,1.738-1.882l1.027-2.779c2.025,0.22,4.093,0.147,6.147-0.231l1.235,2.685
 c0.772,1.674,2.766,2.41,4.44,1.638l3.402-1.566c1.678-0.771,2.413-2.763,1.639-4.439l-1.237-2.685
 c1.626-1.314,3.024-2.838,4.173-4.52l2.778,1.027c0.841,0.311,1.75,0.272,2.563-0.103c0.81-0.374,1.426-1.042,1.736-1.879
 l1.297-3.515C52.695,101.488,51.807,99.56,50.077,98.919z M31.669,107.662c-1.754,0.809-3.615,1.216-5.533,1.216
 c-5.152,0-9.872-3.022-12.025-7.697c-3.052-6.631-0.144-14.507,6.483-17.559c1.753-0.809,3.614-1.217,5.529-1.217
 c5.151,0,9.875,3.021,12.029,7.697C41.204,96.733,38.295,104.609,31.669,107.662z"/>

 <path class="second" d="M83.179,108.5l-1.547-0.569c0.123-1.129,0.082-2.28-0.131-3.423l1.494-0.689c0.935-0.428,1.344-1.538,0.913-2.473
 l-0.872-1.894c-0.432-0.935-1.539-1.346-2.471-0.914l-1.497,0.689c-0.73-0.905-1.58-1.685-2.515-2.325l0.57-1.546
 c0.355-0.964-0.14-2.037-1.103-2.396l-1.958-0.722c-0.934-0.346-2.048,0.168-2.394,1.102l-0.571,1.548
 c-1.126-0.121-2.278-0.081-3.421,0.13l-0.688-1.493c-0.432-0.934-1.541-1.345-2.474-0.914l-1.895,0.873
 c-0.934,0.432-1.342,1.54-0.913,2.473l0.689,1.495c-0.905,0.732-1.684,1.581-2.326,2.519l-1.544-0.57
 c-0.931-0.347-2.049,0.165-2.394,1.101l-0.724,1.958c-0.171,0.468-0.15,0.975,0.055,1.427c0.21,0.45,0.583,0.795,1.049,0.966
 l1.547,0.572c-0.123,1.129-0.083,2.278,0.13,3.423l-1.495,0.688c-0.934,0.431-1.343,1.538-0.913,2.472l0.874,1.896
 c0.429,0.932,1.538,1.343,2.471,0.913l1.495-0.688c0.731,0.905,1.581,1.683,2.519,2.323l-0.571,1.545
 c-0.174,0.468-0.154,0.975,0.055,1.427c0.208,0.451,0.579,0.797,1.048,0.971l1.956,0.722c0.467,0.172,0.972,0.152,1.425-0.056
 s0.797-0.58,0.968-1.046l0.571-1.55c1.129,0.123,2.278,0.084,3.423-0.129l0.688,1.495c0.43,0.932,1.539,1.343,2.471,0.911
 l1.896-0.872c0.934-0.432,1.342-1.538,0.912-2.472l-0.688-1.496c0.904-0.731,1.684-1.578,2.323-2.516l1.547,0.57
 c0.468,0.175,0.975,0.152,1.428-0.056c0.449-0.207,0.795-0.581,0.967-1.047l0.722-1.957
 C84.636,109.932,84.141,108.856,83.179,108.5z M72.929,113.37c-0.977,0.448-2.012,0.677-3.08,0.677
 c-2.868,0-5.497-1.684-6.696-4.287c-1.7-3.69-0.082-8.077,3.61-9.775c0.976-0.45,2.012-0.677,3.079-0.677
 c2.867,0,5.496,1.682,6.696,4.285C78.236,107.284,76.618,111.668,72.929,113.37z"/>

 <path class="third" d="M118.269,49.597l-4.673-1.725c0.369-3.407,0.248-6.882-0.393-10.337l4.514-2.077c2.816-1.294,4.052-4.647,2.754-7.468
 l-2.634-5.718c-1.298-2.819-4.646-4.059-7.461-2.759l-4.519,2.084c-2.208-2.735-4.771-5.082-7.596-7.02l1.723-4.668
 c1.072-2.911-0.418-6.155-3.328-7.229l-5.909-2.186c-2.818-1.036-6.186,0.515-7.228,3.33l-1.724,4.673
 c-3.405-0.366-6.881-0.245-10.333,0.391l-2.08-4.51c-1.298-2.819-4.646-4.056-7.465-2.758l-5.72,2.634
 c-2.818,1.299-4.055,4.65-2.759,7.466l2.083,4.513c-2.731,2.211-5.083,4.773-7.02,7.603l-4.665-1.724
 c-2.815-1.049-6.188,0.504-7.23,3.324l-2.181,5.912c-0.521,1.41-0.46,2.938,0.166,4.304c0.634,1.364,1.758,2.403,3.163,2.917
 l4.673,1.73c-0.371,3.403-0.25,6.882,0.392,10.335l-4.514,2.078c-2.819,1.299-4.053,4.645-2.756,7.461l2.635,5.724
 c1.298,2.813,4.646,4.054,7.463,2.755l4.515-2.08c2.208,2.735,4.771,5.083,7.602,7.019l-1.726,4.669
 c-0.524,1.407-0.463,2.936,0.167,4.303c0.626,1.364,1.751,2.406,3.159,2.929l5.909,2.179c1.409,0.521,2.938,0.461,4.303-0.164
 c1.367-0.63,2.404-1.754,2.922-3.163l1.729-4.675c3.404,0.371,6.879,0.25,10.336-0.389l2.076,4.512
 c1.298,2.814,4.648,4.056,7.466,2.755l5.72-2.634c2.821-1.3,4.054-4.646,2.755-7.464l-2.079-4.513
 c2.732-2.213,5.084-4.771,7.017-7.601l4.672,1.729c1.411,0.521,2.94,0.459,4.307-0.171c1.362-0.628,2.398-1.753,2.919-3.159
 l2.184-5.911C122.671,53.914,121.178,50.67,118.269,49.597z M87.322,64.294c-2.95,1.357-6.078,2.046-9.301,2.046
 c-8.663,0-16.597-5.082-20.22-12.945C52.669,42.249,57.559,29.007,68.7,23.876c2.947-1.359,6.077-2.045,9.297-2.045
 c8.662,0,16.601,5.079,20.224,12.94C103.351,45.92,98.463,59.163,87.322,64.294z"/>
 </g>
 </g>
</svg>

Ok now, don’t be scared, it won’t bite you. This code could be inline in the HTML or on a separate .svg file.

This SVG was probably generated with a desktop software, Illustrator or something similar. Although, if you need how they work you could code basic forms by hand.

If you take a deeper look you’ll see each path has a class. We’ll use them to style it like so:

.first {
 fill: green;
}

.second{
 fill: red;
}

.third {
 fill: blue;
}

With SVG you can even use stroke-width and stroke to style the border of each element:

 stroke: #c0392b;
 stroke-width: 2px;

svg-icon-stroke

Beautiful.

Final thoughts

There is no SVG support in IE8 and in some old Android browsers. If needed, detect the browser and create a fallback.
In the other hand, if you need old browsers and you don’t actually need the extra customization SVG has to offer, stick with font icons. Once your clients drop IE8 from their requirements, you can do the upgrade.

Did you know about SVG icons? Are you using them already?

iconic-svg-icons

CSS Preprocessors and why we can’t live without them

So you’re a developer who usually writes CSS and you’re sick and tired of writing things like this:

.container .class a { color: red; }
.container .class h2 { color: blue; }
.container .class p { color: yellow; }
.container .class .another-class { color: green; }

By the end of the article you’ll be asking yourself: “What could’ve I done with all the time I’ve wasted writing CSS?”

What’s a CSS Preprocessor anyway?

A CSS Preprocessor extends the CSS language by adding features that will make your life so much easier. The code will be more maintainable, easier to read and faster to type (well, not faster but you’ll certainly type less).

If you do a quick Google search for “CSS Preprocessor” you’ll probably come across: Sass/SCSS, LESS or Stylus.
All of them, more or less, serve the same purpose with some small variations. You’ll have to choose one, lucky for you there’s no right or wrong choice.

All the code you write with this new syntax will have to be compiled into normal CSS. What great about it is that we can set minification and compression with the same process (we all know how #perfmatters).

How to have fun while writing CSS

At TBSCG we use Sass when we need to bring out the big guns. With that said, CSS Preprocessors aren’t usually used when you need to do a small change in an existing project using regular CSS. Once again it’s up to you, if you think you’re going to edit this on a daily basis perhaps you should consider creating a .scss file. One cool thing is that SCSS syntax is superset of CSS so you can actually paste regular CSS into a SCSS file and compile it. It won’t be any different but then you could use SCSS syntax for the new pieces of code.

The wait is over, what are those features I’ve been talking about?

Variables

We can create our own variables. Yes, like in a “normal” programming language. We usually create a specific file where we write all our variables so we can easily keep a track of them.

$global-font-family: Helvetica, sans-serif;
$main-color: #333;

body {
  font-family: $global-font-family;
  color: $main-color;
}

You’re welcome! And there’s more where that came from.

@import, let’s keep it clean

I’ve mentioned different files, it’s a good practice to separate your components SCSS into different files. It will be easier to maintain and it’s great for collaboration. Don’t worry, all those files will only generate one CSS compiled file.

You could have your main.scss with this:

@import "components/header";

Which will be fed from components/header.scss

Nesting

Using the example from the beginning of the article we could’ve written it like this:

.container {

    .class {

        a {
            color: red;
        }

        h2 {
            color: blue;
        }

        p {
            color: yellow;
        }

        .another-class {
            color: green;
        }
    }
}

Once compiled it’d look like so:

.container .class a{ color: red; }
.container .class h2{ color: blue; }
.container .class p{ color: yellow; }
.container .class .another-class{ color: green; }

Nesting allows us to save a lot of writing. You have to be carefull though, with this feature it’s easy to overdo creating too many selectors and children. Sometimes a root level class will be more than enough.

Functions and Mixins

So yes, we can create our own functions. Like you would expect, this functions accept parameters and will help you reuse code and write less.

They can do anything you want, i.e. change string to int:

@function parseInt($n) {
  @return $n / ($n * 0 + 1);
}

We can call functions like normal function, ie.:

.class {
  line-height: parseInt(3.5px);
}

Which once compiled will look like:

.class { line-height: 3.5; }

There are also some “special” functions called mixins, we can use them with the @include directive.

@mixin opacity($opacity) {
  opacity: $opacity;
  // IE8 filter
  $opacity-ie: ($opacity * 100);
  filter: #{alpha(opacity=$opacity-ie)};
}

.element {
    @include opacity(.5);
}

Browser prefixing is a pain, we can ease our agony creating a Mixin:

@mixin translate($x, $y) {
-webkit-transform: translate($x, $y);
  -ms-transform: translate($x, $y);
   -o-transform: translate($x, $y);
      transform: translate($x, $y);
}

.element {
    @include translate(200px, 300px);
}

Mixins can also be used without any parameter. Let’s say we need to do some calculations or set styles, something we’ll be using over and over:

@mixin center-block() {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.element {
    @include center-block();
}

Mixins can have default content so it can be easily used to extend/wrap some piece of code, i.e. keep all breakpoints in one place and easily maintain them:

@mixin breakpoint($name) {
  @if $name == very-small {
    @media only screen and (max-width: 29.95em) { @content; }
  }
  @else if $name == tablet {
    @media only screen and (min-width: 30em) { @content; }
  }
  ...
}

@include breakpoint(very-small) {
  .sth {
    font-weight: 700;
  }
}

There’s even more

Each language comes with a long list of core functions such as darken() or lighten(), with this two functions we can change the colors using percentatges:

.class{
    color: darken($main-color, 20%);
}

This is great to create themes from two or three base colors. Designers get onboard!

If the core functions aren’t enough for you and you need more power, check out Compass. I’ll just quote the description:

Compass is an open-source CSS authoring framework which uses the Sass stylesheet language to make writing stylesheets powerful and easy.

My recommendation would be to first to get a sense of Sass and then take a look at Compass.

I’m sold, how do I compile this things?

If you’re friends with the command line it’s probably the fastest way to get you up and running. If you prefer a GUI there’s also Windows and Mac clients to deal with this files. Check out each language site for their How to Install guides.

Final thoughts

At this point I hope you’re convinced of the power of the CSS-Preprocessors. Like anything in the dev world you’ll have to learn it first, there’s no way around it. As you have already seen it’s not hard and the benefits you get from it are great.
In the end this tools help us be more efficient with our work and allow us to optimize our time.

What about you, do you already use a CSS Preprocessor?

Resources to get you started