Sass Framework

How To Create Your Own Responsive Framework Using Sass – Part 1

What are Responsive Frameworks?

Responsive frameworks are used to help develop and design websites quickly using CSS selectors and classes and allow us to easily create responsive websites with ease. By developing our own responsive framework, we can easily understand how we can use our selectors and classes to quickly build responsive websites.

In this tutorial, I will be going over how to develop our own responsive framework using the Sass language. If you are not familiar with Sass, you can read my previous article called Using Extensible CSS Preprocessor Language: Sass or LESS for more information.

In any case, let’s begin the tutorial.

Start with Variables

Sass Variables
Let’s first start by creating variables for us to use in our responsive framework. Let’s create a _vars.scss file (the underscore is used to determine that we will use it as an import file…more on that later) and include the following CSS Preprocessor code in there. We’ll also include default values for some of our styling.

[CSS]
//spacing
$contentWidth: 1000px; //max width of our main content
$gridColumns: 12; // # of columns for our grid. Change as needed
$gutterWidth: 1%; // margin width of gutters between columns. Change as needed.Make sure to use percentages
$auto: 0 auto;

// Colors (feel free to change these values)
$green: #53c73f;
$orange: #ffa126;
$red: #d63838;
$blue: #4286B3;
$yellow: #f9f761;
$gray: #888888;
$white: #ffffff;
$black: #000000;

//elements
$linkColor: $blue;
$linkHover: lighten($blue, 20%);
$font-family: ‘Helvetica Neue’, ‘Helvetica’, Arial, sans-serif;
[/CSS]

Time for some Mixins

Sass Mixins
Now that we have that out of the way, let’s create a separate file for our mixins and name it _mixins.scss. We’ll include the following mixins to our framework. These mixins can also be found in my previous article Free and Useful Sass Mixins You Can Use for Your Next Project. The article also talks about the purpose of mixins and how they are used.

The great thing about mixins is that they will not be rendered unless you call them. Anyways, here are the mixins we’ll be using:

[CSS]
@mixin letterpress($opacity: 0.5){
text-shadow:0 1px 1px rgba(255,255,255,$opacity);
}
@mixin text-shadow($opacity:0.5){
text-shadow:0 1px 1px rgba(0,0,0,$opacity);
}
@mixin border-radius ($borderRadius){
-webkit-border-radius: $borderRadius;
-moz-border-radius: $borderRadius;
border-radius: $borderRadius;
}
@mixin box-shadow ($boxShadow…){
-moz-box-shadow: $boxShadow;
-webkit-box-shadow: $boxShadow;
-ms-box-shadow: $boxShadow;
-o-box-shadow: $boxShadow;
box-shadow: $boxShadow;
}

//border radius directions
@mixin border-top-radius ($borderRadius){
-webkit-border-top-left-radius: $borderRadius;
-webkit-border-top-right-radius: $borderRadius;
-moz-border-radius-topleft: $borderRadius;
-moz-border-radius-topright: $borderRadius;
border-radius: $borderRadius $borderRadius 0 0;
}
@mixin border-bottom-radius ($borderRadius){
-webkit-border-bottom-left-radius: $borderRadius;
-webkit-border-bottom-right-radius: $borderRadius;
-moz-border-radius-bottomleft: $borderRadius;
-moz-border-radius-bottomright: $borderRadius;
border-radius: 0 0 $borderRadius $borderRadius;
}
@mixin border-left-radius ($borderRadius){
-webkit-border-top-left-radius: $borderRadius;
-webkit-border-bottom-left-radius: $borderRadius;
-moz-border-radius-topleft: $borderRadius;
-moz-border-radius-bottomleft: $borderRadius;
border-radius: $borderRadius 0 0 $borderRadius;
}
@mixin border-right-radius ($borderRadius){
-webkit-border-top-right-radius: $borderRadius;
-webkit-border-bottom-right-radius: $borderRadius;
-moz-border-radius-topright: $borderRadius;
-moz-border-radius-bottomright: $borderRadius;
border-radius: 0 $borderRadius $borderRadius 0;
}

//for use of custom transitions
@mixin transition($transition) {
-webkit-transition: $transition;
-moz-transition: $transition;
-ms-transition: $transition;
-o-transition: $transition;
transition: $transition;
}
@mixin box-shadow-transition ($duration){
-webkit-transition: box-shadow #{$duration}s ease;
-moz-transition: box-shadow #{$duration}s ease;
-o-transition: box-shadow #{$duration}s ease;
transition: box-shadow #{$duration}s ease;
}

//transformations
@mixin box-rotate ($deg){
-webkit-transform: rotate(#{$deg}deg);
-moz-transform: rotate(#{$deg}deg);
-ms-transform: rotate(#{$deg}deg);
-o-transform: rotate(#{$deg}deg);
transform: rotate(#{$deg}deg);
}
@mixin scale($ratio) {
-webkit-transform: scale($ratio);
-moz-transform: scale($ratio);
-ms-transform: scale($ratio);
-o-transform: scale($ratio);
transform: scale($ratio);
}
@mixin translate($x, $y) {
-webkit-transform: translate($x, $y);
-moz-transform: translate($x, $y);
-ms-transform: translate($x, $y);
-o-transform: translate($x, $y);
transform: translate($x, $y);
}
@mixin skew($x, $y) {
-webkit-transform: skew($x, $y);
-moz-transform: skew($x, $y);
-ms-transform: skew($x, $y);
-o-transform: skew($x, $y);
transform: skew($x, $y);
}
@mixin translate3d($x, $y, $z) {
-webkit-transform: translate3d($x, $y, $z);
-moz-transform: translate3d($x, $y, $z);
-o-transform: translate3d($x, $y, $z);
transform: translate3d($x, $y, $z);
}

//Add opacity to elements
@mixin opacity($opacity){
-ms-filter: “progid:DXImageTransform.Microsoft.Alpha(Opacity=#{$opacity}*10)”;
filter: alpha(opacity=#{$opacity}*100);
-moz-opacity: $opacity;
-khtml-opacity: $opacity;
opacity: $opacity;
}

// Add an alphatransparency value to any background or border color
@mixin translucent-background($color: #fff, $alpha: 0.5) {
background: $color; //fallback
background: hsla(hue($color), saturation($color), lightness($color), $alpha);
}
@mixin translucent-border($size: 1px, $style: solid, $color: #fff, $alpha: 0.5) {
border: $size $style hsla(hue($color), saturation($color), lightness($color), $alpha);
background-clip: padding-box;
}

//gradients
@mixin gradient($startColor, $endColor, $noGradient: mix($startColor, $endColor,50%), $type: ‘vertical’, $degOrImagePath: ”){
@if ($type == ‘vertical’){
background: $noGradient;
@each $i in ” {
background: #{$i}linear-gradient(top, $startColor, $endColor) repeat-x mix($startColor, $endColor, 60%);
}
}

@if ($type == ‘horizontal’){
background: $noGradient;
@each $i in -webkit-, -moz-, -ms-, -o- {
background: #{$i}linear-gradient(left, $startColor, $endColor) repeat-x mix($startColor, $endColor, 60%);
}
background: linear-gradient(to right, $startColor, $endColor) repeat-x $endColor;
}

@if ($type == ‘radial’){
background: $noGradient;
@each $i in -webkit-, -moz-, -ms-, -o-, ”{
background: #{$i}radial-gradient(circle, $startColor, $endColor) no-repeat mix($startColor, $endColor, 60%);
}
}

@if ($type == ‘directional’){
background: $noGradient;
@each $i in -webkit-, -moz-, -ms-, -o-, ” {
background: #{$i}linear-gradient(#{$degOrImagePath}deg, $startColor, $endColor) repeat-x mix($startColor, $endColor, 60%);
}
}

@if ($type == ‘image’){
background: url(‘#{$degOrImagePath}’) no-repeat scroll $noGradient;
@each $i in -webkit-, -moz-, -ms-, -o-, ” {
background: url(‘#{$degOrImagePath}’) no-repeat scroll, #{$i}linear-gradient(center top, $startColor, $endColor);
}
}

}

@mixin gradient-vertical-three-colors($startColor: #00b3ee, $midColor: #7a43b6, $colorStop: 50%, $endColor: #c3325f, $noGradient: #444){
background: $noGradient;
@each $i in -webkit-, -moz-, -ms-, -o-, ” {
background: #{$i}linear-gradient($startColor, $midColor $colorStop, $endColor) no-repeat mix($midColor, $endColor, 80%);
}
}
@mixin gradient-vertical-button($highlightColor: #fbeda1, $topColor: #FFBB02, $bottomColor: #EB6900, $shadowColor: #b07504){
background: $bottomColor;
@each $i in -webkit-, -moz-, -ms-, -o-, ” {
background: #{$i}linear-gradient(top, $highlightColor 0%,$topColor 4%,$bottomColor 95%,$shadowColor 100%);
}
}

// triangles ($direction can be: up, down, left, right, up-right, up-left, down-righ or down-left)
@mixin triangle ($size, $color, $direction) {
height: 0;
width: 0;

@if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) {
border-color: transparent;
border-style: solid;
border-width: $size / 2;

@if $direction == up {
border-bottom-color: $color;
} @else if $direction == right {
border-left-color: $color;
} @else if $direction == down {
border-top-color: $color;
} @else if $direction == left {
border-right-color: $color;
}
}

@else if ($direction == up-right) or ($direction == up-left) {
border-top: $size solid $color;

@if $direction == up-right {
border-left: $size solid transparent;
} @else if $direction == up-left {
border-right: $size solid transparent;
}
}

@else if ($direction == down-right) or ($direction == down-left) {
border-bottom: $size solid $color;

@if $direction == down-right {
border-left: $size solid transparent;
} @else if $direction == down-left {
border-right: $size solid transparent;
}
}
}

//hide text for use with background images
@mixin hide-text{
overflow:hidden;
text-indent:-9999px;
display:block;
}

//for custom @font-face
@mixin family($family: ”, $url: ‘/fonts/’, $weight: normal, $style: normal) {
@font-face {
font-family: $family;
src: url(‘#{$url}.eot’);
src: url(‘#{$url}.eot?#iefix’) format(’embedded-opentype’),
url(‘#{$url}.woff’) format(‘woff’),
url(‘#{$url}.ttf’) format(‘truetype’),
url(‘#{$url}.svg#svg’) format(‘svg’);
font-weight: $weight;
font-style: $style;
}
}

// Clearfix for clearing floats like a boss (from h5bp.com/q)
@mixin clearfix() {
zoom: 1;
&:before,
&:after {
display: table;
content: “”;
zoom: 1;
}
&:after {
clear: both;
}
}

// browser specific————————-
@mixin ie7-inline-block() {
vertical-align: baseline; // for all other browsers
*vertical-align: auto; // set for consistency in IE7
*display: inline; // IE7 inline-block hack
*zoom: 1; //enables hasLayout
}

// IE7 likes to collapse whitespace on either side of the inline-block elements.
// Ems because we’re attempting to match the width of a space character. Left
// version is for form buttons, which typically come after other elements, and
// right version is for icons, which come before. Applying both is ok, but it will
// mean that space between those elements will be .6em (~2 space characters) in IE7,
// instead of the 1 space in other browsers.
@mixin ie7-restore-left-whitespace() {
*margin-left: .3em;

&:first-child {
*margin-left: 0;
}
}

@mixin ie7-restore-right-whitespace() {
*margin-right: .3em;

&:last-child {
*margin-left: 0;
}
}
[/CSS]

The Framework Structure

Sass Grid Structure
Now that we have our variables and mixins set up, let’s get into the actual nitty gritty structure of our framework. Let’s start by creating another file and naming it _default.scss. We’ll include all the structure styles and default styles for our framework within this file. I’ll also be explaining the three different portions of this file in detail below:

Imports and CSS Resets

Let’s start off by including our variables and mixins into our _default.scss file as well as some simple CSS resets.
[CSS]
// Import our _vars.scss and _mixins.scss files.
// Notice that I don’t include the underscore(_) or file extension(.scss) when importing our _vars.scss and _mixins.scss files
@import “vars”, “mixins”;

//—– CSS RESETS
* {
margin:0;
padding:0;
-moz-box-sizing: border-box; /* Firefox, other Gecko */
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
box-sizing: border-box; /* Opera/IE 8+ */
}
img {
border:0 none;
}
html {
width:100%;
height:100%;
min-height:100%;
}
body {
width: 100%;
color: #333;
position:relative;
text-align: left;
font-size: 1em;
line-height:1.4em;
font-family: $font-family;
background: #fff;
}
a {
color:$blue;
text-decoration: none;
&:hover {
color: lighten($blue, 20%);
}
}
.hidden {display: none;}

//—– GLOBAL FONTS

h1 {font-size: 2.4em;}
h2 {font-size: 1.4em;}
h3 {font-size: 1.2em;}
h4 {font-size: 1em;}
h5 {font-size: .8em;}
h6 {font-size: .6em;}
label {font-size: .8em;}
p {font-size: 1em;}
[/CSS]

As you may have noticed, we imported our _vars.scss and _mixins.scss files using @import function.

We are also using the new box model structure using the box-sizing properties for all our elements. (You can learn more about box-sizing from Chris Coyier’s box-sizing article ) This ensures that we don’t get weird padding and/or width issues for our responsive box-model elements.

Responsive Grid Structure

Next we’ll include our actual grid classes which is the main bulk of our responsive grid system. We’ll also include some breakpoints (media queries) that we’ll use for our desktop and mobile views.

[CSS]
//—– GRID STRUCTURE
/* Notice how we’re using the silent classes with the ‘%’ symbol. Silent classes were introduced in Sass version 3.2
* Silent classes are not rendered in your CSS file unless they are called upon, thus slimming down your CSS file size
* We’ll be using these silent classes when we start designing our actual webpages
*/
.grid {
overflow: hidden;
width:$contentWidth;
margin:$auto;
}
%gridBase {
float:left;
margin: 0 $gutterWidth;
}

// grid making magic
@for $i from 1 through $gridColumns {
.g#{$i} {
@extend %gridBase;
width: ((100%/$gridColumns)*$i)-$gutterWidth*2;
}
}

//—– BREAKPOINTS
@media only screen and (max-width: $contentWidth)
{
.grid {
width:100%;
margin: $auto;
}
}

@media only screen and (min-width: 0px) and (max-width: 480px)
{
.grid {width:100%;}
@for $i from 1 through $gridColumns {
.g#{$i} {
width: 100%;
margin: $auto;
}
}
}

[/CSS]

Let’s break this down to get a better understanding of how we’ll use this grid based system on our webpages. First let’s talk about the .grid class:
[CSS]
.grid {
overflow: hidden;
width:$contentWidth;
margin:$auto;
}
[/CSS]
You’ll notice that we are using overflow:hidden;. This is to prevent the issue of the container not covering the entire grids when working with floats (You’ll notice this if you apply a background color or something similar). Since our grid system will mostly be using floats to simulate columns, we need our parent container to clear and wrap around the entire grid system (using overflow:hidden; allows that to happen without adding unnecessary clear divs in our HTML markup).

You’ll also notice that we use the $contentWidth variable which is called from our _vars.scss file which we imported earlier on. This is the max-width we’ll be using as our base viewable area for desktops. And of course adding our margin: $auto; which also comes from our _vars.scss file.

Next, let’s break down the actual grid system:
[CSS]
%gridBase {
float:left;
margin: 0 $gutterWidth;
}

// grid making magic
@for $i from 1 through $gridColumns {
.g#{$i} {
@extend %gridBase;
width: ((100%/$gridColumns)*$i)-$gutterWidth*2;
}
}
[/CSS]
You’ll notice that we’re using the silent class called %gridBase. The reason for this is so that it doesn’t have to be rendered in the final CSS output(thus saving a few lines of code if you don’t need to call it). Instead, we will use this to extend our grid system.

As you can see, we’re also using a @for from through Control Directive to create our grid system.

What this does is reiterate through the number of $gridColumns we have set in our _vars.scss file (in this case, the default we set was 12 columns). Then it creates 12 grid-based classes that we’ll use in our HTML markup.

This is the actual CSS output of our @for from through function:
[CSS]
.g1, .g2, .g3, .g4, .g5, .g6, .g7, .g8, .g9, .g10, .g11, .g12 {
float: left;
margin: 0 1%;
}
.g1 {width: 6.33333%;}
.g2 {width: 14.66667%;}
.g3 {width: 23%;}
.g4 {width: 31.33333%;}
.g5 {width: 39.66667%;}
.g6 {width: 48%;}
.g7 {width: 56.33333%;}
.g8 {width: 64.66667%;}
.g9 {width: 73%;}
.g10 {width: 81.33333%;}
.g11 {width: 89.66667%;}
.g12 {width: 98%;}
[/CSS]
Notice how that the @for from through function created our grid system for us. You’ll also notice that the @extend %gridBase; applies the float left and margins to all our grid column classes. Furthermore, the @for from through function has also applied the appropriate widths of our columns to compensate for the gutter width that we had applied in our variables file. Play around with the $gridColumns and $gutterWidthvalues in the _vars.scss files to see how the grid system changes.

Lastly, let’s talk about our media query breakpoints which will help us display different grid-based system depending on device width:
[CSS]
//—– BREAKPOINTS
@media only screen and (max-width: $contentWidth)
{
.grid {
width:100%;
margin: $auto;
}
}

@media only screen and (min-width: 0px) and (max-width: 480px)
{
.grid {width:100%;}
@for $i from 1 through $gridColumns {
.g#{$i} {
width: 100%;
margin: $auto;
}
}
}
[/CSS]

You’ll notice that in the first breakpoint, once it reaches the max-width of our container, we make our main .grid class to 100% the width of our browser window.

The second media query will expand all our grid sizes to 100% width when it reaches 480px device width or lower.

This will become more apparent when we apply it to our webpage HTML structure. Primarily,we’ll be applying our grid like so:

[HTML]

G1
G2
G3
G4
G5
G6
G7
G8
G9
G10
G11
G12

[/HTML]

Extra Styling Elements (optional)

These are extra styling classes for input forms and buttons. Feel free to include this to your framework if needed.

[CSS]
//—– EXTRA STYLES
// input
input[type=”text”],
input[type=”number”],
input[type=”email”], textarea {
background: none repeat scroll 0 0 #fff;
border:1px solid #777;
@include border-radius(4px);
@include box-shadow(0 0 3px rgba(0, 0, 0, 0.25) inset, 0 0 3px rgba(0, 0, 0, 0.3));
color: $gray;
display: block;
float: left;
font-size: .8em;
height: auto;
margin: 0 0 6px 0;
padding: 0.2em;
line-height: 30px;
height:30px;
width: 100%;
}
textarea:focus,
input[type=”text”]:focus,
input[type=”number”]:focus,
input[type=”email”]:focus {
@include box-shadow(0 0 3px rgba(0, 0, 0, 0.5) inset,0 0 3px rgba(66, 134, 179, 0.8));
border:1px solid $gray;
color: #333;
text-shadow:0 1px 0 rgba(255,255,255,0.6);
}
input:focus::-webkit-input-placeholder,
input:focus::-moz-placeholder {
color: $gray;
}

//button classes
%btn {
width:auto;
height:auto;
color: #fff;
clear: both;
float: none;
font-weight: bold;
font-size: 1.3em;
padding: 6px 8px;
border: 0 none;
text-shadow:0 0 3px rgba(0,0,0,0.3);
@include box-shadow(0 1px 3px rgba(0,0,0,0.25));
@include border-radius(4px);
margin: $auto;
text-align: center;
display:block;
cursor:pointer;
position:static;
}
%blue-btn {
@extend %btn;
@include gradient-vertical-button(#87ccf9, #5aade4, #4286b3, #3777a1);
&:hover {
@include gradient(#4286b3, #519fd2,lighten(#4286b3,20%));
}
}
%red-btn {
@extend %btn;
@include gradient-vertical-button(#f98787, #e45a5a, #b93b3b, #a13737);
&:hover {
@include gradient(#b34242, #d25151,lighten(#b34242,20%));
}
}
%orange-btn {
@extend %btn;
@include gradient-vertical-button(#f3cd1b, #f2ac04, #e47203, #c65f04);
&:hover {
@include gradient(#e57403, #ef9d05,lighten(#e57403,20%));
}
}

[/CSS]

Conclusion

Download Source Files

This concludes Part 1 of the How To Create Your Own Responsive Framework Using Sass tutorial. I hope that this tutorial has helped you understand a little about how to create your own responsive frameworks.

The basic structure and code are just a small preview of how powerful and useful Sass (and other CSS preprocessor languages) is. I hope that this tutorial made you understand the basics of using Sass and all its possibilities.

In Part 2 of this tutorial series, I’ll walk you through the actual usage of how to implement our responsive framework. If you found this tutorial useful, please let me know in the comments below. Also, don’t forget to spread the word by Tweeting and Liking this tutorial. You can also sign up to the monthly newsletter to get updates, articles, and free tutorials such as this.

Other Articles you might like:

One thought on “How To Create Your Own Responsive Framework Using Sass – Part 1

Leave a Reply

Your email address will not be published. Required fields are marked *