A few days ago, I wrote Building Landing Page with Tailwind CSS – Install and Setup. Today is the final part. We will build a simple landing page with Tailwind CSS.
Landing Page
Below is the landing page we will build today. We have both desktop and mobile versions. We also build the tablet version as well which will look the same as a mobile version.
The mobile menu will be a simple dropdown menu that is controlled by JavaScript. It looks like the screen below.
Style guide
Color
We will use blue color as the main color of our landing page. We also have black, dark gray, light gray, and gray color as well. We will add these color via the config file.
Fonts
We will use self-hosting fonts and web fonts on our landing page. So you will learn how to add custom fonts from both sources.
For self-hosting fonts, we will use Antic and Bebas fonts which you can download from GitHub. You will add these fonts to the fonts folder.
For web font, we will use Roboto which we will add the CDN link to our index.html which is the main file for our project. We will add the CDN link later.
We will add these fonts via the config file.
Logo
We will use the logo font which is Antic.
Images (assets)
You can download the images for this tutorial from Github. All images will be stored in “img” folder.
Dist folder
In our tutorial, everything in the “dist” folder will be used for production.
Index.html
Okay, now the fonts and images are set. Next, we will start by adding the HTML markup in index.html. From Part 1, index.html is in the root. But in Part 2, I design to move index.html into “dist” folder. So your file structure will look like this.
|- tailwind-lp (root folder)
|– dist/index.html (our main file)
|– src/tailwind.css (Tailwind stylesheet)
|– dist/style.css (generated by Tailwind CLI later)
Now, add the code below to your index.html.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<title>Tailwind CSS - Simple Landing Page</title>
</head>
<body>
<!-- header STARTs -->
<header class="mx-auto px-8 bg-cover bg-no-repeat" style="background-image: url('img/hero-image.jpg');">
<!-- Nav bar -->
<nav class="flex justify-between py-5 text-white lg:px-16 ">
<!-- logo -->
<div class="py-4 logo uppercase text-white text-2xl filter drop-shadow-md">
SURF BROS</div>
<!-- menus bar -->
<div class="py-4 text-right">
<!-- menu button -->
<button id="btn-menu" class="relative top-2 lg:hidden">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
clip-rule="evenodd" />
</svg>
</button>
<!-- menus list -->
<ul id="menus" class="hidden mt-4 lg:mt-0 lg:flex lg:gap-2">
<li><a href="#" class="menu-link">home</a></li>
<li><a href="#" class="menu-link">about</a></li>
<li><a href="#" class="menu-link">testimonial</a></li>
<li><a href="#" class="menu-link">contact us</a></li>
<li class="mt-2 lg:mt-0">
<span class="btn"><a href="#" class="menu-link">reservation</a></span>
</li>
</ul>
</div>
</nav>
<!-- Hero section -->
<section
class="flex flex-col items-center sm:py-14 lg:px-5 lg:py-10 xl:px-16 xl:py-32 lg:flex-row lg:flex-wrap lg:justify-evenly">
<!-- text -->
<h1
class="text-white text-8xl py-2 sm:text-9xl md:mt-10 lg:mt-0 lg:py-0 lg:text-7xl xl:text-9xl 2xl:text-10xl opacity-75 filter drop-shadow">
explore<br>your
nature
</h1>
<!-- image -->
<img src="img/woman-surfing.png" alt="woman-surfing"
class="py-12 sm:w-11/12 md:p-12 md:mb-10 lg:w-2/4 lg:mb-0 lg:p-0 xl:w-6/12">
</section>
</header>
<!-- header ENDs -->
<!-- section STARTS -->
<main class="py-20 px-8 flex flex-col-reverse gap-20 lg:flex-row lg:py-20 lg:px-20 xl:px-10 2xl:py-32">
<!-- image -->
<div class="flex-1 w-full self-center md:py-20 lg:pr-10 lg:py-10 xl:pr-0">
<img src="img/founder-surf-bros.png" alt="Surf Bros Founder" class="w-max lg:w-full">
</div>
<!-- text -->
<div class="flex-1 self-center xl:pr-20 xl:pl-0">
<h1
class="pb-10 text-7xl gradient-header-title sm:text-8xl md:text-8xl md:py-10 lg:text-6xl xl:text-7xl 2xl:text-9xl 2xl:pt-0">
explore phuket beach today!
</h1>
<h4 class="pb-10 text-4xl sm:text-4xl md:pb-5 lg:text-2xl xl:text-4xl 2xl:text-6xl">Lorem ipsum dolor, sit
amet
consectetur
adipisicing elit.
</h4>
<p class="text-lg">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Eos quas atque, maiores
voluptatibus sequi
autem, aspernatur nam quos ipsam soluta debitis sit assumenda pariatur magnam? Repudiandae illo debitis
doloremque itaque. Lorem ipsum, dolor sit amet consectetur adipisicing elit. </p>
<!-- button -->
<div>
<a href="#"
class="btn btn-surf mt-10 p-3 capitalize text-xl inline-block sm:text-3xl 2xl:mb-10 2xl:text-4xl">explore
more
exciting</a>
</div>
</div>
</main>
<!-- section ENDS -->
<!-- section STARTS -->
<section class="py-20 px-8 bg-surf-light-gray sm:py-36 xl:pt-32 xl:pb-0">
<!-- title -->
<h2 class="pb-24 text-center text-7xl sm:text-8xl lg:text-8xl">how awesome <br
class="hidden md:block lg:block">we are
</h2>
<!-- features list -->
<ul class="feature-list">
<li class="feature-item">
<!-- image -->
<div style="background-image: url('img/tall-tress.jpg')"
class="flex-1 bg-no-repeat bg-cover bg-center 2xl:flex-size-1">
<img src="img/tall-tress.jpg" alt="tall trees" class="w-full object-cover opacity-0">
</div>
<!-- text -->
<div class="bg-white flex-1 2xl:flex-size-2">
<span
class="font-Bebas text-5xl text-surf-blue bg-white px-4 py-1 relative -inset-y-8 rounded-t-md xl:inset-x-0">01.</span>
<p class="px-5 sm:text-lg">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto,
dolorum.
Adipisci incidunt
unde
voluptatum repudiandae natus et nostrum officia sunt placeat, ut non tempora iste? Officia dicta
vel
non in.
Necessitatibus quidem in aspernatur facilis at incidunt, animi dicta laborum dolor accusamus
adipisci pariatur, odit iste molestias nisi officiis numquam, hic minus quos. Saepe in ratione
blanditiis provident fugit fuga.
</p>
<a href="#"
class="inline-block mt-10 mb-10 btn btn-surf text-lg pt-1 pb-1 capitalize sm:text-xl sm:p-3 sm:mb-20 xl:ml-5 xl:mb-9">read
more</a>
</div>
</li>
<li class="feature-item">
<!-- image -->
<div style="background-image: url('img/man-sitdown.jpg')"
class="flex-1 bg-no-repeat bg-cover bg-center 2xl:flex-size-1">
<img src="img/man-sitdown.jpg" alt="" class="w-full object-cover opacity-0">
</div>
<!-- text -->
<div class="bg-white flex-1 2xl:flex-size-2">
<span
class="font-Bebas text-5xl text-surf-blue bg-white px-4 py-1 relative -inset-y-8 rounded-t-md xl:inset-x-0">02.</span>
<p class="px-5 sm:text-lg">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto,
dolorum.
Adipisci incidunt
unde
voluptatum repudiandae natus et nostrum officia sunt placeat, ut non tempora iste? Officia dicta
vel
non in.
Necessitatibus quidem in aspernatur facilis at incidunt, animi dicta laborum dolor accusamus
adipisci pariatur, odit iste molestias nisi officiis numquam, hic minus quos. Saepe in ratione
blanditiis provident fugit fuga.
</p>
<a href="#"
class="inline-block mt-10 mb-10 btn btn-surf text-lg pt-1 pb-1 capitalize sm:text-xl sm:p-3 sm:mb-20 xl:ml-5 xl:mb-9">read
more</a>
</div>
</li>
<li class="feature-item">
<!-- image -->
<div style="background-image: url('img/man-with-surf.jpg')"
class="flex-1 bg-no-repeat bg-cover bg-center 2xl:flex-size-1">
<img src="img/man-with-surf.jpg" alt="" class="w-full object-cover opacity-0">
</div>
<!-- text -->
<div class="bg-white flex-1 2xl:flex-size-2">
<span
class="font-Bebas text-5xl text-surf-blue bg-white px-4 py-1 relative -inset-y-8 rounded-t-md xl:inset-x-0">03.</span>
<p class="px-5 sm:text-lg">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto,
dolorum.
Adipisci incidunt
unde
voluptatum repudiandae natus et nostrum officia sunt placeat, ut non tempora iste? Officia dicta
vel
non in.
Necessitatibus quidem in aspernatur facilis at incidunt, animi dicta laborum dolor accusamus
adipisci pariatur, odit iste molestias nisi officiis numquam, hic minus quos. Saepe in ratione
blanditiis provident fugit fuga.
</p>
<a href="#"
class="inline-block mt-10 mb-10 btn btn-surf text-lg pt-1 pb-1 capitalize sm:text-xl sm:p-3 sm:mb-20 xl:ml-5 xl:mb-9">read
more</a>
</div>
</li>
<li class="feature-item">
<!-- image -->
<div style="background-image: url('img/surfing.jpg')"
class="flex-1 bg-no-repeat bg-cover bg-center 2xl:flex-size-1">
<img src="img/surfing.jpg" alt="" class="w-full object-cover opacity-0">
</div>
<!-- text -->
<div class="bg-white flex-1 2xl:flex-size-2">
<span
class="font-Bebas text-5xl text-surf-blue bg-white px-4 py-1 relative -inset-y-8 rounded-t-md xl:inset-x-0">04.</span>
<p class="px-5 sm:text-lg">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto,
dolorum.
Adipisci incidunt
unde
voluptatum repudiandae natus et nostrum officia sunt placeat, ut non tempora iste? Officia dicta
vel
non in.
Necessitatibus quidem in aspernatur facilis at incidunt, animi dicta laborum dolor accusamus
adipisci pariatur, odit iste molestias nisi officiis numquam, hic minus quos. Saepe in ratione
blanditiis provident fugit fuga.
</p>
<a href="#"
class="inline-block mt-10 mb-10 btn btn-surf text-lg pt-1 pb-1 capitalize sm:text-xl sm:p-3 sm:mb-20 xl:ml-5 xl:mb-9">read
more</a>
</div>
</li>
</ul>
</section>
<!-- section ENDS -->
<!-- section STARTS -->
<section class="py-20 px-8 flex flex-col sm:flex-row sm:items-end">
<div class="flex-1 md:flex-size-1 lg:flex-1 xl:pl-28 2xl:flex-size-1">
<h3 class="text-surf-dark-gray text-4xl lg:text-6xl">subscribe</h3>
<div class="text-surf-blue font-Bebas text-3xl relative inset-x-3 -inset-y-2 lg:text-6xl">get our latest
news</div>
</div>
<div class="flex-1 md:flex-size-2 lg:flex-1 2xl:flex-size-2">
<form action="#" class="py-2 flex gap-1 md:justify-center lg:justify-start lg:pb-4">
<input type="email" placeholder="Your Email"
class="ring-1 ring-surf-gray bg-surf-light-gray px-2 py-1 rounded outline-none lg:w-4/6 xl:w-4/6 2xl:w-3/6">
<button
class="bg-surf-blue text-white font-Bebas px-5 py-1 rounded hover:bg-surf-dark-gray outline-none lg:text-2xl xl:text-3xl 2xl:text-5xl">go!</button>
</form>
</div>
</section>
<!-- section ENDS -->
<hr class="border border-gray-300 border-opacity-30">
<!-- footer STARTS-->
<footer class="px-8 pt-5 pb-10 flex flex-col text-center sm:flex-row sm:justify-between">
<div class="text-surf-gray">copyright@2021 <span class="uppercase">surf bros</span></div>
<div class="text-surf-gray">powered by <a href="https://applerinquest.com" title="WordPress developer"
class="text-surf-blue capitalize">apple rinquest</a>
</div>
</footer>
<!-- footer ENDS -->
</body>
<!-- Javascript STARTS -->
<script>
// # menu button
document.getElementById("btn-menu").addEventListener("click", openDropDownMenu);
// # show dropdown menu
function openDropDownMenu() {
const menus = document.getElementById("menus");
if (menus.style.display === "none" || menus.style.display.length === 0) {
menus.style.display = "block";
} else {
menus.style.display = "none";
}
}
</script>
<!-- Javascript ENDS -->
</html>
HTML5 doctype
You should use HTML5 doctype for Tailwind. With HTML5, we will be sure that Tailwind’s style will work as expected.
If you view the index.html using the Live Server extension in VS code, the result will look like this.
Header section
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- add Google web font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<title>Tailwind CSS - Simple Landing Page</title>
</head>
In the header section, we add the Google web font which is Roboto. We also add style.css which is generated by Tailwind Cli from Part 1. Moreover, we use HTML5 doctype and responsive viewport meta tag.
Tailwind.css, tailwind.config.js, style.css
Tailwind.css
Default Tailwind Style, Components and Utilities
Tailwind.css contains @tailwind directive and our custom style. From Part 1, we only add three tailwind directives as shown below.
/* https://tailwindcss.com/docs/functions-and-directives */
/* ./src/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
Base style is a global style at the beginning of the stylesheet. It is built on top of modern-normalize. Tailwind automatically injects the style by using ‘@tailwind base’ in your CSS. When you want to add your own style, you will apply the style by using ‘@layer base‘.
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
h1 {
@apply text-2xl;
}
h2 {
@apply text-xl;
}
}
Components, it is basically dealing with duplication styles that apply to common elements such as buttons, images, forms, and so on. Components are really useful when your project is getting bigger and more complex. With components, you can maintain the duplicated style in one place. Tailwind automatically injects your custom components by using ‘@layer components‘ in your CSS.
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer components {
.btn-blue {
@apply py-2 px-4 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75;
}
}
Utilities, Tailwind provides a ton of utility classes for you. But in some situations, you may need your own. Tailwind allows you to extend the utilities by using ‘@layer utilities‘ in your CSS.
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer utilities {
.scroll-snap-none {
scroll-snap-type: none;
}
.scroll-snap-x {
scroll-snap-type: x;
}
.scroll-snap-y {
scroll-snap-type: y;
}
}
Add our custom style in Tailwind.css
Next, we will add our own style for our landing page in Tailwind.css.
/* https://tailwindcss.com/docs/functions-and-directives */
/* ./src/tailwind.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* https://tailwindcss.com/docs/functions-and-directives#layer */
@layer base {
/* # add custom font by self-hosting */
/* https://tailwindcss.com/docs/adding-base-styles#font-face-rules */
@font-face {
font-family: "Antic";
font-weight: regular;
src: url('./fonts/ANTICFONT.woff') format('woff');
}
@font-face {
font-family: "Bebas";
font-weight: regular;
src: url('./fonts/Bebas-Regular.woff') format('woff');
}
body, nav {
@apply font-Roboto text-base;
}
p {
@apply text-surf-dark-gray;
}
h1, h2, h3, h4, h5, h6 {
@apply font-Bebas text-surf-dark-gray;
}
.logo {
@apply font-Antic;
}
/* menu link */
ul#menus li {
@apply py-1;
}
ul#menus li a.menu-link {
@apply mt-1 p-2 text-white text-center uppercase hover:text-surf-black transition duration-500;
}
.gradient-header-title {
@apply text-transparent bg-clip-text from-surf-blue-100 to-surf-blue-900 bg-gradient-to-r;
}
}
/* we add the repeat style for each HTML element in components */
@layer components {
/* button */
.btn {
@apply text-white rounded-lg ring-white ring-2 p-2 transition duration-500 hover:ring-surf-black;
}
.btn-surf {
@apply text-surf-blue rounded-xl ring-surf-blue text-4xl hover:ring-surf-dark-gray hover:text-surf-dark-gray;
}
button {
@apply transition duration-500;
}
/* feature list */
.feature-list {
@apply flex flex-col text-center flex-wrap lg:flex-row xl:text-left xl:pt-20;
}
.feature-item {
@apply lg:w-2/4 xl:flex xl:flex-row xl:mb-28;
}
.feature-item:nth-child(odd) {
@apply xl:pr-10;
}
}
For the code above, we apply our own base style and components using @layer directive. Layer directive will tell Tailwind where our custom style will be injected.
We also use @apply directive for applying any existing utility classes into our customs CSS.
How to apply the utility classes in HTML or Tailwind CSS
To learn how to use utility classes, visit Tailwind doc and review the existing utilities from there.
Add utility classes in HTML markup
For example, you want to add padding as 0 to an image element in HTML markup. The utility class you will use is p-0. What you have to do, is just apply p-0 via the class attribute of the image element.
<!-- apply padding:0 using Tailwind utility class -->
<img src=".." alt=".." class="p-0">
<!-- normal CSS without Tailwind utility class used -->
<img src=".." alt=".." style="padding:0;">
Add utility classes in Tailwind CSS
Also, you can add padding to the image element via Tailwind CSS.
@layer base {
img {
@apply p-0;
}
}
tailwind.config.js
As I mention in the Style guide section, we will add our own colors and fonts for our landing page. To do that, we will add color and fonts in tailwind.config.js which we already generated from Part 1.
generating config file
If you don’t have the config file yet, you can generate one by using this command in the terminal.
npx tailwindcss init
Here is the minimal config file that is generated by init command.
module.exports = {
purge: [],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
Now, you will replace the config file with this code.
module.exports = {
purge: ['./dist/**/*.html'],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {
// # add new background image
// https://tailwindcss.com/docs/background-image#background-images
// backgroundImage: theme => ({
// 'hero-image': "url('./img/hero-image.jpg')",
// }),
// # add new custom colors
// https://tailwindcss.com/docs/customizing-colors#extending-the-defaults
colors: {
'surf-blue': {
100: "#84D8EB",
200: "#73D3E8",
300: "#61CDE5",
400: "#50C8E2",
DEFAULT: "#38C1DF",
500: "#2CBCDD",
600: "#22B2D3",
700: "#1FA3C1",
800: "#1D95AF",
900: "#1A869E",
},
'surf-black': { DEFAULT: "#17272b" },
'surf-dark-gray': { DEFAULT: "#7a7a7a" },
'surf-light-gray': { DEFAULT: "#eeeeee" },
'surf-gray': { DEFAULT: "#dddddd" },
},
// # add new custom fonts (can use Google font or self-hosting)
// https://tailwindcss.com/docs/font-family#customizing
fontFamily: {
'Roboto': "'Roboto', sans-serif",
'Antic': "'Antic', san-serif",
'Bebas': "'Bebas', san-serif",
},
// # add new custom font size
// https://tailwindcss.com/docs/font-size#font-sizes
fontSize: {
'10xl': '10rem'
},
// # add new custom flex
flex: {
'size-1': '1',
'size-2': '2'
},
},
},
variants: {
extend: {
// # generate hover and active variants for ringColor
// https://tailwindcss.com/docs/ring-color#variants
ringColor: ['hover', 'active'],
},
},
plugins: [
],
}
Purge option
Purge option, this option is integrated with PurgeCSS by Tailwind. PurgeCSS will remove the unused CSS from the templates.
In our config file, we specify the templates( ‘./dist/**/*.html’ ) we want Purge to scan and remove unused CSS from style.css. Purge option is an array. You can add more templates and patterns as you want.
Dark mode option
DarkMode option, in this tutorial, we don’t use dark mode. But you can read more about dark mode and try it by yourself.
Theme option
Theme option, this option allows you to define your own color palette, fonts, border, breakpoints, and more.
In our config file, we add a new color palette, fonts, font size, and flex attribute in extend option. We add the new custom as extend option because we don’t want to override the default theme. But if you want to override the default theme, you can add your override directly under the theme option.
// tailwind.config.js
module.exports = {
theme: {
// Replaces all of the default `opacity` values
opacity: {
'0': '0',
'20': '0.2',
'40': '0.4',
'60': '0.6',
'80': '0.8',
'100': '1',
}
}
}
Variants option
Variants option, this option allows you to generate utility variants you want for each core plugin.
In our config file, we want to generate hover and active variants for ringColor class. The ring color will set the color for box-shadow property. By default, Tailwind doesn’t provide these variants but we will use them for our landing page. So we will generate those utilities for ring-color class.
For Tailwind, if you need more utility variants for the core plugin which are not generated by default, you can simply add them in the config file at the variants option. For overriding, you can add them directly in the variants option. For extending, you can add them in extend option under the variants option.
Plugins option
Plugins option, currently Tailwind provides four official plugins to use. These are Typography, Forms, Aspect Ratio, and Line Clamp. In our tutorial, we don’t use any of them.
For adding plugins, you can simply install the plugins and then add them to the config file. After that, you will build the stylesheet using Tailwind Cli.
Form plugin
For example, you want to use the Form plugin for basic resetting of the form styles. This way, you can use the Tailwind utilities without any cross-browser compatibility issues. The form plugin is useful for styling checkboxes, select boxes, dropdowns, and more. BTW, the Form plugin is designed for Tailwind CSS v2.0.
In order to use the form plugin, you need to install the plugin using npm in the terminal.
npm install @tailwindcss/forms
Then add the plugin into the config file as below.
// tailwind.config.js
module.exports = {
theme: {
// ...
},
plugins: [
require('@tailwindcss/forms'),
// ...
],
}
Finally, build the CSS file using Tailwind cli. That’s it. You can style your form using Tailwind utility classes.
Build Style.css from Tailwind.css
Once we add the custom style in tailwind.css, we need to build the stylesheet for production using Tailwind cli.
npx tailwindcss -i ./src/tailwind.css -o ./dist/style.css
By running the build command, tailwind will look at the config file (tailwind.config.js) first then look at tailwind.css and lastly, tailwind will generate the style.css for production.
After the style.css is built, you should see the final result for our landing page as below.
Tailwind Landing page for mobile
Miscellaneous
Tailwind CSS IntelliSense extension
In VS code, you can install and enable Tailwind CSS IntelliSense extension. This extension will show the Tailwind utility classes while you are working on the templates (HTML, JSX, and so on). In order to activate this extension, you need to install tailwindcss and have a tailwind config file names tailwind.config.js in your workspace.
PostCSS Language Support extension
In VS code, if you see some warning below, you will need PostCSS extension for it.
Responsive Design
Similar to other CSS frameworks, Tailwind provides five breakpoints by default.
Breakpoint prefix | Minimum width | CSS |
sm | 640px | @media (min-width: 640px) { … } |
md | 768px | @media (min-width: 768px) { … } |
lg | 1024px | @media (min-width: 1024px) { … } |
xl | 1280px | @media (min-width: 1280px) { … } |
2xl | 1536px | @media (min-width: 1536px) { … } |
With Tailwind, all you need to do is prefix the utility with breakpoint name (sm, md, lg, xl, 2xl). You can add the utility classes without leaving HTML. It is really cool. You can use the breakpoint name by adding the breakpoint name following to comma and then adding the utility class.
For example, on our landing page, we want to show the hamburger menu when the screen size is less than 1024px. Here is the code.
<!-- menu button -->
<button id="btn-menu" class="relative top-2 lg:hidden">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 15a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1z"
clip-rule="evenodd" />
</svg>
</button>
From the code, we add the hidden class to hide the dropdown menu when the screen size is bigger than 1024px. In the code, we simply add “lg:hidden” class at the button element. That’s it. It is very easy to use.
Another example, let’s say you want to add different padding values for each breakpoint, you can do this as shown below.
<button id="btn-menu" class="relative top-2 lg:hidden p-1 sm:p-2 md:p-3 lg:p-4 xl:p-5 2xl:p-6">
</button>
Tailwind doesn’t use the breakpoints to target the devices. All breakpoints are just breakpoints. Meaning, the sm breakpoint is not for the mobile device. Since Tailwind uses mobile first breakpoint system so any utility classes without breakpoint prefixes will take effect for all screen sizes. So the p-1 class will take effect for all screen sizes until the screen size hits 640px (sm), the p-2 class will then take effect for 640px breakpoint and wider screen. Once the screen size hits 768px (md), the p-3 class will then take effect, and so on. You get this.
The breakpoint name works for every utility class in the framework
Since you can use the breakpoint name for every utility class in the framework, you can change anything at the given breakpoint. This is really cool.
Mobile First
By default, Tailwind uses a mobile first breakpoint system. Any utility classes without breakpoint prefixes will take effect for all screen sizes.
In Tailwind, the sm prefix doesn’t mean to target the mobile device. Instead, it targets the small breakpoint. Tailwind uses unprefixed utilities to target mobile and override them at larger breakpoints. Below is an example.
<!-- This will center text on mobile, and left align it on screens 640px and wider -->
<div class="text-center sm:text-left"></div>
Hover, Focus, Other States
In our landing page, we use a hover state for the button. Similar to the breakpoint prefix, Tailwind uses the states following the comma and then the utility class. See the example below.
<button class="bg-surf-blue text-white font-Bebas px-5 py-1 rounded hover:bg-surf-dark-gray outline-none lg:text-2xl xl:text-3xl 2xl:text-5xl">go!</button>
For the code above, we add the hover state and change the background color to dark gray. All we need to do, we just add ” hover:bg-surf-dark-gray” class at the button element.
Note that, not all state variants are enabled by default. If you want to generate some for your project, you can add them to the tailwind config file as shown below. Then run the build command at the terminal.
variants: {
extend: {
// # generate hover and active variants for ringColor
// https://tailwindcss.com/docs/ring-color#variants
ringColor: ['hover', 'active'],
},
},
How do you know you need to generate new state for the core plugin, the easy way is, you just build the style without Purge config in the tailwind config file. Then you check the state with the utility classes you want in the built CSS file. If you don’t find any state with the utility classes you want then you will add those states into the config file and run the build command for generating them.
Container
Unlike containers in other frameworks, Tailwind’s container doesn’t center itself automatically. Also, it doesn’t have any built-in horizontal padding. Because Tailwind wants to totally reset the style and let you add the style you want from start.
To center a container, just use ‘mx-auto‘ utility. It will add margin-left and margin-right as auto.
To add horizontal padding, use ‘px-{size}‘ utility. For example, adding px-4, will add padding-left and padding-right as 1 rem.
If you like to center by default, you can add the config in the config file.
Flexbox and Grid
Tailwind provides you with Flexbox and Grid utilities which are easy to use. If you need more Flexbox and Grid properties, you just simply add the new properties to the config file.
Remove unused CSS
In our landing page, we can remove the unused CSS from style.css. This way, our style.css will be a smaller size.
To do that, we add the templates we want Purge to scan in the config file. In our case, it is index.html. But I like to add the pattern instead of a specific file name. Below is an example.
module.exports = {
purge: ['./dist/**/*.html'],
...
Next, we will run the build command by adding the NODE_ENV with production as shown below.
NODE_ENV=production npx tailwindcss -i ./src/tailwind.css -o ./dist/style.css
NODE_ENV with production will tell Tailwind cli to use PurgeCSS.
With this command, it will look for the config file first and then read the purge option. In this case, it finds ‘ ./dist/**/*.html ‘ at the purge option. So Purge will scan all HTML files under the “dist” folder to find the used Tailwind CSS and then Purge will remove the unused Tailwind CSS from style.css. The result is, style.css is a smaller size.
Minify CSS file
Just like other CSS preprocessors (Sass or Less), Tailwind can minify CSS. Tailwind uses cssnano for this. Simply add –minify at the build command as shown below.
NODE_ENV=production npx tailwindcss -i ./src/tailwind.css -o ./dist/style.css --minify
The result is, all comments, space, and new lines are removed from style.css.
Watch mode
When we develop the project and we need to run the build command manually every time the code changes, it is not fun and it consumes time. Just like other CSS preprocessors, we can add watch mode at the build command like so.
NODE_ENV=production npx tailwindcss -i ./src/tailwind.css -o ./dist/style.css --watch
To kill watch mode, you just hit Ctrl+c in the terminal.
Source code
You can download the source code from Github.
Explore more
You should explore Tailwind more at Tailwind’s doc and Tailwind lab YouTube channel.
Wrap up
Tailwind focuses on building complex components from the set of utilities. With the utility workflow, you can control any piece of your work and design almost everything. Furthermore, Tailwind doc is well-documented in my opinion.
For fast development, Tailwind offers paid UI components that are built with Tailwind CSS as well.
This tutorial, explains how to setup Tailwind CSS for your project. It tells you where to add the customization. It also tells you how to use the utility classes in HTML markup and Tailwind CSS. The idea behind the tutorial is, you see the big picture of Tailwind. You get the idea of how Tailwind works and how to use Tailwind. Moreover, it tells you what type of projects you should use Tailwind.
That’s it for Tailwind.