Tailwind CSS vs. SCSS: A Comparison of Utility-First and Preprocessor Approaches

Muzammil syed
10 min readFeb 9, 2024

--

If you are a web developer, you might have used or heard of SCSS and Tailwind CSS. These are two popular tools for styling web pages, but they have different features and approaches. In this post, I will compare them and show you how and why Tailwind CSS is a better choice than SCSS for your project.

What is SCSS?

SCSS stands for Sassy CSS. It is a CSS preprocessor that extends the capabilities of CSS with features like variables, mixins, functions, and nesting. A CSS preprocessor is a tool that allows you to write CSS in a more powerful and expressive way, and then compiles it into plain CSS that browsers can understand.

Why use SCSS?

People use SCSS for various reasons, but some of the main ones are:

  • Nesting: SCSS allows you to nest selectors within other selectors, making it easier to write and read complex stylesheets, whereas CSS requires you to write each selector separately. For example, you can write:
.parent {
background-color: blue;

&:hover {
background-color: red;
}

.child {
margin: 2rem;
color: green;
}
}
  • Variables: Both SCSS and CSS allow you to define variables to store commonly used values such as colors, font sizes, and spacing. However, SCSS variables offer advantages such as preprocessing, imperative behavior, and advanced features like color calculations. For example, you can write:
$white: #ffffff;
$ubuntu-font: "Ubuntu", "Arial", "Helvetica", sans-serif;
$base-color: #ff0000;
$border-dark: darken($base-color, 20%);

body {
color: $white;
font: $ubuntu-font;
border: 1px solid $border-dark;
}
  • Mixins: SCSS allows you to create reusable code snippets using mixins, which are like functions in programming languages. CSS does not provide this functionality. For example, you can write:
@mixin border-radius($radius) {
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
-ms-border-radius: $radius;
border-radius: $radius;
}

.box {
@include border-radius(10px);
}
  • Partials and Imports: SCSS allows you to split your stylesheet into multiple files using partials, which are files that start with an underscore (_). You can then import these partials into your main stylesheet using the @import directive. This helps you to organize your code and avoid repetition. CSS does not support this feature. For example, you can write:
// _variables.scss
$primary-color: #ff0000;
$secondary-color: #00ff00;
$tertiary-color: #0000ff;
// main.scss
@import "variables";

body {
background-color: $primary-color;

h1 {
color: $secondary-color;
}

p {
color: $tertiary-color;
}
}
  • Inheritance and Operators: SCSS allows you to inherit styles from another selector using the @extend directive, which helps you to avoid duplicating code. SCSS also supports arithmetic and logical operators, such as +, -, *, /, %, and, or, and not, which allow you to perform calculations and comparisons with your styles. CSS does not have these features. For example, you can write:
.error {
border: 1px solid red;
color: red;
}
.warning {
@extend .error;
color: orange;
}

.success {
@extend .error;
color: green;
}

.container {
width: 100% / 3 - 20px;
height: 50% + 10px;
}

@media (min-width: 768px) and (max-width: 1024px) {
.container {
width: 50% - 10px;
}
}

What are the disadvantages of SCSS?

  • Tool Dependence: SCSS requires a preprocessor to compile into CSS, which adds an extra step to the development process. This dependency on tools might complicate project setup and maintenance.
  • Debugging Complexity: Debugging SCSS-generated CSS can be challenging since the compiled CSS doesn’t directly reflect the SCSS source. This can make it harder to pinpoint issues during development.
  • File Size: SCSS files might be larger than plain CSS files due to features like nesting and mixins, potentially increasing load times.
  • Performance Impact: The additional step of preprocessing SCSS files can impact build times, especially in larger projects.
  • Dependency on Build Process: Projects using SCSS rely on a build process to compile SCSS into CSS. This adds complexity to the development workflow and may require additional configuration and tooling.

What is Tailwind CSS?

Tailwind CSS is a utility-first CSS framework that enables you to create beautiful and responsive websites without ever leaving your HTML. Unlike SCSS or other CSS frameworks that provide ready-made components and styles, Tailwind CSS gives you the building blocks to create your own custom design with low-level utility classes.

Why use Tailwind CSS?

Tailwind CSS has many advantages over traditional CSS or other CSS frameworks. Here are some of the reasons why you should use Tailwind CSS:

  • It is highly customizable: You can easily configure Tailwind CSS to match your design system, such as colors, fonts, spacing, breakpoints, and more. You can also add your own custom utility classes or use third-party plugins to extend Tailwind’s functionality.
  • It is responsive and easy to use: You can use utility classes to control the layout, color, spacing, typography, shadows, and more for different screen sizes, directly in your HTML. You don’t have to write media queries or use complex CSS selectors. Tailwind CSS also provides helpful tools like flexbox, grid, and transitions to create complex layouts and animations.
  • It is component-friendly: You can extract common patterns into reusable components, or use directives like @apply and @variants to apply utility classes to other selectors. You can also use frameworks like React, Vue, or Angular to create dynamic components with Tailwind CSS.
  • It is small and fast: Tailwind CSS only generates the styles you actually use, resulting in very small CSS files. It also uses PostCSS to optimize the CSS for production, such as removing unused styles, minifying the code, and adding vendor prefixes.
  • Community support: Tailwind CSS has a large and active community of developers who use and contribute to the framework. There are also many popular UI libraries that are built with or compatible with Tailwind CSS, such as Headless UI, Daisy UI, Shadcn UI, and Preline UI. These libraries provide ready-made components and utilities that you can use in your projects.

Here is an example of how to use Tailwind CSS to create a card component with a hover effect:


<figure class="bg-gray-100 rounded-xl p-8 hover:bg-green-600 hover:text-white transition duration-300 ease-in">
<img class="w-32 h-32 rounded-full mx-auto" src="/sarah-dayan.jpg" alt="" width="384" height="512">
<div class="pt-6 space-y-4">
<blockquote>
<p class="text-lg">
“Tailwind CSS is the only framework that I've seen scale
on large teams. It’s easy to customize, adapts to any design,
and the build size is tiny.”
</p>
</blockquote>
<figcaption class="font-medium">
<div>
Sarah Dayan
</div>
<div>
Staff Engineer, Algolia
</div>
</figcaption>
</div>
</figure>

How Tailwind CSS can replace SCSS for your web design needs

You might be wondering: if SCSS is so powerful and flexible, why should I switch to Tailwind CSS? Well, the answer is: because Tailwind CSS can do everything SCSS can do, and more. Let me show you how.

Want to Separate your styles from HTML?

Tailwind CSS lets you style your HTML elements by applying pre-defined classes directly in your markup. This way, you can build any design you want without writing any custom CSS.

However, some people might not like Tailwind CSS because they think it adds too many classes to the HTML file, making it hard to read and maintain. They might prefer a more traditional approach of using semantic class names and writing CSS in a separate file. Fortunately, Tailwind CSS offers a way to avoid this problem and keep your HTML clean and semantic. One of them is to use the @apply directive in your CSS file, which allows you to create your own custom classes and apply Tailwind utility classes to them:

<div class="bg-white shadow-lg rounded-lg p-4 flex items-center justify-between">
<div class="flex items-center">
<img src="avatar.jpg" alt="Avatar" class="w-12 h-12 rounded-full mr-4">
<div class="text-sm">
<p class="text-gray-900 font-bold">Jane Doe</p>
<p class="text-gray-600">janedoe@example.com</p>
</div>
</div>
<button class="bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded">Follow</button>
</div>

You can write this:

/* main.css */
.card {
@apply bg-white shadow-lg rounded-lg p-4 flex items-center justify-between;
}

.card-image {
@apply w-12 h-12 rounded-full mr-4;
}

.card-info {
@apply text-sm;
}

.card-name {
@apply text-gray-900 font-bold;
}

.card-email {
@apply text-gray-600;
}

.card-button {
@apply bg-blue-500 hover:bg-blue-600 text-white font-bold py-2 px-4 rounded;
}
<div class="card">
<div class="flex items-center">
<img src="avatar.jpg" alt="Avatar" class="card-image">
<div class="card-info">
<p class="card-name">Jane Doe</p>
<p class="card-email">janedoe@example.com</p>
</div>
</div>
<button class="card-button">Follow</button>
</div>

Or, and this is my preferred way, you could use a code editor extension that can fold or collapse your HTML classes, such as Inline-Fold for VS Code. This transforms the code as follows:

React button component (without extension)

Into this:

React button component (with extension)

In this approach you can get the best of both worlds.

Can’t live without Nesting?

One feature that SCSS users love is nesting, which allows you to write nested selectors within other selectors. If you are separating your styles from your markup, you can use this feature in Tailwind CSS as well, thanks to the tailwindcss/nesting plugin. It’s included directly in the Tailwind CSS package, so to use it, just add it to your PostCSS configuration, somewhere before tailwindcss. For example:

// postcss.config.js
module.exports = {
plugins: {
'tailwindcss/nesting': {}, // add this line
tailwindcss: {},
autoprefixer: {},
}
}

And then you can write nested selectors with Tailwind utility classes, like this:

.navbar {
@apply bg-gray-900 text-white;

ul {
@apply list-none;

li {
@apply inline-block px-4;

a {
@apply no-underline text-inherit;

&:hover {
@apply text-yellow-500;
}
}
}
}
}

As you can see, Tailwind CSS does not limit your ability to use nesting. It actually makes it more powerful and flexible.

Like Multiple CSS files?

Another feature that SCSS users enjoy is partial files, which allow you to split your stylesheet into multiple files and import them into your main file, You can also do this with Tailwind CSS. To use it.

Install this plugin via npm:

npm install -D postcss-import

Then add it as the very first plugin in your PostCSS configuration:

// postcss.config.js
module.exports = {
plugins: {
'postcss-import': {}, // add this line
'tailwindcss/nesting': {},
tailwindcss: {},
autoprefixer: {},
}
}

Now you can create a file called button.css and store your button styles there, like this:

/* buttons.css */
.base-button {
@apply bg-gray-900 text-white;
}

Then you update your main file, from this:

/* main.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

to this:

@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

/* Your custom files here */
@import "buttons.css"

As you can see, Tailwind CSS does not prevent you from using multiple files. It actually makes it easier to organize and manage your styles.

Want to centralize colors, fonts, and screen sizes?

One of the benefits of SCSS is that it allows you to define variables to store commonly used values, such as colors, fonts, screen-sizes, and more. You can also do this with Tailwind CSS. All you need to do is add your custom values to the theme object in your Tailwind configuration, like this:

// tailwind.config.js
module.exports = {
theme: {
colors: {
primary: '#00FF00',
secondary: '#FF0000',
// ...
},
fontFamily: {
roboto: ['Roboto', 'sans-serif'],
// ...
},
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
// ...
},
// ...
},
// ...
};

And then use them in your HTML file, like this:

<div class="bg-primary text-white font-roboto">
<p>This is a custom value</p>
</div>

<div class="lg:bg-secondary">
<p>This is a custom breakpoint</p>
</div>

As you can see, Tailwind CSS does not restrict you from using variables. It actually makes it more convenient and consistent to use them.

What about the mixins for vendor prefixes?

One of the features that SCSS users rely on is mixins, which are reusable code snippets that can be used throughout your stylesheets. One of the common use cases for mixins is to add vendor prefixes to CSS properties that are not fully supported by all browsers, such as box-shadow, border-radius, or transform. You don’t need to do this with Tailwind CSS. Tailwind CSS already takes care of adding vendor prefixes for you, using PostCSS and Autoprefixer. You can simply use the utility classes that Tailwind CSS provides, such as shadow, rounded, or rotate, and they will work across all browsers. For example, you can write:

<div class="card shadow rounded rotate-3">
<p>This is a card with shadow, rounded corners, and rotation</p>
</div>

Conclusion

In this blog post, I have demonstrated how Tailwind CSS with PostCSS is a superior choice for frontend design than SCSS. Tailwind CSS offers more flexibility, control, speed, efficiency, customization, and responsiveness than SCSS, while also reducing the amount of CSS code you have to write. It also has many unique features and benefits that SCSS lacks, such as utility classes, component-friendly syntax, and better community support.

If you are a frontend developer who wants to create stunning and adaptive websites with less hassle, you should give Tailwind CSS a try. You can learn more about it from their official website, documentation, or tutorial. You can also use this interactive cheat sheet to quickly find and search for all the class names and CSS properties from Tailwind.

I hope you found this blog post informative and useful. If you have any feedback or questions, please leave them in the comments section below. Thank you for reading. 😊

--

--