How to Build a Framework that is Actually Helpful

Written by euqueme | Published 2019/11/23
Tech Story Tags: css | sass | bootstrap | css-framework | tutorial | latest-tech-stories | bem-should-not-exist | frontend-development

TLDR In this post, I’m going to show you how I wrote a 4-thousand-lines CSS framework in less than 2 working days. This framework is based on Bootstrap which is a CSS framework. It also has the 5 breakpoints used by this famous framework for responsiveness. With less than 75 lines we were able to create 72 classes equivalent to 378 lines of code. We followed Bootstrap and kept the 12 column grid grid, but you can create more or less. Preprocessors are used to generate CSS code and make the web page layering enjoyable.via the TL;DR App

And also that you are capable of doing
Have you ever wonder how can I optimize my website a little bit? You probably use Bootstrap or Foundation but not really all of the classes.
You might be thinking: how hard would it be to build my own framework? And how could I, a simple human being be able to achieve such a task?
In this post, I’m going to show you how I wrote a 4-thousand-lines CSS framework in less than 2 working days. You want to see it for yourself? Go to my Github repo.
Okay, I didn’t do it all by myself, I had a very helpful coding partner. But still, after you are done with this you’ll be able to do it alone and even faster.
This framework is based on Bootstrap which is a CSS framework. A lot of the classes’ names are the same or similar to Bootstrap. It also has the 5 breakpoints used by this famous framework for responsiveness.
Here are the most important things we took into account for this process:

Base it on a page (and don’t be afraid)

Or your own website. This framework was done for the ionos page (your welcome!) This is going to help for specific styling like colors, font type, font size, etc..
Later on, I’ll explain what I mean with don’t be afraid, but you’ll probably figure it out soon enough.

Preprocessors (or should I say lifesavers)

There are plenty of preprocessors out there for CSS coding, we use SASS for this framework.
But what are Preprocessors and why should I use them? you’d be asking… to keep it simple, Preprocessors are used to generate CSS code and well, make the web page layering enjoyable this means that you’ll be able to use variables, loops and a lot of useful functions to create repetitive CSS code. And if you check out, any Framework out there has tons of repetitive rules.
This is what is going to make you achieve writing lots of code with only a few lines. This article it’s pretty straight forward on how to use them

Keep it organized

If you’re a costume to layout web pages at this point, you already know that having only one CSS file on your website its a good practice, but you can have as many SCSS files as you need to.
Take advantage of this and put your reset and variables (at least) outside the main SCSS file.
This is how we imported all the SCSS files to the main.SCSS file:
//import.scss
@import "reset";
@import "variables";
@import "spacing";
@import "display";
@import "width-height";
@import "font-color";
these were the files:

Grid and gutters

The most important part of the framework, the backbone if you will. We followed Bootstrap and kept the 12 column grid, but you can create more or less it’s up to you.
There are many ways to achieve this, I think our gutters (the space between the columns) were a little bit too thick but again it’s up to you to decide these factors.
We used percentages to calculate the width of the columns and the formula is pretty straight forward:
$column-width: (100%-$gutter-width*12)/12
I must share with you the code applying this formula we used to create the responsive 12 column grid and all the responsive breakpoints:
//SCSS code for 12 column grid

//VARIABLES
$xs: xs;
$sm: sm;
$md: md;
$lg: lg;
$xl: xl;

$breakpoint-xs: 575px;
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;

$class-col: col;
$gutter-width: 1%;
$column-width: 7.33%;

//MAIN
@mixin grid-unit-normal($span) {
  float: left;
  margin-right: $gutter-width;
  width: ($column-width * $span) + ($gutter-width * ($span - 1));
}

@mixin grid-unit($span) {
  float: left;
  margin-right: $gutter-width;
  width: ($column-width * $span) + ($gutter-width * ($span - 1)) !important;
}

@for $i from 1 through 12 {
  .#{$class-col}-#{$i} {
    @include grid-unit-normal($i);
  }
}

@for $i from 1 through 12 {
  @media screen and (max-width: $breakpoint-xs) {
	.#{$class-col}-#{$xs}-#{$i} {
      @include grid-unit($i);
	}
 }
}

@for $i from 1 through 12 {
  @media screen and (min-width: $breakpoint-sm) {
	.#{$class-col}-#{$sm}-#{$i} {
      @include grid-unit($i);
	}
 }
}

@for $i from 1 through 12 {
  @media screen and (min-width: $breakpoint-md) {
	.#{$class-col}-#{$md}-#{$i} {
      @include grid-unit($i);
	}
 }
}

@for $i from 1 through 12 {
  @media screen and (min-width: $breakpoint-lg) {
	.#{$class-col}-#{$lg}-#{$i} {
      @include grid-unit($i);
	}
 }
}

@for $i from 1 through 12 {
  @media screen and (min-width: $breakpoint-xl) {
	.#{$class-col}-#{$xl}-#{$i} {
      @include grid-unit($i);
	}
 }
}
//12 column grid CSS code result


/*Result*/
.col-1 {
  float: left;
  margin-right: 1%;
  width: 7.3333333333%; 
}

.col-2 {
  float: left;
  margin-right: 1%;
  width: 15.6666666667%; 
}

.col-3 {
  float: left;
  margin-right: 1%;
  width: 24%; 
}

.col-4 {
  float: left;
  margin-right: 1%;
  width: 32.3333333333%; 
}

.col-5 {
  float: left;
  margin-right: 1%;
  width: 40.6666666667%; 
}

.col-6 {
  float: left;
  margin-right: 1%;
  width: 49%; 
}

.col-7 {
  float: left;
  margin-right: 1%;
  width: 57.3333333333%; 
}

.col-8 {
  float: left;
  margin-right: 1%;
  width: 65.6666666667%; 
}

.col-9 {
  float: left;
  margin-right: 1%;
  width: 74%; 
}

.col-10 {
  float: left;
  margin-right: 1%;
  width: 82.3333333333%; 
}

.col-11 {
  float: left;
  margin-right: 1%;
  width: 90.6666666667%; 
}

.col-12 {
  float: left;
  margin-right: 1%;
  width: 99%; 
}

//Breakpoints for col-1
@media screen and (max-width: 575px) {
  .col-xs-1 {
    float: left;
    margin-right: 1%;
    width: 7.3333333333% !important;
  }
}

@media screen and (min-width: 576px) {
  .col-sm-1 {
    float: left;
    margin-right: 1%;
    width: 7.3333333333% !important; 
  } 
}

@media screen and (min-width: 768px) {
  .col-md-1 {
    float: left;
    margin-right: 1%;
    width: 7.3333333333% !important; 
  } 
}

@media screen and (min-width: 992px) {
  .col-lg-1 {
    float: left;
    margin-right: 1%;
    width: 7.3333333333% !important; 
  } 
}

@media screen and (min-width: 1200px) {
  .col-xl-1 {
    float: left;
    margin-right: 1%;
    width: 7.3333333333% !important; 
  } 
}
In the result above I’m only showing you the 12 column grid and all of the breakpoints for the first column.
With less than 75 lines we were able to create 72 classes equivalent to 378 lines of code!
Yeah yeah… you would say 75 lines it’s a bit much, maybe you could’ve done it with a lot less, Maru…
And you are right! In fact, this was the first section we built and we were still getting the hang of SASS. But for something we code in 2 days I think we did a good job. After all, the goal is to make your life easier, and if you are too focused on doing it perfectly, you’ll probably end up complicating your work even more.
But the sections to come are a little bit more optimized I promise!

Sizing and spacing

Just as Bootstrap, this framework has classes for margins and paddings (left, right, top and bottom), and they are also responsive; Bootstrap only has up to 6 levels of margin and padding, from 0 to 3rem but in this framework, we added 5 more to make our lives easier.
$sizes: 0, 0.5rem, 1rem, 1.5rem, 2rem, 2.5rem, 3rem, 3.5rem, 4rem, 4.5rem, 5rem;
Also, Bootstrap only includes 4 levels of sizing classes for 25%, 50%, 75% and 100% width and height, in our framework, we use 10 (from 10% to 100%)and again you can add as many as you need or want to.
Here is the code we use to create the classes for width and height:
//VARIABLES
$breakpoints:  $sm, $md, $lg, $xl;

$breakpoint-xs: 575px;
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;

$breaks: $breakpoint-sm, $breakpoint-md, $breakpoint-lg, $breakpoint-xl;

$wh-options: 10;

// Width and Height 

@for $i from 1 through 10 {
  .h-#{$wh-options * $i}{
    height: ($wh-options * $i)#{"% !important"};
  }
  .w-#{$wh-options * $i}{
    width: ($wh-options * $i)#{"% !important"};
  }
}

$j: 1;
@each $break in $breaks {
  @media screen and (min-width: $break) { 
    @for $i from 1 through 10 {
      .h-#{nth($breakpoints,$j)}-#{$wh-options * $i}{
        height: ($wh-options * $i)#{"% !important"};
      }
      .w-#{nth($breakpoints,$j)}-#{$wh-options * $i}{
        width: ($wh-options * $i)#{"% !important"};
      }
    }
  }   
  $j: $j + 1
}
With the lines above we generated more than 400 lines of CSS code; 10 classes for each: width and height, and we repeated the same 20 classes for each of the 4 responsive breaks.
Wich translates to 100 classes… now we are talking!

Positioning the elements

Now that you have all your columns and rows, and also are happy with the size of your elements, you have to decide how the content is going to be displayed or aligned: you could use flexbox or grid, (or both?) to create the main layout. In this framework, we used flexbox.
And this is is the good stuff right here:
//VARIABLES
$xs: xs;
$sm: sm;
$md: md;
$lg: lg;
$xl: xl;
$breakpoints: $sm, $md, $lg, $xl;
$breakpoint-xs: 575px;
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;
$breaks: $breakpoint-sm, $breakpoint-md, $breakpoint-lg, $breakpoint-xl;
$display-flex: justify-content, align-content;
$flex-name: start, end, around, between, center;
$flex-options: flex-start, flex-end, space-around, space-between, center;
$align-flex: align-items, align-self;
$align-names: start, end, center, stretch, baseline;
$align-options: flex-start, flex-end, center, stretch, baseline;

//DISPLAY-FLEX OPTIONS
@each $display in $display-flex {
  $i: 1;
  @each $option in $flex-options {
    .#{$display}-#{nth($flex-name, $i)} {
      #{$display}: #{$option} !important;
    }
  $i: $i + 1;
  }
}

$j: 1;
@each $break in $breaks {
  @media screen and (min-width: $break) {
    @each $display in $display-flex {
      $i: 1;
      @each $option in $flex-options {
        .#{$display}-#{nth($breakpoints,$j)}-#{nth($flex-name, $i)} {
          #{$display}: #{$option} !important;
      }
      $i: $i + 1;
      }
    }
  }
  $j: $j + 1
}

//ALIGN-FLEX OPTIONS
@each $align in $align-flex {
  $i: 1;
  @each $option in $align-options {
    .#{$align}-#{nth($align-names, $i)} {
      #{$align}: #{$option} !important;
    }
    $i: $i + 1;
  }
}

$j: 1;
@each $break in $breaks {
  @media screen and (min-width: $break) {
    @each $align in $align-flex {
      $i: 1;
      @each $option in $align-options {
        .#{$align}-#{nth($breakpoints,$j)}-#{nth($align-names, $i)} {
          #{$align}: #{$option} !important;
        }
        $i: $i + 1;
      }
    }
  }
  $j: $j + 1
}

@each $direction in $flex-direction {
  .flex-#{$direction} {
    flex-direction: #{$direction} !important;
  }
}

@each $break in $breaks {
  @media screen and (min-width: $break) {
    @each $direction in $flex-direction {
      $j: 1;
      .flex-#{$direction}-#{nth($breakpoints,$j)} {
        flex-direction: #{$direction} !important;
      }
    }
  }
  $j: $j + 1
}
Now is your turn to test it out! But you can always check it out in my repo.
With only 90 lines we were able to create 200 classes!
And last but not least:

Don’t be afraid!

You are probably tired of me repeating it again and again and probably by now you realized this:
Add as many classes as you need or want!
Remember this is not Bootstrap or Foundation, this is your own Framework and you are doing this to make your work of layering pages easier.
Not only we added variables for the palette of colors of the website this framework was created for (just like Bootstrap),
we also added classes to set color to each side of the borders, unlike Bootstrap.
//Variables
$main: #001b41;
$secondary: #465a75;
$main-blue: #003d8f;
$light-blue: #0b9dcc;
$soft-blue: #28cce8;
$secondary-blue: #3364a5;
$light: #fff;
$light-gray: #f6f7f8;
$article-blue: #0357a0;
$footer-blue: #0b2863;

// change _font-color file if more colors are added
$colors: $main, $secondary, $main-blue, $light-blue, $soft-blue, $secondary-blue, $light, $light-gray, $article-blue, $footer-blue;
$color-names: main, secondary, main-blue, light-blue, soft-blue, secondary-blue, light, light-gray, article-blue, footer-blue;

$side-name: "left", "right", "top", "bottom";

//Background & Border Colors
$i: 1;
@each $color in $colors {
  .bg-#{nth($color-names, $i)} {
    background-color: $color;
  }
  .border-#{nth($color-names, $i)} {
    border: solid 1px $color;
  }
  .#{nth($color-names, $i)} {
    color: $color;
  }
  $i: $i +1;
}

// change if more colors are added
@each $side in $side-name {
  @for $k from 1 through 10{
    .border-#{$side}-#{nth($color-names, $k)} {
      border-#{$side}: solid 1px #{nth($colors, $k)};
    }
  }
}

.border-none{
   border: none !important;
}
The result for the code above is right here
This is what’s going to make the difference: you are not only saving your website from loading unused classes,
you are also creating useful classes that weren’t in the framework you were using in the first place,
and you won’t have to repeat them on every CSS file of your website never again!
ta-da!

That’s it!

Congratulations! If you follow this article to the end, you have successfully created your own framework and survived in the process.
What’s next? you’d be asking… Well, you can keep adding classes or modifying the ones that already exist but you have created the main core of a very useful framework you can call your own.
If you want to see this framework up and running it’s right here.
I’d like to hear from you! Was this article helpful? Tell me all about your experience in the process of creating your own framework!
claps to you!


Published by HackerNoon on 2019/11/23