In the previous videos, we saw how to improve our workflow using Sass mixins. Now it's time to see the power of functions, and what else we can accomplish with Sass. Before getting started, the inspiration for this practice came from Una Kravets: Let’s Build a CSS Game . If you haven't seen it, I recommend you take a couple minutes to watch. Una Kravets is amazing, and that talk was great. This is what we're going to create: an 8-bit animated character. Let's get started!
The first thing we're going to do is to create our project folder. I’ll also create an assets folder with a subfolder for stylesheets. Inside the stylesheets, we’ll create a couple more folders for components and characters. Now, we create an
index.html
file and
_variable.scss
,
_functions.scss
,
_tools.scss
,
_normalize.scss
, which are going to be imported in
application.scss
like this:
@import "variables";
@import "characters/*.*";
@import "functions";
@import "tools";
@import "normalize";
@import "components/*.*";
The order is important. Notice that we are going from logic to property definition, by making variables the bottom level. Then, functions and mixins, which interact with those variables, the mid level. Lastly, the actual styling, which is the top level.
Now, open
index.html
and we're going to create a
div
with the class
character-container
. Then we add an
h1
with
title
as class. Finally we create the class for our character. He’s our CTO, Adam. So, I will call it
pixel-adam
. Lastly we add
application.css
to our head.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="assets/stylesheets/application.css">
<title>Sass Features</title>
</head>
<body>
<div class="character-container">
<h1 class="title">Pixel Adam</h1>
<div class="pixel-adam">
</div>
</div>
</body>
</html>
With this, we have everything we need to start styling our pixel character. Now, what we're going to do is to open our
variables
file and define a map of colors, which are the ones our character will use. Every color is linked to a key; we'll use these keys to set a color for each pixel. After that, we define a size for the pixels. I'll use
1rem
as the default size. It's important to highlight that from now on, everytime I say
pixel
I'll be' referring to a pixel square of the size we just defined.
$colors: (
"background": #3e4c61,
"r": red,
"b": black,
"m": #c27a2e,
"n": #774c2a,
"j": #331a13,
"f": #1c74bb,
"g": #2db572,
"d": #251f21,
"s": #fdbe9f,
"v": #e5b180,
"z": #c69869,
"t": transparent,
"w": white,
"a": #b27a5d
);
$pixel-size: 1rem !default;
Inside our characters folder, we need to create a file for pixel Adam. I'm going to call it
_pixel-character.scss
. Here we will do another map, but this time for the character itself. Basically we draw the character using the
keys
we defined before for each color:
$pixel-character: (
adam: (
( t t t t t d d t t t t t t d d d d d d t t t t t t t t )
( t d d t d s s d t t t d d s s s s s s d d t t t t t t )
( d s s d d s s d t t d s s s s s s s s s d t t t t t t )
( d s s s d s s d d d s s s s s s s s s s s d d t t t t )
( t d s s s d d d d d s s s s s s s s s s s s s d t t t )
( d s s s d s s s d s s s s s s s s s s s s s s d t t t )
( d s s s d s s s d b b b b b b b b b b b b b b d t t t )
( d s s s s d d s d s s b b b b b b b b b b s s d t t t )
( t d d s s s s d s s s s b b b s s b b b s s s s d t t )
( t t t d d d d d s d s s s b s s s s b s s s d s d t t )
( t t t t d s s d s d s s s s s s s s s s s s d s d t t )
( t t t t d s s s d d s m m m m m m m m m m s d d t t t )
( t t t t t d f f f f m m m s s s s s s m m m d t t t t )
( t t t t t t d f f f m m m s w w w w s m m m d t t t t )
( t t t t t t t d f f f m m s s s s s s m m d t t t t t )
( t t t t t t t t d f f f m m m m m m m m f d d t t t t )
( t t t t t t t t d f f f f m m m m m m f f f f d t t t )
( t t t t t t t t t d f f f f m m m m f f f d d s d t t )
( t t t t t t t t t t d f f f d m m d f f d s s s d t t )
( t t t t t t t t t t d f f f d d d d f f d s s s d t t )
( t t t t t t t t t t d f f f f f f f f f d s s d t t t )
( t t t t t t t t t t d f f f f f f f f f f d d t t t t )
( t t t t t t t t t d n n n n n n n n n n n n d t t t t )
( t t t t t t t t t d n n n n n n n n n n n n d t t t t )
( t t t t t t t t d n n n n n n n n n n n n n n d t t t )
( t t t t t t t t d n n n n n j j j j n n n n n d t t t )
( t t t t t t d d d n n n n j j j j j j n n n n d d d t )
( t t t t t d b b b b b b b b d t t d b b b b b b b b d )
( t t t t t d d b b b b b b d d t t d d b b b b b b d d )
( t t t t t t d d d d d d d d t t t t d d d d d d d d t )
)
If you look closely, you can see the details, like his beard and glasses. Something important to notice here: every key in the map represents a pixel, which is
1rem
, and each key has its own value, a color. Which means we have
1rem
of whatever color the key represents. So we just have to go through the map, replace each key for its value, and assign all that to a CSS property we can hack... But, how can we do that? Well, luckily for us, Sass has lots of useful
methods
that will help us. We can also use
loops
and
conditionals
, so we have everything we need to make a function that does what we want.
Now, we open our
functions.scss
file and define a function called
build_character
. This function will have two parameters: our character color map and the size of the pixels.
@function build_character($character_draw, $size) {
}
We're going to use
box-shadow
to draw our character. The main reason is because it’s easy to hack. Due to how it works, we can define an indefinite quantity of shadows and use any color we want. So, let’s take advantage of that. Inside our function we define a variable called
$character
. This will contain our character draw, which is going to be a bunch of shadows simulating pixels.
The first thing we need to draw our character is to get the total number of rows from our map. To do so we can use a Sass method called
length
, which returns the size of a given map. Once we have the total number of rows, we can iterate through our character map using
@for
:
@function build_character($character_draw, $size) {
$character: "";
$rows: length($character_draw);
@for $row-num from 1 through $rows {
}
}
We define a variable called
$row-number
which we’re going to use to get the values from each row. For that we use another Sass method,
nth
, which returns a specific item in a list. We pass our character map and our
$row-number
to get the complete row with all its values, which are the color keys we defined for our character. Then we iterate through that row to get the columns (which are our color keys). To determine how many times the process should repeat we use
length
again, which will return the total number of columns inside every row.
@function build_character($character_draw, $size) {
$character: "";
$rows: length($character_draw);
@for $row-num from 1 through $rows {
$row: nth($character_draw, $row-num);
@for $col from 1 through length($row) {
}
}
}
Now that we have access to the columns, we can get every color key in our map, one by one. Let’s define a variable called
$color-key
. Then use
nth
again to get the item passing the
row
and the
column
as arguments.
@function build_character($character_draw, $size) {
$character: "";
$rows: length($character_draw);
@for $row-num from 1 through $rows {
$row: nth($character_draw, $row-num);
@for $col from 1 through length($row) {
$color-key: nth($row, $col);
}
}
}
Now we can build our shadows. We can define the horizontal and vertical position of the shadows using the first and second parameter from
box-shadow
. We can define the color with the third. Knowing that, we can take advantage of it. The first parameter will be equal to
pixel-size * column
, the second will be equal to
pixel-size * row-num
, and the third will be a
map-get
passing our colors map and current color-key as arguments.
@function build_character($character_draw, $size) {
$character: "";
$rows: length($character_draw);
@for $row-num from 1 through $rows {
$row: nth($character_draw, $row-num);
@for $col from 1 through length($row) {
$color-key: nth($row, $col);
$character: $character + ($size*$col) + " " + ($size*$row-num) + " " +
map-get($colors, $color-key);
}
}
}
What we're doing is creating a shadow and moving it a "pixel" to the right for each
color-key
contained in one row. Once there are no more
color-keys
in that row, we lower the vertical position of the shadows one "pixel". Then, repeat the process with the next row of
color-keys
until there are no more rows. To define the color of every "pixel" we’ll use
map_get
with the array of colors we defined before and the
color-key
we're getting from the loop. To link all that together, we use the
+
operator and empty spaces.
This isn’t going to work, but why? Well, the shadows need to be separated by commas — except for the last shadow, which can't have a comma because if it does, it'll invalidate all the shadows. We're iterating through rows and columns, so we can use a negated conditional, which will be triggered every iteration. This will verify if we aren't in the last column of the last row. If that's the case, we add a comma to our
character
variable. Finally we return the
character
, which will be our
box-shadow
value. We're going to use
unquote
because
box-shadow
doesn't accept strings as values.
@function build_character($character_draw, $size) {
$character: "";
$rows: length($character_draw);
@for $row-num from 1 through $rows {
$row: nth($character_draw, $row-num);
@for $col from 1 through length($row) {
$color-key: nth($row, $col);
$character: $character + ($size*$col) + " " + ($size*$row-num) + " " +
map-get($colors, $color-key);
@if not ($col == length($row) and $row-num == $rows) {
$character: $character + ",";
}
}
}
@return unquote($character);
}
Finally we create a
_pixel-adam.scss
file inside
components/
, and define a pseudo element
after
. We give it a
height
and
width
equal to the
pixel-size
we defined. Set
position
to
absolute
, and use our function, passing our map character and the
pixel-size
as arguments.
.pixel-adam {
&:after {
content: "";
height: $pixel-size;
position: absolute;
width: $pixel-size;
box-shadow: build_character(map-get($pixel-character, adam), $pixel-size);
}
}
Boom! We have our 8-bit character! This was a fun way to see how functions works in Sass. We still have to do a lot of stuff to improve our character. So, we're going to stop here, and continue in the next video. See ya!
Comments for Build your own 8-bit character using Sass Part I