CSS in HTML will always feel a bit gross. Every front-end web developer learns at some point that inline styles are a bad idea. A style
attribute for each element leaves your styling fragmented and unmaintainable at scale. What happens if you need the same styles somewhere else? They're unique to the tags you've put them on. The situation does not change with Bootstrap and Tailwind (or does it?).
<!-- Some inline styles. Not the best. -->
<div style="padding: 1em; margin: 1em; border-radius: 16px">
Some text content
</div>
Bootstrap and Tailwind, to varying degrees, implement piecewise style classes on elements. If you want medium padding on all sides of an element, you can give it the class p-3
. Bootstrap attempts to provide a wide array of ready-to-use components, while Tailwind is practically the same as writing CSS with variables. So, from the argument presented in the first paragraph, why would anyone want to use Tailwind over Bootstrap?
<!-- The Tailwind equivalent to the inline styles -->
<div class="p-4 m-4 rounded-2xl">
Some text content
</div>
The primary benefit of these tools is speed. You're not switching between editors; your styles live within the DOM. An innumerable amount of developers at any given moment are cooking up pretty websites in no time flat. That's where my first issue arose: Bootstrap is not fast. In fact, it was adding seconds onto compiletime with Webpack. I suppose I could bring it in through a CDN and override the variables, but I'd rather work with the configuration directly through SCSS. Tailwind, on the other hand, rebuilds in less than a second. Its configuration is managed through PostCSS variables and a tailwind.config.js
file. It's excellent for rapid prototyping.
✔ Build
Compiled successfully in 331.37ms
Entrypoint index 189 KiB = index.css 47.3 KiB index.js 142 KiB
webpack 5.99.8 compiled successfully in 332 ms
Another big plus for Bootstrap and Tailwind is their globalization of styles. Every padding of such size is the same everywhere; when necessary, the theme changes in unison. They're normal CSS variables with hundreds of classes that use them.
// tailwind.config.js
const { createThemes } = require("tw-colors");
// Palettes declared here become globally available in Tailwind
// For example, using the `dark` theme, `bg-primary` returns #444444
const themes = createThemes({
dark: {
primary: {
DEFAULT: "#444444",
100: "#000000",
...
},
secondary: {
...
}
},
});
module.exports = {
content: ["./src/**/*.{eta,ts}"],
plugins: [ themes ],
};
Tailwind, notably, only includes classes that you reference within your content files. Cutting back on the included styles leads to extremely slim stylesheets. You can import specific classes and tools with Bootstrap, but it is neither automatic nor fine-grain. Below, you can see all of the background color classes generated by Tailwind for the website (at the time of writing):
.bg-black:not(#\#):not(#\#):not(#\#):not(#\#) {
background-color: var(--color-black);
}
.bg-blue-500:not(#\#):not(#\#):not(#\#):not(#\#) {
background-color: var(--color-blue-500);
}
.bg-gray-600:not(#\#):not(#\#):not(#\#):not(#\#) {
background-color: var(--color-gray-600);
}
.bg-gray-900:not(#\#):not(#\#):not(#\#):not(#\#) {
background-color: var(--color-gray-900);
}
.bg-secondary:not(#\#):not(#\#):not(#\#):not(#\#) {
background-color: var(--twc-secondary);
}
.bg-secondary-500:not(#\#):not(#\#):not(#\#):not(#\#) {
background-color: var(--twc-secondary-500);
}
.bg-tertiary-500:not(#\#):not(#\#):not(#\#):not(#\#) {
background-color: var(--twc-tertiary-500);
}
.bg-white:not(#\#):not(#\#):not(#\#):not(#\#) {
background-color: var(--color-white);
}
And, finally, Tailwind came out on top for me due to its composability. Once you've figured out what works, pull it out into a new class. PostCSS allows you to compose Tailwind classes into a larger class. Check it out:
.btn {
@apply bg-primary-500 hover:bg-primary-400 text-white
font-bold py-2 px-4 rounded-full;
}
The capacity to rapidly prototype and easily pull them into external styles is massive. I suppose you can do all of this in plain old CSS, but it winds up being significantly more verbose at the cost of being susceptible to browser inconsistencies.
That's it for this post. I'll try to have another up sooner than later. Beyond this website, there are other projects in the works.