Building Your Own CSS Framework

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 Bhogesara
Ashish Vikram BhogesaraSenior Software Engineer - I

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

More from the engineering frontline.

Dive deep into our research and insights on design, development, and the impact of various trends to businesses.
Insight
Building a Real-Time Photo Sync Video Experience Using 100ms SDK and Reactive State Management
Oct 15, 2026

Building a Real-Time Photo Sync Video Experience Using 100ms SDK and Reactive State Management

This blog explains how to build a real-time video experience with synchronized photo sharing, chat, and reactive state management using the 100ms SDK.

Insight
Taming Elasticsearch at Scale
Oct 13, 2026

Taming Elasticsearch at Scale

Optimize Elasticsearch for millions of records with better pagination, leaner payloads, efficient filtering, faster ingestion, and frontend techniques that keep search responsive with increase in data.

Insight
Deep Linking for Mobile Apps(React Native) with NestJs, AWS CloudFront, S3 & ALB: A Complete Guide
Oct 13, 2026

Deep Linking for Mobile Apps(React Native) with NestJs, AWS CloudFront, S3 & ALB: A Complete Guide

Build a self-hosted deep linking and referral system for React Native without a third-party SDK. This guide covers Android App Links, iOS Universal Links, an S3 and CloudFront setup, and a NestJS backend that routes users to the right app store.

Insight
How We Engineered a Three-Path Reward Processing System for a Real-Time Sports Platform
Oct 12, 2026

How We Engineered a Three-Path Reward Processing System for a Real-Time Sports Platform

This blog explains how a real-time sports platform uses synchronous, asynchronous, and scheduled processing paths to handle rewards without slowing down the player experience.

Insight
Building an MCP-Powered QA Agent
Oct 12, 2026

Building an MCP-Powered QA Agent

Build an MCP QA agent that runs Playwright tests, validates APIs, and analyzes failures through a controlled, auditable tool layer with human approval.

Insight
From Test Failure to Root Cause: Building an AI-Assisted Playwright Failure Analysis Pipeline
Oct 9, 2026

From Test Failure to Root Cause: Building an AI-Assisted Playwright Failure Analysis Pipeline

This blog explains how an AI-assisted Playwright pipeline can analyze test failure evidence, identify probable root causes, and support human-validated debugging.

Insight
The Model Context Protocol: From First Call to Production
Oct 8, 2026

The Model Context Protocol: From First Call to Production

This blog explains how Model Context Protocol (MCP) works, from tool discovery and execution to OAuth authorization, security controls, and production deployment.

Footer

The Right Conversation Can

Save You Six Months.

Book a Call