Nov 24, 2020

Building Your Own CSS Framework

Create a framework like bootstrap 4 with custom theme colored components & responsive styling in under 10 minutes.

Author

Ashish Vikram BhogesaraAshish Vikram BhogesaraSenior Software Engineer - I
Building Your Own CSS Framework

Alright, People, we got 10 minutes on the clock and a framework to build. Although the time is short, I will explain to you, the process of building one and simultaneously, build some part of it in the process that would be enough to get you started and build one for yourself.

Why Build One?

Before we get the clock running and get into the thick of it, why do we need to build one in the first place? We don't build things just 'cause! Building a Framework gives us deeper insights about how one works and what goes into making one suit the ever changing needs of an Engineer. So, depending upon our use cases, we can modify the existing ones or create a new one.

What Is Needed?

What do you need?

Some experience with bootstrap version 3 or 4, some basic CSS (media queries is a must) & a little bit of SASS. Although, you can build one without SASS (or any CSS processor), but you would be seriously violating a lot of programming principles like KISS, DRY, etc and would probably end up writing a hell lot of spaghetti code.

Tick Tock! Let's go!

A framework like bootstrap has a lot of features like a responsive grid, typography, reusable multiple colored elements/components, forms, navigation, etc. We will start by focusing on building the responsive grid and custom theme based components. Let's start by building a theme-based button and then will build a responsive grid.

First, let’s start by creating a file app.scss which will hold all the code of our framework. Now, let’s write down all the main colors of our theme in a map in our app.scss

$theme-colors: (
   "primary" : #626ED4,
   "secondary" : #343549,
   "success": #2AA39A,
   "danger": #EC4561,
   "warning": #F8B425,
   "info": #38A5F8,
   "light": #f8f8fa,
   "dark": #575c62,
   "muted": #EDECF1
);

The next step is to create the base style for our class btn:

.btn{
   display: inline-block;
 
   padding: .375rem .75rem;
  
   font-weight: 400;
   font-size: 1rem;
   line-height: 1.5;
  
   border: 1px solid transparent;
   border-radius: .25rem;
 
   
   background-color: transparent;
   &:hover{
       cursor: pointer;
   }  
}

Now, wherever we use the btn class, the element will get the base style as defined above. Now, let’s focus on how we can create theme colored buttons with bootstrap like classes such as btn-primary, btn-secondary etc. For this, will have to loop through our colors map like below:

@each $name,$color in $theme-colors {
   .btn-#{$name}{
       background-color: $color;
       color: white;
   }
}

@each allows us to loop through a map in SCSS and gives us access to the key and value pair of the map. We can use the key to name the class and value to apply the background color. This will generate classes to allow us to style our buttons with respect to our theme colors.

Why stop at buttons when you could use the same process to create a number of components like badges, pills, progress bars, spinners etc. The sky's the limit and the possibilities are just endless, owing to just a few lines of code.

To summarize, create a base style for a component loop through the theme colors to get theme styled-components.

Are you still here? I’m glad you’re still reading.

Let me tell you a quick secret. You’re in for a treat.

Ever wanted a grid of odd no of columns or different breakpoints? You will soon learn just how to do it. If you have done the previous steps correctly, you would get this part pretty easily. 

Let's first decide the no of columns, grid breakpoints and the basic style for containers & rows.

$no-of-columns: 12;

$breakpoints: (
   "sm": 576px,
   "md": 768px,
   "lg": 992px,
   "xl": 1200px
);
 
.container{
   display: block;
   width: 100%;
   max-width: 1170px;
  
   padding: 0px 1rem;
   margin: 0px auto;
 
   &-fluid{
       display: flex;
       flex-direction: column;
  
       width: 100%;
      
       padding: 1rem 0px;
   }
}
 
.row{
   display: flex;
   flex-direction: row;
   flex-wrap: wrap;
   width: 100%;
}

Now, let's move towards generating the styles for our columns dynamically. For this, we will use our breakpoints map and loop through it, just like below:

@each $breakpoint,$value in $breakpoints {
   // RESPONSIVE COL CODE
}

We will then use a media query to restrict our columns styles to be included only after the query condition has been met. The following condition will loop through the breakpoints map and create media queries for it:

@each $breakpoint,$value in $breakpoints {
   // MEDIA QUERY
   @media only screen and (min-width: $value) {
       // RESPONSIVE COLUMN CODE .....
   }
}

We’re done with the heavy lifting for our code.

Now, we will have the 'number of columns' variable loop through it with a special @for loop, In our case, it will loop between 1 to the number of columns, while providing the current column number in the loop.

 @each $breakpoint,$value in $breakpoints {
       // MEDIA QUERY
       @media only screen and (min-width: $value) {
           // RESPONSIVE COLUMN CODE .....
           @for $i from 1 through $no-of-columns {
               .col-#{$breakpoint}-#{$i} {
                   width: (100% /  ( $no-of-columns / $i))  ;  
                   padding: 0px 1rem;
               }
           }
       }
   }

The base style of the columns are the padding & its width. The width is calculated depending upon the number of columns occupied. 

width: (100% /  ( $no-of-columns / $i))  ;  

The above code will generate responsive columns style & classes for all our breakpoints but we still need to create column style & classes for very small devices, which we will have to do manually.

@media only screen and (max-width: $extra-small-screen-width-breakpoint) {
       // RESPONSIVE COLUMN CODE .....
       @for $i from 1 through $no-of-columns {
           .col-#{$i} {
               width: (100% /  ( $no-of-columns / $i))  ;  
               padding: 0px 1rem;
           }
       }
   }

Tada! That's it! We’re done building our framework.

Recap

To summarize, in the first part, we defined our theme colors, created a basic button style then using those theme colors, we created a fleet of multi-theme colored buttons for our usage.

For the responsive grid, we defined the number of columns, breakpoints and the basic style for our container (grid) & row. Then, we looped through the breakpoints and, with the help of media queries, created column styles for each of our breakpoints. We, then looped through the columns to create a style for every column.

I hope this article has given you the basic understanding or building blocks of a CSS framework & shown you how you can use SASS to build one quickly for yourself, or just create theme-based components in minutes for your existing projects.

Thank you for reading!

Subscribe to Our Newsletter

RELATED ARTICLES

More from the engineering frontline.

Dive deep into our research and insights on design, development, and the impact of various trends to businesses.
The Bug That Doesn't Show Up in Code Review: Why Your Flutter Web App Reloads on Safari
The Bug That Doesn't Show Up in Code Review: Why Your Flutter Web App Reloads on Safari
A real-world look at how oversized images can trigger Safari reloads and iOS crashes in Flutter apps and how smarter image decoding prevents them.
From Prompting to Process: What Changed When Flutter Shipped Agent Skills
From Prompting to Process: What Changed When Flutter Shipped Agent Skills
This blog explores how Flutter Agent Skills improve AI-assisted development by combining official framework workflows with project-specific guidance for more consistent development.
Why Everything Your AI Builds Looks the Same
Why Everything Your AI Builds Looks the Same
This blog explores why AI-generated interfaces often look alike and explains how design systems, product context, and reusable engineering practices help teams build distinctive, scalable
How We Built the Missing Bridge from Code to Figma
Technology

Jul 10, 2026

How We Built the Missing Bridge from Code to Figma
This blog explores how AI-generated React apps get turned into fully editable, designer-ready Figma files by reading React Fiber instead of the DOM.
Building a Resilient Hybrid-Cloud Network with WireGuard HA, Route-Based Failover, and Deep Observability
Technology

Jun 27, 2026

Building a Resilient Hybrid-Cloud Network with WireGuard HA, Route-Based Failover, and Deep Observability
A practical breakdown of building resilient AWS-to-on-premises connectivity with WireGuard HA, active-standby failover, and deep packet-forwarding observability.
We Built a 114-Second AWS-to-Azure Failover. Here’s What We Learned
Technology

Jun 19, 2026

We Built a 114-Second AWS-to-Azure Failover. Here’s What We Learned
A practical guide to building a 114-second multi-cloud disaster recovery failover between AWS and Azure — what we built, what broke, and what we learned.
Cloud-Native and Cloud-Agnostic Are Not Ideologies; They Are Business-Stage Decisions
Technology

Jun 12, 2026

Cloud-Native and Cloud-Agnostic Are Not Ideologies; They Are Business-Stage Decisions
This blog explains how organizations can balance speed, scalability, and operational flexibility as they grow from startup to enterprise scale.

The Right Conversation Can Save You Six Months.

Whether you’re navigating AI adoption, modernizing legacy systems, or scaling a product - we start by listening. No pitch deck. No template. A real conversation.