Floating on Tailwind CSS | SitePen

As modern reactive front ends have begun to converge on effective module patterns and universal approaches to common application paradigms, it’s not uncommon to see much of the variance between front ends come from how they expose and implement their given style guide. The implementation and the delivery of application styles to an underlying component tree has become almost an art form, wherein each application attempts to solve the ever-present CSS problems of naming and reuse in the best, most-effective way possible. Tailwind CSS provides a set of style guide-agnostic utility classes backed by opinionated, customizable variables, allowing developers to switch between projects using the same CSS tool set.

Styling of the past

Many strategies are used in an attempt to overcome and to unify styling between projects in an effort to reduce developer time spent on styling. For example, CSS variables can be shared between components and their stylesheets, allowing for the reuse of colors, measurements, and utilities. Components can also be used to abstract away and to share typography, layout, and responsive styles in a declarative manner without the need for CSS at all. While these approaches can be effectively utilized to share most aspects of a given design system throughout a component tree, they only provide a mechanism for reuse and don’t actually lessen any learning curve for developers: variable names and available utility classes must still be learned, style components must be understood, and naming conventions and measurement scales must be memorized.

Another approach used to reduce the time developers spend on styling in a project is relying on a trusted third-party design framework. Many such frameworks exist that expose robust component sets and underlying CSS that prescribes a given look or feel that can be reused between projects (e.g. Material). Many of these off-the-shelf solutions work well and look great in practice, and they objectively solve the issue of developers needing to learn new styling approaches between projects, but they do so by handing developers a ready-made style guide rather than allowing a design team to create their own. It’s not uncommon for enterprise products to have underlying design systems that compete with the concepts provided by a third-party CSS solution, reducing the real-world usefulness and customizability of such design frameworks.

The future: Tailwind CSS

The effectiveness of Tailwind can be thought of in two distinct categories: utility classes and base values. The utility classes exposed by Tailwind are intentionally low-level and can be used to apply any defined CSS rule to a given node in a declarative manner. For example, overflow can be hidden with .overflow-x-hidden, text truncation can be added using .truncate, and opacity can be cut by half using .opacity-50. Almost every defined CSS rule has a corresponding utility class, and all utility classes are named using easy-to-remember conventions that are indicative of the underlying rule itself. At first, it may seem like this is just sugar over inline styles within components, but Tailwind goes further by also providing state-based variations of all defined utility classes so that styles can be conditionally-applied based on breakpoint, dark mode, and hover or focus states. For example, a black background can be conditionally-applied based on system dark mode simply by applying the .dark:bg-black class. In this way, Tailwind mitigates the need for most custom CSS, and instead allows styling to be declarative using powerful classnames that don't change between projects.

The utility classes provided by Tailwind gain much of their power over raw inline styles because they rely on common internal values for things like measurements, colors, and breakpoints. This means that developers are not freely using any arbitrary values when applying Tailwind utility classes like they would be using inline styling, and they are instead restricted to what Tailwind defines. For example, the width of an object can be changed using classes such as .w-1, .w-2, .w-3, etc., and Tailwind uses a carefully-chosen internal scale to determine what "width 1", "width 2" and "width 3" actually mean in terms of actual width values. Tailwind opaquely provides base values like this for all utility rules that involve variables, most commonly measurements and colors. This means that developers can add medium vertical padding using .pv-2, and increase this vertical padding on large screens with .lg:pv-4, without ever caring about what the large breakpoint value is or what "padding 4" means. In this way, developers use Tailwind to apply any CSS rule, but these rules are backed by a subtle design system of values that cohesively work together no matter what is being designed.

Tailwind has broken new ground as a low-level, declarative CSS framework that’s also backed by a design system that provides just enough opinion to make developers effective. Perhaps most importantly, it does so in a manner that can be used repeatedly across different projects with different architectures and different application style guides.

Head-to-head showdown

Vanilla CSS

The example above has the advantage of being concise when only looking at the HTML because class names can be semantic and specific to the case in which they’re used. However, the example above also suffers from several key disadvantages that inhibit developers quickly stepping in and making modifications.

  1. Class names are arbitrarily named
    While semantic class names are usually easy to follow, forcing developers to add custom CSS class names to nodes inherently opens a project up to subjective naming deviations and steepens the resulting learning curve. Different authors may choose different class names to accomplish similar styling, so the CSS must always be consulted for truth.
  2. The required CSS is verbose.
    The resulting external CSS file is over 100 lines even with some reuse and streamlining of styling logic. While this could be made more concise if iterated on a few more times, this is inherently tedious to have to write so much custom CSS to accomplish styling that’s almost exclusively layout-based. In a component-based framework like React, this also requires an external CSS file to be created and imported, which is both tedious and incurs extra (albeit minimal) build time indirection.
  3. All CSS values used are arbitrary.
    The resulting CSS also includes raw measurements for things like paddings, margins, font sizes, and colors. Leaving such values up the developer to choose without any restriction on those choices again opens styling up to subjective deviation. This could be mitigated by sharing CSS variables, but then those variable names also must be learned, which can change between projects.

Tailwind CSS

The example above has the disadvantage of having more-verbose markup due to more class names, as much of the CSS logic from the previous example has been moved to declarative class names in this case. However, developers also gain several key advantages that usually outweigh this added verbosity.

  1. All presentation logic is in a single location.
    All markup and its corresponding styling is in a single, declarative location, allowing for easy mental absorption and easy declarative modification based on component state.
  2. Naming subjectivity is removed.
    Since no custom CSS is needed, no hard-to-follow custom class names or supporting CSS variables or utility classes are needed. This greatly reduces the learning curve when switching between potentially-unrelated projects since the syntax and available CSS class set will be the same.
  3. All values used adhere to the Tailwind internal system.
    When using styling that relies on values such as widths or colors, no longer are developers asked to loosely-adhere to an arbitrary measurement scale or to use proprietary color palette variables. Instead, Tailwind projects use the same utility classes, and the underlying values are automatically applied.
  4. Concepts are not per-project.
    Perhaps most importantly, all concepts provided by Tailwind can be applied across projects. Because Tailwind straddles a unique line in which it’s both low level and also provides smart values, it can be effectively used in entirely unrelated projects with entirely different higher level style guides, with no additional ramp up at all.

Customization

Conclusion

Originally published at https://www.sitepen.com on April 15, 2021.

Modernizing Apps, Tools & Teams | sitepen.com | Twitter: @sitepen

Modernizing Apps, Tools & Teams | sitepen.com | Twitter: @sitepen