🎨 Moving from vanillaCSS to TailwindCSS in an Express app using Pug templates 🎨
Disclaimer:
If you are only just starting with CSS and are tempted to take a shortcut with CSS frameworks, my personal opinion is: take your time. Styling is a BIG part of web app development and taking the time to learn and experiment with vanilla CSS will not only make you a more confident web developer but also save time in the future. It can seem overwhelming at first due to all the “rules” you’ve got to learn and you will have to do a lot of reading but it will payoff 💯 %.
I think it is easier / more enjoyable to start playing with a CSS framework like Tailwind once you have a good level of understanding and confidence with CSS.
As always one of the best place to learn web development technologies is:🔥🦊 https://developer.mozilla.org/en-US/docs/Learn/CSS .
Introduction
I recently had an impulse through work to start working with a CSS framework: TailwindCSS.
I have been writing vanilla CSS for a while and to be honest I quite like it. It is a very pleasant activity which in my opinion uses both the programming and graphic design areas of one’s brain. So I would often take a few days to fully focus on the styling of an app, this would give me the time to dig into the implementation details of a design, experiment with fonts / colors / responsive layouts. Sometimes getting stuck and spending 3 hours or more just switching between different colors or padding values. (We have all been there..)
This is fine if you like it and for small scale projects where one or maybe two devs are responsible for the whole project 👍. Now, in a bigger company setup where you typically have a separate design department the implementation work won’t be as straightforward. 📋
Especially when you consider an app which will be developed and maintained by different people through many years / version implementations — using custom CSS utility classes written and implemented by different devs at different time will create lots of frictions.
If on top of that you now consider a company which builds not only one app but a bunch of apps then it becomes even harder to follow and maintain. 🤯
You have two options: build a set of company-wide utility classes (building your own CSS framework) 🚀 or use a publicly available CSS framework ❤️.
Using a publicly available CSS framework will save some time but it would be great if that CSS framework was fully customisable so you could add your own color palettes, custom fonts and implements all those lovely designs from your Design department ? 👨🎨
Tailwind offers just that: 🖼 https://tailwindcss.com
“Because Tailwind is a framework for building bespoke user interfaces, it has been designed from the ground up with customization in mind.”
“ Extend it, tweak it, change it.”
“Tailwind includes an expertly crafted set of defaults out-of-the-box, but literally everything can be customized — from the color palette to the spacing scale to the box shadows to the mouse cursor. “
That sounds awesome ! I was quite convinced till my eyes fell upon that scary statement: “Rapidly build modern websites without ever leaving your HTML.” What ? No more CSS files… How come ? I love CSS files and I love writing them, they allow you to separate the style from the substance of you app, I don’t want to have cluttered HTML files… Right ?
But maybe I am being a bit change adverse and stuck in my ways, I have been working with vanilla CSS for a while, it is time to try something new!
Let’s dive in!
I gave myself the following exercise:
Converting an existing App built with vanilla CSS (and custom CSS utility classes) to only using Tailwind for styling.
The starting point for the project can be found here: https://github.com/argonathmos/joyeux
🐶 https://pugjs.org/api/getting-started.html
Part 1 — Install TailwindCSS
Our goal for part one is to install Tailwind in our app and go through the steps to make it usable directly in our Pug templates.
Simply clone the git repo and follow the steps detailed below to get started.
1.a — Install Tailwind via npm (without PostCSS and autoprefixer):
npm install -D tailwindcss@latest
Output :
1.b — Manually build your CSS file:
npx tailwindcss-cli@latest build -o public/styles/tailwind.css
(This will create the file tailwind.css — you are free to name it however you want).
Output :
1.c — Replace stylish.css by tailwind.css in the index.pug file:
link(rel=”stylesheet” type=”text/css” href=”styles/stylish.css”)
Now becomes:
link(rel=”stylesheet” type=”text/css” href=”styles/tailwind.css”)
(This is the stylesheet that the app will use)
1.d — Run the app locally
npm run dev
It should now look pretty basic as only the default tailwind styles (preflight) are applied — https://tailwindcss.com/docs/preflight
The stylish.css file is not loaded so the CSS classes in the pug file are not applied anymore (we can delete them from the index.pug )
👉 Don’t delete the stylish.css file yet, we will keep going back to our previously defined styles in order to translate them to Tailwind’s classes.
👉 If you want to start from step 1.d, use the code from this starting point: https://github.com/argonathmos/joyeux/commit/76d965972ab9fc972b8fade3eaf4d1d81b1cef51
It includes the tailwind install, the generated tailwind.css file and index.pug cleaned up.
Part 2 — Adding styles to HTML attributes via Classes
Our goal is to match our previous 🍦 vanillaCSS styling using Tailwind’s default utility classes only.
At this step we will “merge” stylish.css into index.pug , going through each properties in the CSS file and adding them as classes onto our html element in the pug file.
But how do I know the class names Tailwind uses ? There is so many ? You are right there is no point learning them. The official website is very well made and make it simple to find classnames by searching for a regular CSS properties. You will find what you are looking for plus a short and insightful description.
So we will simply search for classes matching our CSS properties in stylish.css
and apply them to our HMTL elements in index.pug
in order to style the app.
Properties applied to the body are now becoming classes onto the body element.
/* stylish.css */body { font-family: monospace; font-size: 15px; color: rgb(205, 217, 229); background-color: rgb(34, 39, 46); width: 75%; max-width: 640px; margin: 10px auto; display: flex; flex-direction: column; justify-content: center;}
Our previous styles applied via CSS properties inside a CSS file become a class attribute value on and HTML element in our Pug template.
//- index.pugbody(class=”font-mono text-base text-gray-50 bg-gray-800 w-3/4 max-w-screen-sm my-10 mx-auto flex flex-col justify-center”)
text-gray-50
is not exactly matching {color:rgb(205, 217; 229);}
but is close enough for now.
max-w-screen-sm
matches exactly our css property{max-width: 640px;}
Refresh the browser, the app should look like this:
We are getting close to our our original vanillaCSS file 💪, let’s keep adding Tailwind utility classes to our HTML elements to get as close as possible to
You can stop at any point, if you have gained enough understanding of the process or can take a few shortcuts by either:
- Using pre-existing combination of classes from Tailwind components: https://v1.tailwindcss.com/components/buttons#outline 👍
- Pulling the code from this commit to compare your code to mine after this step: https://github.com/argonathmos/joyeux/commit/dff90dd591b533c0ad99a0ce1a443a325c010de4
Part 3 (Optional) — Customising Tailwind:
Now we have moved from styles implemented through vanilla CSS (using our own utility classes) to styles implemented using Tailwind’s default utility classes.
The eagle eyed 🦅 reader will have noticed that some of the default styles provided by Tailwind don’t exactly match our previous styles from stylish.css .
We will now have a look at how to tweak Tailwind’s config files to implement our own custom styles.
3.a — Add webfonts
At the moment we are using Tailwind’s class font-mono
instead of our CSS property: body{font-family:monospace}
. I personally can’t tell the difference between 🧐 the two but let’s pretend we want to use another font: Space Mono by colophon-foundry.org ✒️👌.
i — The first step is to load the web font into the head section of the pug template:
link(href=”https://fonts.gstatic.com" rel=”preconnect”)link(href=”https://fonts.googleapis.com/css2?family=Space+Mono&display=swap" rel=”stylesheet”)
ii — Then create a tailwind.config.js file and replace the default font utility classes with our own:
module.exports = { theme: { fontFamily: { thatCoolColophonFont: [‘“Space Mono”’, “monospace”], }, },};=> ❤️ Ensure fonts with spaces are wrapped by “ “ .
iii — Rebuild our CSS file to overwrite tailwind default fontFamily utility classes:
npx tailwindcss-cli@latest build -o public/styles/tailwind.css
It will generate the following lines in our tailwind.css file:
.font-thatCoolColophonFont { font-family: “Space Mono”, monospace;}
iv — Update index.pug to use our new utility class: font-thatCoolColophonFont
v — Restart the server npm run dev and reload the page:
3.b — Add custom colors
We had 6 different colors in our stylish.css file which we moved away from to use exclusively colors from Tailwind’s default color palette. The default palette is very rich, great for rapid prototyping but what if you would like to use a custome color palette / scheme you took ages to come up with ? 🤔
By default, Tailwind color classes point to a default color palette:
gray-50 points to #F9FAFB
gray-800 points to #1F2937
pink-600 points to #DB2777 etc…
To change this and use our own colors, we need to add to tailwind.config.js file again to override the default color palette.
Our stylish.css file, we have used a mix of rgb()
functional notation, css named color
notation and RGB hex
notation-> 🤫 … let’s clean up and convert them all to RGB Hex notation. 🧹
i — Add `colors`field to tailwind.config.js to override the default color utility classes with our own color palette.
https://tailwindcss.com/docs/customizing-colors#custom-colors
module.exports = { theme: { fontFamily:{…}, colors: { gray: { 50: “#cdd9e5”, 600: “#495057”, 800: “#22272e”, }, blue: { 400: “#539bf5”, }, pink: { 600: “#DB277”, }, transparent: “transparent”, white: “#fff”, },},};
=> ❤️ We still have to define white and transparent if we want to use them as the config file will override all the tailwind predefined colors.
ii — Rebuild or css style to override Tailwind default colors with our own colors:
npx tailwindcss-cli@latest build -o public/styles/tailwind.css
iii — Restart the server and reload the page:
Our own colors are now being applied, without needing to update our classes in index.pug as the color classes now points to our own values. 👏👏
3.c — Add custom utility class (optional)
If you followed carefully 🦉 you might have noticed that we had the property {height: 40vh;} for our form element defined in stylish.css but I have used h-96 Tailwind’s class on that element as Tailwind doesn’t offer the equivalent in its pre-defined utility classes.
At the time of writing Tailwind only offer h-screen class which will make the height of the element: 100vh.
<div class=”h-screen”></div>
⬇️ ⬇️ ⬇️
div { height: 100vh;}
https://tailwindcss.com/docs/height#screen-height
There might be a good reason behind it: https://stackoverflow.com/questions/21624014/css-are-view-height-vh-and-view-width-vw-units-widely-supported. 🤷♂️
But let’s say I really want to add a height of 40 viewport-height to my form element, what are my options 🤓 ?
I could simply add a style attribute to my form element in the pug template (CSS inline styles) which will take precedence and override the h-96 class but that would mean mixing inline styling with Tailwind classes… I would like to stick to one approach.
Let’s create our own utility class: https://tailwindcss.com/docs/adding-new-utilities#using-css 🪄
i — Create a custom.css file in the folder of your choice (mine is /build at the root of the project)
// custom.css@tailwind base;@tailwind components;@tailwind utilities;@layer utilities { .h-screen-40 { height: 40vh; }}
ii — Manually build our tailwind.css file taking into account our custom.css file:
npx tailwindcss-cli@latest build build/custom.css -o public/styles/tailwind.css
The output of the command is
iii — Add our custom `h-screen-40` class to our form element in the pug template.
Part 4 (recommended) — Purge the generated CSS file
Removing unused CSS styles from our tailwind.css file — https://tailwindcss.com/docs/optimizing-for-production#basic-usage
By default Tailwind will generate a file containing all the CSS code their default utility classes will point to, but in a single project we use only a fraction those styles made available to us. Tailwind offers a way to remove this unnecessary styling properties from the generated style files.
4.a — Add the purge key to our tailwind.config.js file, and make sure to target all the files in which we are using tailwind classes (here only index.pug):
// tailwind.config.jsmodule.exports = { purge: [ ‘./views/*.pug’, ], theme: { … },}
4.b Manually build the tailwind.css file by running:
NODE_ENV=production npx tailwindcss-cli@latest build -o public/styles/tailwind.css
By setting NODE_ENV=production
, Tailwind will automatically “purge” the generated CSS.
If you followed the step 3.c, you will have to run:
NODE_ENV=production npx tailwindcss-cli@latest build build/custom.css -o public/styles/tailwind.css
To include our custom utility class.
Conclusion
We moved from vanilla CSS with pre-defiend custom CSS utility classes such as (.btn .form-control-field .form-control-label) in our stylish.css filed to using Tailwind’s utility classes directly in our Pug template, we didn’t need to write any CSS code in order to style our app (apart from adding custom configurations), though knowing CSS makes the process way easier as we can browse Tailwind’s website through CSS properties.
At this stage, I have no opinion on which approach is better, using Tailwind in a project could implement a sort of de facto standard for styling. So a big plus ✌️ if you work within a team and will help with maintenance in the future (the class names will stay the same and mean the same to everyone who knows Tailwind / can search the docs), plus you don’t have to write CSS files (we ended up adding a few classes to your HTML elements instead).
On the other hand, if you are working on a smaller project or if you want to create your own standard (and you like vanilla CSS and want to stick with it) by all means go for it 🏎 🏁 and create your own utility classes.
Regarding this particular exercise facts are: I got rid of my stylish.css file (replaced by the automatically generated tailwind.css file), HTML elements and their associated styles are all in one place: index.pug.
We also ended up with a “bloated” index.pug file with lots of CSS classes duplication: the classes in <p> elements, <input> elements and <label> elements needs to be written on each element. (This could be avoided by creating “Pug component” or “template partial” files and referencing them from the index.pug file https://pugjs.org/language/inheritance.html . But this will create extra work especially for a small project like this one).
I believe Tailwind is a great tool that offers lots of power and flexibility if you decide to implement it to force consistency between your projects.
In my opinion, using Tailwind would be even more interesting when building SPAs with components based frameworks such as Vue or React as you won’t have to worry about duplicating classes to style element as your App’s UI would likely be split in components already. Bonus: you won’t have to worry about styles scope anymore as using tailwind classes from within your component makes the styles de facto scoped to that component ! 👑 👑
Will try this in a future article: update a ⚛️ React App where style is implemented via “CSS modules” to use TailwindCSS.
✌️ Stay Awesome 😘