In this little series of posts, we’d like to show you why and how we migrated the styles on our main website from Tachyons to Tailwind CSS and what we’ve learnt along the way. We will also share tools that will help you migrate much faster, should you set up on the same endeavor. Our website is built with Ruby on Rails, so parts of the article will be Rails-specific, but the principles mentioned here should work equally well elsewhere.
A small TL;DR teaser: we migrated around 650 distinct utility classes at ~30,000 places in ~800 files. The full migration took us a month in a team of two, while the rest of the dev team continued to work normally (it was harder than anticipated, though). We like the completeness and expressiveness of Tailwind classes and the opinionated way they are designed in. The integrated PurgeCSS of Tailwind is just superb, the dependence of bundling the CSS on the JavaScript ecosystem seems OK, though not very ”Railsy“. RubyMine tooling is catching up. We find the community around Tailwind to be active, supportive and inspiring.
The process described below will be almost as magical as this 😉:
Why we migrated to Tailwind CSS
Note: this section is not about ”Why utility CSS in general“. It’s rather ”Why Tailwind CSS in particular, compared to Tachyons“, i.e. we suppose you know why you (dis-)like utility CSS in the first place.
We started using Tachyons five years ago, in 2016, long before the current hype around utility CSS frameworks, Tailwind especially. Back then, we adopted the framework in a simple way using SASS, modified some of the scales, added our color palette, set up conventions, enjoyed the boost in front-end coding speed and used it quite happily since. (We even wrote a guest post about our early Tachyons experience but it’s in Czech only, sorry.)
Throughout the time, we began noticing things that we liked less, such as:
- It was way too easy (and thus common) to add new utilities to Tachyons. Not to the main length-scales perhaps (these were auto-generated by SASS mixins) but to all other parts of the framework. In the beginning, we needed to adapt the Tachyons defaults quite heavily and unfortunately we kept this ”if you need it, just add it“ mindset even after our design system stabilized. Thus, if you were unlucky, you could come across e.g. this horrible mess in the percentage width scale that accumulated over the years in our codebase:
.w-10 { width: 10%; }
.w-15 { width: 15%; } /* hmm 🤔 */
.w-20 { width: 20%; }
.w-24 { width: 24%; } /* oops 🙄 */
.w-25 { width: 25%; }
.w-28 { width: 28%; } /* yikes! 😬 */
.w-30 { width: 30%; }
.w-32 { width: 32%; } /* ouch! 😩 */
.w-33 { width: 33%; }
.w-34 { width: 34%; } /* what the… 😖 */
.w-35 { width: 35%; } /* well…? 🤨 */
.w-37 { width: 37%; } /* no way! 😱 */
/* ... */
.w-90 { width: 90%; }
.w-95 { width: 95%; }
.w-98 { width: 98%; } /* aaargh! 🤯 */
.w-100 { width: 100%; }
Partly related to the above point, we missed some kind of guidance when building our visual style set. For example, we needed to amend Tachyons to use our own color palette but unfortunately it does not provide any opinion on how to do that. Eventually, we’ve chosen to adopt this nice online service to name our colors but we actually like the Tailwind default color system better as it tries to sort the colors as well based on their approximate darkness, leading to a less arbitrary, more predictable palette. In general, we find Tailwind much more opinionated, in various ways, while Tachyons being more generic and leaving more decisions up to the user.
Tachyons is said to be feature-complete and one cannot expect new features to be added or problems discussed. The latest release is three years old. While the framework continues to be perfectly usable as is, we couldn’t escape a feeling of some stagnation. For example, in Tachyons, the core grid system is done via floats. We’re not saying this is wrong, it just isn’t inspiring any more and we regret that the CSS grid will probably never be integrated in any way. The same goes with many modern features that Tailwind already supports natively (dark mode, GPU-enhanced animations, reduced motion, etc).
More recently, we started looking rigorously into the front-end performance of our web. The main CSS file, being part of the critical rendering path, is of course of utmost importance for page speed. Some time ago we noticed that we were actually using only about 40% of all our Tachyons classes (mainly due to unused length-scale classes in media queries) and thus that more than half of our CSS was served needlessly! While there are many solutions to this problem, none seemed to be nicely usable from the Rails asset pipeline. On the contrary, PurgeCSS is integrated right inside Tailwind 2.0.
Over the years, we hired a few new front-end developers, some of them junior. We quickly found that while it is hard to find tutorials on Tachyons, there are many learning materials on Tailwind (not to mention the great official Tailwind documentation). Of course, the general principles are the same but it seems better to not have to mentally translate all you see in the tutorials to another ”language“. Furthermore, the chance of hiring someone who knows Tailwind upfront is much bigger than in the case of Tachyons, as the community is larger.
As you can see, there was actually no urgent technical reason to migrate, no hard push, we might as well go on with a bit of style cleaning, perhaps supported by a few new processes and team rules. But we were tired and wanted a refresh, a new inspiration. We wanted to raise our front-end devs happiness a bit by moving our code out of the legacy land, closer to what’s currently hot in the community. So, that’s why we decided to migrate to Tailwind and now, let’s see how we did it!
Migration rules
Before jumping on the migrations, we set some important constraints for our efforts:
The whole process must not prevent other colleagues from working as usual. During the transition, they should be able to use the familiar system and not be forced to mix Tachyons and Tailwind syntax while coding. That means that the two systems must coexist for some time, live in production.
This also means that the migration cannot be a single-shot nor a manual process. It must support replacing the given classes repeatably and automatically.
We need to be able to continuously measure the progress of the migration, to estimate how much work is left to do.
We want to adhere to the Tailwind defaults as much as possible. We want to add only the most needed custom classes and will refactor / rewrite / remove the rest.
Installing Tailwind CSS 2.0
The particular installation steps are somewhat outside the scope of this post. If you’ve never used webpack to bundle your CSS before, get ready for a deep dive into a whole new world…
Since our web was a Rails application, in general we needed to:
- upgrade nodejs to a version supported by Tailwind 2.0
- upgrade Webpacker to version 6 (currently in beta) to support PostCSS 8 needed by Tailwind 2.0
- add CSS bundling to Webpacker (webpack)
- add Tailwind 2.0 as a PostCSS plugin
- generate the full Tailwind configuration as the basis that we would work later on
- properly configure Tailwind and Webpacker for the migration - much more on that below…
Luckily, there are quite a few nice tutorials to follow. We recommend skimming through all of them as their small differences helped us understand better what we were actually doing…
BTW, note that Tailwind 2.0 officially drops support for IE, so go the 2.0 route only if you can afford that.
Cleaning up Tachyons styles
To fulfill the rule #4, we spent quite some time cleaning the Tachyons styles. And yes, you bet we also cleaned the horrible width scale you saw above!
Sometimes we decided to slightly change the visual appearance of a particular piece on the web to be able to remove a spurious utility class. No need to hunt for pixel-perfection and nobody ever noticed… 😉
This tidying up took us most of the first week.
What about media queries?
During that time, we also did an analysis of our Tachyons media queries usage, with two questions in mind:
- can we possibly remove some of the media queries ahead of the transition?
- can we map the remaining Tachyons media queries easily to their Tailwind counterparts?
We grabbed our analytics data and confirmed that, in terms of screen sizes, our visitors come in just two large groups: ”mobile users“ and ”desktop users“. And that there is almost nobody visiting us in the "medium" / tablet range between ~430-1200 pixels:
When me mapped these visit stats to our Tachyons media queries, we saw this:
There were two important media queries, the ”non-small“ (-ns
) and ”large“ (-l
), that we definitely wanted to migrate. Luckily for us both were defined using a min-width
rule only so the mapping to Tailwind breakpoints was straightforward (-ns
⟶ sm:
and -l
⟶ lg:
). The only change was that the breakpoints shifted a bit with the migration but that was no big deal. (One funny detail though: what was ”non-small“ before is now called ”small“ 🙃.)
The other two media queries turned out as clear candidates for removal:
- The ”small“ (
-s
) media query seemed relevant but actually was not at all — it was our ancient messy attempt to solve some specific issues we had with utility classes early after adopting Tachyons. It was used only on a handful places and now that we were more experienced, we were able to easily get rid of it completely during code cleaning. - The ”medium“ (
-m
) media query was more scattered around the codebase but from the analysis we had learned that it was actually effective only for a very small fraction of visitors. It looked like we coded for these devices almost needlessly. We decided to disable these utilities, look around the web and manually correct the few places where the missing medium breakpoint actually broke something visually. Then we deleted this media query altogether from the codebase.
This is getting long so we’ll wrap it here for now and in the next post we’ll actually get to the hardcore migration stuff! Stay tuned… (we’ll tweet).
Top comments (0)