Keeping your CSS Dry with Tachyons

Dakota Lee Martinez
9 min readJun 24, 2016

--

In the process of learning web development, we talk a lot about modular design and the importance of creating reusable abstractions. When we’re working on building functionality, we understand that the best way to do that is to have a bunch of functions or methods that just do one thing, do it well, and don’t rely on a knowledge of their context to do their job. That becomes habitual and really helps when we’re trying to debug problems in our code or extend its functionality. But what about CSS?

Higher level frameworks like bootstrap are built with class names that make a bunch of appearance, layout and design decisions for you. Take Bootstrap’s ‘btn’ class for example. Adding the ‘btn’ class to a link applies about 450 lines of CSS to that element (if you don’t believe me, check out lines 3005 to 3461 on the Bootstrap GitHub Repo). If you’re building a site that’s a twitter clone, and you want it to look and feel exactly like twitter, this is great. Super easy and you’re done.

I’m going to bet, however, that you don’t want everyone coming to your site to instantly have that association with so many other sites that are using Bootstrap. Your users may not know what Bootstrap is, but they know it when they see it, and it does start to feel generic. So let’s say you want to customize the look and feel so that you can ‘make it your own.’ Let’s say you don’t like the hover color on your button. Okay, so let’s start going through those 450 lines of CSS and make sure we’ve got all of those colors we want changed. That doesn’t seem too bad, after those styles are adjusted we can use the ‘btn’ class as before and it will look the way we want it to.

Now let’s say we want to customize the Bootstrap Navbar (check out lines 4169 to 4695 on the Bootstrap GitHub Repo). This is where things get super frustrating. Let’s say we don’t like the color scheme of the items in dropdown menus/hover color/active color, etc. This is the code we’d be working with to make customizations:

.navbar-default {
background-color: #f8f8f8;
border-color: #e7e7e7;
}
.navbar-default .navbar-brand {
color: #777;
}
.navbar-default .navbar-brand:hover,
.navbar-default .navbar-brand:focus {
color: #5e5e5e;
background-color: transparent;
}
.navbar-default .navbar-text {
color: #777;
}
.navbar-default .navbar-nav > li > a {
color: #777;
}
.navbar-default .navbar-nav > li > a:hover,
.navbar-default .navbar-nav > li > a:focus {
color: #333;
background-color: transparent;
}
.navbar-default .navbar-nav > .active > a,
.navbar-default .navbar-nav > .active > a:hover,
.navbar-default .navbar-nav > .active > a:focus {
color: #555;
background-color: #e7e7e7;
}
.navbar-default .navbar-nav > .disabled > a,
.navbar-default .navbar-nav > .disabled > a:hover,
.navbar-default .navbar-nav > .disabled > a:focus {
color: #ccc;
background-color: transparent;
}
.navbar-default .navbar-toggle {
border-color: #ddd;
}
.navbar-default .navbar-toggle:hover,
.navbar-default .navbar-toggle:focus {
background-color: #ddd;
}
.navbar-default .navbar-toggle .icon-bar {
background-color: #888;
}
.navbar-default .navbar-collapse,
.navbar-default .navbar-form {
border-color: #e7e7e7;
}
.navbar-default .navbar-nav > .open > a,
.navbar-default .navbar-nav > .open > a:hover,
.navbar-default .navbar-nav > .open > a:focus {
color: #555;
background-color: #e7e7e7;
}
@media (max-width: 767px) {
.navbar-default .navbar-nav .open .dropdown-menu > li > a {
color: #777;
}
.navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
.navbar-default .navbar-nav .open .dropdown-menu > li > a:focus {
color: #333;
background-color: transparent;
}
.navbar-default .navbar-nav .open .dropdown-menu > .active > a,
.navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,
.navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus {
color: #555;
background-color: #e7e7e7;
}
.navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
.navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
.navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
color: #ccc;
background-color: transparent;
}
}
.navbar-default .navbar-link {
color: #777;
}
.navbar-default .navbar-link:hover {
color: #333;
}
.navbar-default .btn-link {
color: #777;
}
.navbar-default .btn-link:hover,
.navbar-default .btn-link:focus {
color: #333;
}
.navbar-default .btn-link[disabled]:hover,
fieldset[disabled] .navbar-default .btn-link:hover,
.navbar-default .btn-link[disabled]:focus,
fieldset[disabled] .navbar-default .btn-link:focus {
color: #ccc;
}

If the source of the frustration isn’t immediately apparent, imagine that you’re in Chrome’s developer tools, trying to tweak the colors to get at the right one. When you click on inspect element, you usually get a pretty general CSS selector in the inspector. You’ll find that nearly none of your declarations work without adding !important to them!

For instance, it wouldn’t work if you tried to adjust the background color of the dropdown menu links with this CSS selector:

.navbar-default .dropdown-menu a {
background-color: gray;
}

Instead, you’d have to use this selector:

.navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,
.navbar-default .navbar-nav .open .dropdown-menu > li > a:focus, .navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,
.navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,
.navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus {
background-color: gray;
}

Needless to say, if you’re making any kind of significant customization to the default bootstrap styles, you’ll run into a lot of repetitive code and complicated selectors, making your CSS grow even bigger than it already is given the size of the Bootstrap CSS framework itself.

Customizing a CSS library like Bootstrap in this manner also leads to extra decisions about how you’re going to organize your CSS. If you have a separate file for your navigation CSS, for instance, do you also have a separate file/section/folder for Bootstrap customizations? Then of course we haven’t even begun to address the issue of where you put all of the Bootstrap overriding styles that are within media queries. In any event, dealing with multiple files in this way can easily lead to distracting thoughts that have nothing to do with the slight change in appearance you wanted to make to a particular element on the page.

Using A Small Library like Tachyons Instead

Let’s say you want to build your own custom button using Tachyons that doesn’t look like the generic Bootstrap button. The process is very different. Much like AngularJS took a lot of the focus back into HTML itself, adding in the ability to describe behavior and logic directly within HTML through the use of directives and expressions, Tachyons allows you to control the appearance of individual HTML elements by adding a bunch of classes to them.

Isn’t that exactly what Bootstrap does? Well, semantically yes, but in practice it’s a much different experience. Bootstrap classes tend to apply many more CSS declarations to the elements they are applied to than Tachyons classes do. Like we saw above, applying the .btn class to an anchor tag adds about 450 lines of CSS that could possibly affect the appearance of that element. The Tachyons library takes a much more modular approach. All the way down to packaging the library into 47 different modules that can be individually included via npm depending on your needs.

Adding a Button

Building a Custom Button using the Tachyons CSS Library

I like looking at the whole Tachyons library’s source on GitHub and searching the page for quick reference when applying styles. So let’s say we want to add our own button to the page. Let’s start with a link:

<a class=”” href=”#”>Click Me</a>

Okay, so the first thing we need to do is add some padding and a light gray background color:

<a class=”pa2 bg-light-gray” href=”#”>Click Me</a>

Great, now we have a simple button.

Button Step 1

Let’s say we want to take away the underline below the button text. Here’s what we do:

<a class=”pa2 bg-light-gray link” href=”#”>Click Me</a>

Voila! Look at that This also adds a nice .15 second color transition to the element, so our hover color will come in nice and smooth:

Button Step 2

All right, let’s say we want to add a border to the button:

<a class=”pa2 bg-light-gray link ba” href=”#”>Click Me</a>
Button Step 3

Okay, now let’s say we want to make the border a bit thicker:

<a class=”pa2 bg-light-gray link ba bw2” href=”#”>Click Me</a>
Button Step 4

Okay, maybe not that thick:

<a class=”pa2 bg-light-gray link ba bw1” href=”#”>Click Me</a>
Button Step 5

Okay, that’s looking pretty good now. Let’s see about adding a hover background color so that it will change when we’re getting ready to click:

<a class=”pa2 bg-light-gray link ba bw1 bg-hover-moon-gray” href=”#”>Click Me</a>
Button Step 6

So the color of the border and the text are a bit darker navy, and I’d like to see what it would look like if they were black:

<a class=”pa2 bg-light-gray link ba bw1 bg-hover-moon-gray black” href=”#”>Click Me</a>
Button Step 7

This is a pretty subtle difference, but I like it. I think this looks great, but if you did want to add a border radius, this is how easy that is to do:

<a class=”pa2 bg-light-gray link ba bw1 bg-hover-moon-gray black br3” href=”#”>Click Me</a>
Button Step 8

Hopefully that gives you a better idea of how you would use Tachyons to apply styles to elements in your project. I think one of the things that I really like about this workflow is that you don’t have to worry about an ever expanding stylesheet when you’re creating slight variations for particular elements because all you have to do is adjust the combination of styles that you’re applying.

Another awesome side effect of using Tachyons is that you’re customizing a particular element you don’t have to worry about breaking the styling applied to other similar elements in your site. The modular approach protects you from having to introduce more classes to deal with slight variations between elements because you’re actually just changing the combination of classes applied to each individual element. This allows your CSS classes to be reused many many times without forcing you to create new ones to deal with slight variations.

When you want to expand the functionality of tachyons, you don’t have to change tachyons at all, you can just tack on a few more classes that you’d like to use and have them follow the same modular pattern. Let’s say you wanted to add a primary color to your site for branding. If you’re using Rails, you can use SASS right out of the box and all you need to do is add these styles:

$primary-color: blue;
.primary-color, .focus-primary-color:focus, .hover-primary-color:hover { color: $primary-color; }
.bg-primary-color, .bg-focus-primary-color:focus, .bg-hover-primary-color:hover { background-color: $primary-color; }
.b--primary-color { border-color: $primary-color; }

Now all you have to do to change the feature color throughout your entire site is to adjust the value of the $primary-color variable. Color is definitely not covered very well in the tachyons library, if you’d like to check out a great extension for the tachyons library that adds in a bunch of colors and gives you great examples of combining background and foreground colors, check out Colors for the examples (be sure to go into the inspector and check out the class names) and the GitHub repo to check out a full list of the class names and installation instructions.

Overall, the main side-effect of using a CSS library like tachyons as opposed to a full on framework like Bootstrap is that you start thinking about your CSS in terms of lightweight classes. These classes only do one thing, standing in for individual CSS properties, allowing them to be combined to create the perfect styles for a particular element — without creating an ever expanding stylesheet!

Worth Checking Out

--

--