Logo
Published on

Why Tailwind CSS is worth looking into?

Authors
  • avatar
    Name
    Kamil Cieplicki
    Twitter

In my experience, the approach to styling web applications is often marginalized by frontend developers that I have worked with. Most of them are strongly focused on app logic, which is okay, but I think the problem of selecting an optimal CSS approach is more complex than it appears. It depends on the size and complexity of the application.

What is the best approach for styling components?

As I wrote this article, I tried to recall my approaches for writing CSS code in the last few years and I came to the conclusion: there is no one "ideal" approach for styling components that will work for every project or situation.

The problem of selecting an optimal CSS approach depends on a number of factors, including:

  • The size and complexity of the application: A larger, more complex application may require a more sophisticated CSS approach in order to handle the increased number of styles and layout requirements.
  • The available resources: The CSS approach that is most appropriate for a project may depend on the amount of time and resources that are available to implement and maintain it.
  • The preferences of the development team: Different teams may have different preferences and comfort levels when it comes to using different CSS approaches, and the approach that is most suitable for a project may depend on the team's skills and experience.
  • The desired level of reusability: Some CSS approaches, such as component-based frameworks or CSS-in-JS libraries, are designed to make it easy to reuse styles across different parts of the application. If reusability is a priority, these approaches may be more suitable.
  • The desired level of customizability: Some CSS approaches, such as utility-first frameworks, are designed to be highly customizable, making it easy to adjust the look and feel of the application to fit the specific needs of the project. Other approaches, such as traditional CSS frameworks, may be less customizable but offer a more opinionated set of styles and layout options.

Let's review some CSS approaches.

TailwindCSS disrupts the concept of separating HTML content and CSS styles

  1. Basically the idea assumes that HTML document only contain content information and css hooks, which refers to HTML element. It is reffered to as Separation of Concerns.
/** good */
<p class="main-paragraph">Hello!</p>

/** bad */
<p class="greetings">Hello!</p>
  1. BEM (Block Element Modifier) methodology - it uses separation of concerns and also use CSS classes which names are depends on HTML content. It is reffered to as Mixing Concerns.

The BEM methodology is based on the idea of breaking down a webpage into small, reusable blocks of HTML, with each block representing a distinct component of the page. Each block is then divided into elements, which are the individual parts that make up the block, and modifiers, which are variations of the block or element that can be used to change its appearance.

<div class="home-wrapper">
    <h1 class="home-wrapper__title">Hello!</h1>
    <img class="home-wrapper__image" src="" alt=""/>
</div>

But what we should do when we have similar but not the same components? We can duplicate styles to a new stylesheet like copy-paste and changing some details. But it is bad approach in comparison to DRY principle and also CSS bundle size is rising.

We can also use @extends directive. If we create a few almost the same components, those directives could cause maintenance problem when another similar components will be created.

  1. Of course we can use Content agnostics CSS components approach. In few words it means that we named CSS classes independent of HTML content and CSS style file is independent of HTML file. It caused reduction of styling duplications. The main principle of that is to use the more reusable names of classes as it possible like
<div class="author-bio">
    <h1 class="author-bio__title">Hello!</h1>
    <img class="author-bio__image" src="" alt=""/>
</div>
<div class="user-bio">
    <h1 class="user-bio__title">Hello!</h1>
    <img class="user-bio__image" src="" alt=""/>
</div>

could be replaced by:

<div class="person-bio">
    <h1 class="person-bio__title">Hello!</h1>
    <img class="person-bio__image" src="" alt=""/>
</div>
<div class="person-bio">
    <h1 class="person-bio__title">Hello!</h1>
    <img class="person-bio__image" src="" alt=""/>
</div>

But what we can do if we need a change for some of above code? We have to add new class so that means escaping the rules of BEM methodology. Another problem is when the more a component does or the more detailed it is, the harder it is to reuse it.

Content agnostics CSS components approach is also known from CSS modules, where we have separate, dedicated CSS file for every component.

Many of solutions for that problem are ended up by duplicate CSS code and assign them into new classes for indicated element.

  1. Above problem could be done if we apply mixed approach of Content agnostic CSS components and utility classes. We prefer composition to duplication. Utility class call for composition and it's fully reusable. Check the example below:

Imagine the code, where you have the form, which is used by two sections in your landing page.

<form>
  <div class="form-element">
    <label for="name">Enter your name: </label>
    <input type="text" name="name" id="name" required>
  </div>
  <div class="form-element">
    <label for="email">Enter your email: </label>
    <input type="email" name="email" id="email" required>
  </div>
  <div class="form-element">
    <input type="submit" value="Subscribe!">
  </div>
</form>
form {
  display: flex;
  flex-direction: column;
}

form.form-element {
    display: flex;	
}

But in second form you have to add an additional space between HTML elements with form-element class. What's the solution? You can simply add reusable class like space-2 to elements which should be touched.

<form>
  <div class="form-element space-2">
    <label for="name">Enter your name: </label>
    <input type="text" name="name" id="name" required>
  </div>
  <div class="form-element space-2">
    <label for="email">Enter your email: </label>
    <input type="email" name="email" id="email" required>
  </div>
  <div class="form-element">
    <input type="submit" value="Subscribe!">
  </div>
</form>
form {
  display: flex;
  flex-direction: column;
}

form.form-element {
    display: flex;
}

div.space-2 {
  margin: 8px 0;
}

Why space-2 not space-0 or space-1? In that case that's just guesswork, but in Tailwind CSS it's defined as a numeric spacing scale. https://tailwindcss.com/docs/customizing-spacing#default-spacing-scale

Why just not use approach with only utility classes? You can build new UI components without writing new CSS code for any of them.

As you read before, you can see that creating reusable components forces more complicated HTML and CSS structure on you. Starting with correct name of class and then following problems with extending additional styles for specific component. All of them effect on our thinking about creating reusable, utility first classes.

Tailwind CSS Core Concepts

Tailwind CSS is a utility-first CSS framework that provides a set of low-level, highly composable utility classes that make it easy to build custom designs without having to write a lot of custom CSS. Some core concepts of Tailwind CSS include:

  1. Utility classes: Tailwind CSS provides a wide range of utility classes that allow you to style elements in a consistent and flexible way. These classes are designed to be as atomic as possible, meaning they affect a single design property and have no dependencies on other styles.
  2. Responsive design: Tailwind CSS includes built-in support for responsive design, allowing you to easily create designs that look great on any device.
  3. Customization: While Tailwind CSS provides a large set of predefined utility classes, it also allows you to customize the framework to fit your specific needs. You can adjust the colors, font sizes, and other design properties to match your brand, or create your own custom utility classes.
  4. Composability: One of the key benefits of Tailwind CSS is its ability to be easily composed to create complex designs. By using a combination of utility classes, you can create sophisticated layouts and user interfaces without having to write a lot of custom CSS.
  5. Performance: Tailwind CSS is designed to be performant, with minimal CSS output and optimized for production use. It uses PostCSS to optimize the CSS it generates, ensuring that your stylesheets are as small and efficient as possible.

Why Tailwind CSS is worth looking into?

I have compiled a list of several advantages of using Tailwind CSS:

  1. It provides a wide range of pre-designed utility classes that can be used to style elements without the need to write custom CSS. This can make it much faster to build layouts and style components.
  2. It promotes a modular, atomic design approach that encourages creating small, reusable styles that can be combined to build larger components. This can make it easier to maintain and scale your styles over time.
  3. It has a low learning curve and is easy to pick up, even for developers who are new to CSS.
  4. It has a strong community and is actively maintained, with new features and improvements being added regularly. Overall, Tailwind CSS can be a great tool for developers who want a quick and easy way to build custom user interfaces without the need to write a lot of custom CSS. It can be especially useful for teams working on large, complex projects where it's important to move quickly and maintain consistent design across the project.