Thumb bruno Bruno Bušić Thursday, September 8, 2016

There are many useful ways to use Sass lists and maps in frontend development, why not doing something just for fun? In this blog post, you will learn how to build pixelized characters using only the box-shadow attribute and the power of Sass.

The second one and the final blog post in a mini series of post on Sass lists and maps. If you missed the basics, read them up here.

Gotha Teach Them All

First of all, you will probably never ever have any practical usage from pixelized CSS Pokémon per se. However, you will benefit from the knowledge and hands-on practice needed for building it.

Box Shadow Pixels

Feel free to freshen up on box-shadow property. Basically, the property describes one or more (this is very important!) shadow effects as a comma-separated list. You can cast a shadow from the frame of almost any element.

Let's try to cast several box shadows, here's the codepen:

See the Pen Box shadow example 01 by Bruno (@3mpetri) on CodePen.

Since the first box shadow is actually below the element, we can shift the element itself left and up by making it absolutely positioned.

See the Pen Box shadow example 02 by Bruno (@3mpetri) on CodePen.

Creating a Matrix-like-list

A matrix-like-list is just a list made of lists of the same length. If we use the space separators and parenthesis, it will look like this:

$matrix-like-list: (
(x o o o x)
(o x o x o)
(o o x o o)
(o x o x o)
(x o o o x)
);

X marks the spot. How do we generate a CSS box shadow grid out of this? Simply by looping through the list and checking the value of the individual element. For starters, we'll simply color the 'x' fields, while skipping the 'o'. This will be done with the pokemonize function. Yes, pokemonize, I don't even care anymore how childish all of this sounds like. Never lose your inner child! :) If you never used Sass functions before, well, read it up.

@function pokemonize($matrix-like-list, $size: $pixel-size, $color: $color--primary) {
$length: length($matrix-like-list);
$pixels: "";

@for $i from 1 through $length {
$row: nth($matrix-like-list, $i);

@for $j from 1 through length($row) {
$item: nth($row, $j);

@if $item == x {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + $color;
}

@else {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + transparent;
}

@if not ($j == length($row) and $i == $length) {
$pixels: $pixels + ',';
}
}
}

@return unquote($pixels);
}

Let's break it down a bit.

@function pokemonize($matrix-like-list, $size: $pixel-size, $color: $color--primary)

We are forwarding to our function three parameters, the first one is the most important one - the list of lists that forms our final output. We also need the size of each pixel and its colour. We are simply defaulting it to predefined variables.

$length: length($matrix-like-list);
$pixels: "";

Next, we're initializing $length variable for looping through the matrix and $pixels string for final box-shadows output. In order to get all the elements of a matrix, we need two nested for loops. The first one will loop through the rows, and the second one will get each individual item inside the current row. This leads us the "meat" of our function:

@if $item == x {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + $color;
}

@else {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + transparent;
}

@if not ($j == length($row) and $i == $length) {
$pixels: $pixels + ',';
}

Once we reached an individual item, all that's left is checking whether it's "x" or not, and generate the appropriate box shadow. The last condition places a comma between each box-shadow value, UNLESS it's the last one (where vertical counter equals the number of rows, and horizontal counter the number of columns).

Output of $shadows variable, when initialized with the pokemonize, is as follows:

1rem 1rem #679E17, 2rem 1rem transparent, 3rem 1rem transparent, 4rem 1rem transparent, 5rem 1rem #679E17,
1rem 2rem transparent, 2rem 2rem #679E17, 3rem 2rem transparent, 4rem 2rem #679E17, 5rem 2rem transparent,
1rem 3rem transparent, 2rem 3rem transparent, 3rem 3rem #679E17, 4rem 3rem transparent, 5rem 3rem transparent,
1rem 4rem transparent, 2rem 4rem #679E17, 3rem 4rem transparent, 4rem 4rem #679E17, 5rem 4rem transparent,
1rem 5rem #679E17, 2rem 5rem transparent, 3rem 5rem transparent, 4rem 5rem transparent, 5rem 5rem #679E17;

It's a mess once transpiled from Sass, but that's the reason why we're using functions, lists and maps, we don't care how the output looks like, only the abstraction.

You can dabble around with it in CodePen:

See the Pen Pokemonize 01 by Bruno (@3mpetri) on CodePen.

Let's Pour Some Colors Into the Mix

Color pixels

Currently, we only handle x or o, filled or transparent, hot or cold, yes or no. in or out, up or down ♫. In order to implement colours, we have to replace x values with corresponding color symbols. For our Pokémon we'll need blue (b), pink (p), red (r), and black (k). Can you guess which Pokémon this is?

(o o k k k k o o o o o o o o o o o o o o o o o k k k k o o)
(o o k p p p k k o o o o o k k o o o o o o k k p p p k o o)
(o o k p k p p p k o o k k p p k k o o k k p p p k p k o o)
(o o k p k k p p p k k p p p p p p k k p p p p k k p k o o)
(o o k p k k k p p k p p p p p p p p p p p p k k k p k o o)
(o o o k p k k k p k p p p p p p k p p p p k k k p k o o o)
(o o o k p k k p p k p p p p p k p k p p p p k k p k o o o)
(o o o k p p p p p p k p p p k k p k p p p p p p p k o o o)
(o o o k p p k k k k k p p p p p p k k k k k p p p k o o o)
(o o o k p k k o o k k k p p p p k k o o k k k p p k o o o)
(o o k p k b k o o k k k k k k k k k o o k k b k p p k o o)
(o o k p k b k k k k k k p p p p k k k k k k b k p p k o o)
(o o k p k b k k k k k k p p p p k k k k k k b k p p k o o)
(o o k p k b k k k k k k p p p p k k k k k k b k p p k o o)
(o o k p k b b k k k b k p p p p k b k k k b b k p p k o o)
(o o k p p k b b b b k p k k k k p k b b b b k p p p k k o)
(o k k p p p k k k k p p k r r k p p k k k k p p p p p p k)
(k p p p p p p p p p p p k r r k p p p p p p p p p p p p k)
(k p p p p p p p p p p p p k k p p p p p p p p p k p p k o)
(o k p k p p p p p p p p p p p p p p p p p p p p p k k o o)
(o o k k k p p p p p p p p p p p p p p p p p p p k o o o o)
(o o o o o k p p p p p p p p p p p p p p p p p k o o o o o)
(o o o o o o k k p p p p p p p p p p p p p k k o o o o o o)
(o o o o o o o o k k k p p p p p p p k k k o o o o o o o o)
(o o o o o o o o k p p k k k k k k k p p k o o o o o o o o)
(o o o o o o o k p p p p k o o o k p p p p k o o o o o o o)
(o o o o o o k p p p p k o o o o o k p p p p k o o o o o o)
(o o o o o o k p p p k o o o o o o o k p p p k o o o o o o)
(o o o o o o o k k k o o o o o o o o o k k k o o o o o o o)

We only need to extend the conditional that outputs the requested color, like so:

@if $item == b {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + $color--blue;
}

@else if $item == p {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + $color--pink;
}

@else if $item == r {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + $color--red;
}

@else if $item == k {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + $color--black;
}

@else {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + $color--none;
}

Take a look at the Codepen, it was Jigglypuff if you didn't recognise him! :)

See the Pen Pokemonize 02 by Bruno (@3mpetri) on CodePen.

DRY It Out

Every time you notice a repetition in your code, your developer's alarm should go off. Is there anything we can do with colours? We could create a map of symbol - color values and fetch the color with map-get().

$color-map: (
'b' : $color--blue,
'p' : $color--pink,
'r' : $color--red,
'k' : $color--black,
'o' : $color--none
);

map-get($color-map, 'b');
//returns $color--blue

And now the drying up. We can replace all of the if and else statements with this:

@if map-has-key($color-map, $item) {
$pixels: $pixels + ($j*$size) + ' ' + ($i*$size) + ' ' + map-get($color-map, $item);
}

And our final CodePen:

See the Pen Pokemonize 03 by Bruno (@3mpetri) on CodePen.

Where Do I Go From Here?

Well, if you would like to play around with Sass maps some more, a great idea would be to create a pixel map of characters that plots onto appropriate classes named after Pokémon! For example, you would have a map of key - value pairs, where the key would be Pokémon's name, and the value would be a pixel matrix of that Pokémon. You could easily generate classes that correspond to Pokémon names in the map and voila - the function would automatically output any Pokémon defined in the map.

If you like to play around with JS, I double dare you to create a clickable matrix that outputs pixel maps. Wouldn't that be great? :)

All the credit for this idea goes to Una Kravets and her amazing blog post on the same subject. I'll leave you off with a Sass dancing banana.

See the Pen PBJ Banana dance in Sass by John W. Long (@jlong) on CodePen.



Cookies help us deliver our services. By using our services, you agree to our use of cookies.