Maybe you've heard of TailwindCSS but have dismissed it because you think writing out class names for each CSS rule is too tedious and you don't want to "litter" your HTML with them? Well that's understandable since it "encourages a utility-first workflow, where designs are initially implemented using only utility classes to avoid premature abstraction", but that's not the end of the story.

Components can be composed of utility classes using @apply. So the following button:

<button class="bg-blue-500 text-white font-bold py-2 px-4 rounded">
  Click Me
</button>

Can be optimized to use this class:

.button {
  @apply bg-blue-500 text-white font-bold py-2 px-4 rounded;
}

Simplifying it to:

<button class="button">
  Click Me
</button>

Pseudo-classes can't be used with @apply so if you wanted to use hover:bg-blue-700 with the button class you would simply add a separate pseudo-class for the underlying utility class:

.button:hover {
  @apply bg-blue-700;
}

So why do this instead of just using CSS rules directly?

Because now you benefit from the convenience of the button component class and you can still use the utility classes to compose other components, style other areas of your site, and easily modify the styles of other elements. The flexibility that utility classes provide is extremely powerful and, because of how it works behind the scenes, the generated CSS is smaller than if you had specified CSS rules directly for all of those things (as long as you're using a tool like PurgeCSS).

Read more about this on the TailwindCSS site: Extracting Components