Create Striped Backgrounds With Gradients (and a Sass Mixin)

The following is a guest post by Hugo Giraudel. Hugo has written several times for CSS-Tricks including an article about a rather clever Pie Timer and several entries for the Almanac. I'm glad to have him back, this time explaining some pretty hardcore Sass stuff with a really practical application.

Hey guys! I'm glad to be able to write for CSS-Tricks again and share some cool tricks about Sass! In the past few weeks, I've been intensively experimenting with Sass lists. I have found a lot of things that likely most people don't know.

I recently built a @mixin to create stripes. The idea is to give the mixin a regular gradient and it will turn it into a striped one. Since it turned out to be a fairly complicated thing to do, I thought it could be a good idea to write up.

Let's begin with some reminders about how gradients work.

Striped Gradients

When you give a gradient two succesive color-stops with the same stop value, the transition between them two is abrupt instead of smooth. It is technically a gradient, but there is no smooth transition from one color to another. Consider the following code:

The Striping Mixin

Let's get to the point of the article: our striping mixin! The main idea is to take advantage of the fact Sass lists can be comma-separated, just like color-stops in gradients. To put it simple, a list like $list: red 20%, blue 55% could be used in a linear-gradient() function as is: linear-gradient($list) outputing linear-gradient(red 20%, blue 55%).

Because we're badasses, we want to make it as flexible as possible. So:

we can define a collection of color-stops

we can define a list of colors if we want all the stripes to have the same size

we define a direction as a default so we can ommit it in some cases

Thus we need two things to turn a regular gradient into a striped one: the list of colors / color-stops (e.g. deepskyblue, tomato, lightgreen or deepskyblue 20%, tomato 35%, lightgreen 62%) and an optional direction. Let's start with the skeleton:

The user passes a comma or space-separated list of colors: (deepskyblue, tomato, lightgreen),

The user passes a single color: deepskyblue or (deepskyblue).

Everything else will either dump out invalid output or throw a Sass error. The mixin is meant for informed developers in a development environment so it's really no big deal if we don't cover every single edge case.

The very first thing we have to find out is whether we are dealing with a list of colors or a list of color-stops. The easiest way to find out is to check the first item in the $color list (with type-of()). If it is a list, then we have to deal with color-stops else the user wants all stripes to have the same width and it's pretty easy for us.

Unfortunately, we cannot do $auto : !(type-of($first-item) == list) since Sass doesn't recognize this as valid syntax. So to check, we can use the if() Sass function which comes close to the var = condition ? true : false statement of other languages.

$auto: if( type-of(nth($colors, 1)) == list, false, true );

To sum up, if $auto is true, it means all stripes will have the same size so the calculations are handled by Sass. If it's false, it means we have to deal with custom stops. We still need two variables before looping through colors: one in case we are running in auto-mode to define the size of a stripe; and one to store our color-stops while looping (later used in a linear-gradient function).

Now we can loop through colors / color-stops and add things to our $gradient variable. To add a numeric component to our loop, we use a @for loop instead of a @each loop. It doesn't make things much harder though. We also declare 2 new variables inside the loop: one for the current item and one to store the current color-stop before appending it to $gradient.

This is where things get complicated. First, we have to differenciate auto mode from hard mode: color-stops are not the same. In auto mode, they are calculated which means in the first loop run (when $i equals 1) the "previous color-stop" equals 0% ($stripe-width * ($i - 1)). In hard mode, we have to check whether we're in the first loop run or not because nth($colors, 0) isn't allowed; it throws a Sass error. Let's check the code:

At the end of the loop, we have a well formated list ready to be used in a linear-gradient. We can now safely use it as background-image. Even with the Compass built-in mixin to output all the prefixes. Here is the whole mixin now:

Demo

As a demo, I took the header of Treehouse's blog: a line made of about 50 colored stripes. It looks absolutely lovely. They currently use 50 spans. Ouch! They could use stripped gradients instead, and it's easy now with this mixin.

I made two versions: the first one is running in auto-mode, meaning all stripes have the same width; the second one use custom color-stops to reproduce Treehouse's effect.

Final words

I think we're done team. If you prefer a function to a mixin, it is fairly easy to edit: simply change @mixin to @function and the background-image line to something like @return linear-gradient(#{$gradient}, #{$linear}) then use it with background-image: stripes($colors). I personally prefer using a mixin, but it's really up to you.

What do you think?

If you feel like you could make the code easier, please be sure to tell! Thanks for reading. :)

I love this CSS gradient example above, and naturally if that wasn’t possible I think I’d fall back to an image. But Peter’s comment has be itching to brainstorm. What are some other crazy ways to do this?

About using spaces as a separator. I’m horribly lazy, so I’ve done that a lot. Which is how I found out that a list like this $l: 5 -$a 7 doesn’t work out right – test (the second one, the one with the rotate transform).

Clever idea, using a mixin to make it easier to build stripes. (I definitely think a gradient or other sort of background image is way better than fifty <div>s as well.) Just a couple thoughts:

You don’t need to use if(condition, false, true) to emulate ! — the ! operator in Sass is not. Therefore all you’d need is

$auto: not (type-of($first-item) == list)

Another way of doing it is

$auto: length($first-item) == 1

which tests to see if it is a list by its length. (Another weirdness to add to your list of list weirdnesses is that individual values can be treated as single-item lists in a lot of places, like the list functions.)
The reason strings can be unquoted in Sass is that they can be unquoted in CSS — as long as they don’t have any weird characters in them.
I think it’s handy to be able to refer to lists with either spaces or commas, because again, that’s how CSS does it. Tuples in CSS (e.g., a list of values for a background shorthand) are space-separated, and groups of them (e.g., multiple sets of values for the same shorthand) are comma-separated. In Sass you can nest lists as deeply as you like with sets of parentheses.

This is pretty awesome-thanks for sharing. Can’t follow everything yet because I’m still a beginner but I’m getting there. Also, do you need to be signed in to Codepen for those pens to work? Because I’m getting an image of a man with a magnifying glass saying ‘there’s nothing here’.

The examples don’t seem to work et all on Safari on latest iOS (6.1.4) on iPhone5. If it is indeed a matter if prefixes, could you fix the code pens? The article doesn’t have to mention them, but it makes it more attractive if the demos actually worked on a modern browser a developer is using to read this, else you’ll make me think this is a CSS feature I can’t even realistically use for a dev-audience.

*** Delete from here down after reading ***
Chris (or moderator) on the blog home page “striped” is spelled “stripped” – don’t hate me for being such a word nerd. I love this site, don’t want anyone thinking ill of you ;)

@Jimmy: Since we’re in language-nazi mode, I feel compelled to point out that Chris didn’t get ‘colour’ wrong, as he’s an American and ‘color’ is acceptable spelling there :-) After all, let’s face it: English spelling is messed up anyway.

This is pretty cool, however I can understand how this could create issues with older browsers. Don’t get me wrong this it a great little article but at the minute id just rather use “background-image… repeat…”.

True, but why couldn’t you use a fallback technique for older browsers? I think more developers need to embrace new technologies to properly move along HTML5/CSS3 and get it FULLY out of the door and into practise.

Well, first of all, this would never cause issues in old browsers. At worst, the gradient simply isn’t display. Since this is clearly a graphical element, it is no big deal.

Now as Richard said, this is progressive enhancement. Serve an image or even a flat border to old browsers, and this solution to modern ones. This can save a HTTP request to browsers which support gradients; it is a big deal.

I didn’t use the functions, but the first part of the article inspired me to make a css gradient version of the uk flag. I think it turned out quite nice. Tricky bit was handling the non-symetrical diagonal striping http://cdpn.io/GAKty

This comment thread is closed. If you have important information to share, please contact us.

We have a pretty good* newsletter.

Email Address

CSS-Tricks* is created, written by, and maintained by Chris Coyier and a team of swell people. It is built on WordPress, hosted by Media Temple, and the assets are served by MaxCDN. The fonts are Source Sans Pro and Source Code Pro. It is made possible through sponsorships from products and services we like.