Design
Using a Matrix to Generate Sprite Map SASS
I'd like to show you a SASS technique that I've been waiting to implement myself first in a client project, but so far have been unable to. I cannot wait any longer; I must share this awesomeness with all of you!
Let's say you have an image sprite of country flags that will be used to display which locale your internationalized site is currently in. Your designer hands you a sprite map all made up, but this time it's different. Instead of each flag being laid out in one row or column for you to easily iterate over like we learned in a previous blog post, we have rows of 5 flags each. You may be shouting "FFFFUUUU" at this point while thinking how much trouble it's going to be to recut this sprite map as a single row or column in order to use your awesome SASS trick. There is a way to work with it as is, however.
For this solution to work, we need to employ a new control directive and built-in SASS function. We're going to use the @for loop rather than an each loop to run from 0 to the length of each direction in our flag matrix. We'll then use a SASS function called nth that will let you pull the nth element in an array in SASS.
To start, let's create our styles for an individual flag. We're using a subset of the Famfamfam flag set as a sprite sheet, so we're going to style our anchors based on their dimensions.
ul.flags
overflow: hidden
width: 90px
li
float: left
padding: 0 2px 2px 0
a
display: block
width: 16px
height: 11px
text-indent: -8685px
overflow: hidden
background: transparent url("/images/famfamfam_flag_icons/example.png") 0 0 no-repeat
Nothing too fancy. We're using an image replacement technique to give dimensions to the anchor and hide the text within it in favor of the icon background. In the HAML I'm creating these links with a title attribute that tells me which country each flag is from.
- @flags = { ca: "Canada", cn: "China", de: "Germany", uk: "England", es: "Spain", fr: "France", it: "Italy", nl: "Netherlands", se: "Sweden", us: "United States of America" }
%h1 Country Flag Sprite Matrix
%ul.flags
- @flags.map do |cc, name|
%li= link_to name, "#", class: cc, title: name
Next, we're going to define our rows and columns based on the class names we've given each flag. In SASS we would define our rows in variables, then define our matrix using those rows. SASS will allow you to skip the comma separators in these declarations, but they read and scan much easier with them.
$row_1: ca, cn, de, uk, es
$row_2: fr, it, nl, se, us
$flags: $row_1, $row_2
We'll then iterate over the flags matrix with two for loops. There are two keywords, to and through, that you use when defining a for loop in SASS. through is inclusive, meaning it will go up to and including the last value in the range. We're going to use to for the purpose of setting the x and y positions of our background.
a
background: transparent url("/images/famfamfam_flag_icons/example.png") 0 0 no-repeat
@for $y from 0 to length($flags)
@for $x from 0 to length(nth($flags, $y + 1))
&.#{nth(nth($flags, $y + 1), $x + 1)}
background-position: (-$x * 16px) (-$y * 11px)
In the first for loop, we'll run from 0 to the number of rows read from calling the length function and passing the $flags matrix. We then start a for loop to iterate over that row's elements up to its length. A little bit of calculation based on the width and height of the icon, and we've got a properly positioned background image for each country code. Check out the example page.
When time permits, I'll create a version of this demo with the entire flag set loaded in for anyone that needs it. Follow me to find out where you can get it at when I'm done. In the meantime, get going on those sprite matrices!