Showing Color Chips From Sass Variables

At Causes we like to make our code more maintainable by building reusable components. Part of this strategy includes assigning variable names to hex colors using Sass. This allows us to more easily reuse the same colors everywhere, which improves consistency and makes it easier to re-color the entire site when our design needs change.

To increase the visibility of these reusable components, we’ve been building out a collection of things that designers and engineers can reference, drop in to projects, and iterate upon. The code sits next to the rendered version, allowing people to easily see the implementation required to produce the result. We call this collection the component gallery. It helps us do more with less code, be more consistent, and iterate on global changes more easily and effectively.

When we started fleshing out the color variables we wanted to use throughout the site, it seemed natural to show these colors in the component gallery as Pantone color chips. That way, designers could reference the colors that we are using, we’d have a single place to see that all of the colors look great next to each other, and engineers could easily pluck variable names when implementing designs to match the mocks.

The quick solution would have had us defining these colors in two places: once in Sass, where we actually need to use them, and again in Ruby, where we want to render them on a page. However, we sensed that this would be a pain to maintain and the two different definitions would quickly fall out of sync.

To resolve these issues, we decided to move our color variables into their own Sass partial, and use Sass to parse it to display the colors and their variables. Since we like to use functions like darken(), lighten(), and scale-color(), we needed a solution that would actually execute the Sass and use the result.

So we built a Sass Visitor to evaluate variables and return pairs of names and values:

1
2
3
4
5
6
7
8
9
10
11
class SassVariableEvaluator < Sass::Tree::Visitors::Base
  def visit_comment(node)
    # prevents empty arrays from being in the returned array
  end

  def visit_variable(node)
    @environment ||= Sass::Environment.new
    @environment.set_local_var(node.name, node.expr)
    [node.name, node.expr.perform(@environment)]
  end
end

Then we have our SassVariableEvaluator visitor evaluate the variables in our colors Sass partial:

1
2
3
4
def color_variables
  engine = Sass::Engine.for_file('path/to/_colors.css.scss', syntax: :scss)
  SassVariableEvaluator.visit(engine.to_tree).compact
end

Looping over those evaluated variables in our view generates the desired markup:

1
2
3
4
5
.clearfix
  - color_variables.each do |name, value|
    .pantone
      .chip{ style: "background-color: #{value};" }
      %var $#{name}

And style them nicely:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.pantone {
  @include box-shadow(0 0 5px rgba(0, 0, 0, .1));
  border: 1px solid #eee;
  float: left;
  font-size: 11px;
  margin: 0 1em 1em 0;
  width: 145px;

  &:nth-child(4n) {
    margin-right: 0;
  }

  .chip {
    background: #f00;
    height: 145px;
  }

  var {
    display: block;
    font-style: normal;
    font-weight: bold;
    height: 40px;
    padding: .75em;
  }
}
Joe Lencioni