Practical Sass Loops

Using loops within Sass 3.3 to generate link icons

Tim Knight
Developing with Sass

--

I’m an absolute advocate for Sass (I’m talking about Syntactically Awesome Stylesheets, but other kinds of sass are just as entertaining). I was first introduced to it while programming Rails and have since adapted it to every web project workflow I have—whether easy to accommodate or not.

Recently while speaking with a designer friend of mine we started talking about practical uses for the @each, @for, and @while functionality within the language. While common to developers, I’ve found many designers have trouble seeing their helpfulness within the UI portion of web construction.

Is it really practical?

First it’s important to point out that conditional flows and loops are extremely important and practical when developing mixins and modular functionality within your Sass projects, but what I wanted to do was answer the question, “Is there a practical way that the average designer could understand the benefits of having loops in Sass?”

Understanding the Basics

Before I get started, it’s important to understand a few concepts about CSS and Sass. First, attribute selectors in CSS allow us to select a element based on an attribute of that element outside of just its ID or class. For example:

<a href="http://www.facebook.com">Facebook.com</a>

The href would be an attribute containing a value of “http://www.facebook.com”. While there are several different attribute selectors, here are three of the most commonly supported.

Begins with: a[href^="http://"] { }
Matches an href attribute that begins with 'http://'.
Includes: a[href*="facebook"] { }
Matches an href attribute that contains the text 'facebook' anywhere in the value.
Ends with: a[href$=".com"] { }
Matches an href attribute that ends with the value '.com'.

I’ll be using the “includes” and “ends with” selectors throughout this Sass exploration.

One final thing I want to make sure you’re familiar with are Sass placeholders. Basically a placeholder is a snippet of code that isn’t included in your code unless you’ve specifically called it to be added to another selector. Similar to a mixin, but without attributes, placeholders let you consolidate your selectors with similar functionality. For example:

%message {
font-weight: bold;
padding: 5px 10px;
text-align: center;
}
.error-message {
@extend %message;
color: red;
}
.success-message {
@extend %message;
color: green;
}

Compiles into…

.error-message, .success-message {
font-weight: bold;
padding: 5px 10px;
text-align: center;
}
.error-message { color: red; }
.success-message { color: green; }

Using Sass placeholders and @extends keeps your code cleaner by consolidating the selectors into a single declaration.

User Profile Social Links

Even with the availability of font icon libraries, it’s not unusual to see a list of social image icons within a user’s profile page. Often accounting for those images can be annoying if they are simply included as images on a page. So we’ll use Sass to simplify the process for us and create them as backgrounds in our profile based on the links.

An example of social links on our sample user profile

Let’s take a look at our markup…

<ul class="social-links">
<li><a href="http://www.facebook.com/user/">Facebook</a></li>
<li><a href="http://www.twitter.com/user/">Twitter</a></li>
<li><a href="http://www.linkedin.com/user/">LinkedIn</a></li>
<li><a href="http://plus.google.com/user/">Google+</a></li>
</ul>

Now, for the Sass. Let’s start by making a list of the social services we want our application to support.

$social-links: "facebook", "linkedin", "twitter", "google";

We’ll want to put our images in /images/social/ for this example and name each image after the service: facebook.png, linkedin.png, twitter.png, and google.png.

Now, let’s set some defaults on our icons with a placeholder, remember to use % to start it off.

%icon-settings {
padding-left: 20px;
background-repeat: no-repeat;
background-position: left center;
}

Finally, we’ll look through our list of services, extend our icon settings, and output our background icons.

@each $link in $social-links {
a[href*="#{$link}"] {
@extend %icon-settings;
background-image: url(/images/social/#{$link}.png);
}
}

Looping through our list we use the “includes” attribute selector to find and assign links with the service keywords and give them a background icon of their associated logo. This generates our final CSS.

a[href*="facebook"], a[href*="linkedin"], a[href*="twitter"], a[href*="google"] {
padding-left: 20px;
background-repeat: no-repeat;
background-position: left center;
}
a[href*="facebook"] {
background-image: url(/images/social/facebook.png);
}
a[href*="linkedin"] {
background-image: url(/images/social/linkedin.png);
}
a[href*="twitter"] {
background-image: url(/images/social/twitter.png);
}
a[href*="google"] {
background-image: url(/images/social/google.png);
}

File Download Links

Social media links aren’t the only way we can style a list using a loop. Common intranets or websites with various file downloads might contain a descriptive filetype icon to show the visitor the type of file they’ll be downloading when clicking the link.

Our process is nearly the exact same as our social links except we’ll now use the “ends with” attribute selector.

$file-types: "doc", "xls", "rtf", "pdf", "zip";%icon-settings { ... }@each $file in $file-types {
a[href$="#{$file}"] {
@extend %icon-settings;
background-image: url(/images/files/#{$file}.png);
}
}

Don’t Make It Complicated

Sure there may be more practical uses of loops outside of mixins for UI advantages with Sass, but I wanted to write about an example that would be approachable by even those unfamiliar with Sass or other preprocessors. The most important thing in any programming language is to avoid being clever at the risk of readability. Simplify your code to its core purpose and take advantage of language features appropriately. But more importantly, have fun doing it.

“Simplicity is about subtracting the obvious and adding the meaningful.”
John Maeda

--

--