4
\$\begingroup\$

I am looking for opinions on this code. I have been experimenting with SASS the last few days and have come up with the following code. The idea was to enable the creation of a fluid grid without having non-semantic markup in the HTML.

$columns: 12; //total number of columns to use
$gutter: 3%; // gutter width can be any unit
$column_width: 5.3333%; // column width can be any unit

// calculated total width
$total_width: $columns * ($gutter + $column_width);

// Sub-pixel fix for IE http://tylertate.com/blog/2012/01/05/subpixel-rounding.html
// min width in pixels, do not append px to the number.
$min_width: 480;
$ie_correction: (.5 / $min_width) * 100 * 1%;


// calculate width of a column based on it's span.
@function width( $span ) {
        @return ( $span * $column_width ) + ( $gutter * ( $span - 1 ) );
}

// micro clearfix hack 
// http://nicolasgallagher.com/micro-clearfix-hack/
@mixin clearfix {
        &:before,
        &:after {
                content: "";
                display: table;
        }
        &:after {
                clear: both;
        }
        *zoom:1;
}

// Sets up a container for individual columns
@mixin row() {
        display: block;
        width: $total_width*(($gutter + width($columns))/width($columns));
        margin: 0 $total_width*((($gutter*.5)/width($columns))*-1);
        *width: $total_width*(($gutter + width($columns))/width($columns)) - $ie_correction;
        *margin: 0 ($total_width*((($gutter*.5)/width($columns))*-1)) - $ie_correction;
        @include clearfix;      
}

// Sets single column and determins the offset distance and direction.
//
// $span: default 1; Determins the width of the column;
// $type: default none; has three available options
//        push: pushes column to the right by the specified amount of columns
//        pull: pulls a column to the left by a specified amount of columns
//        center: centers a column of the desired size in the container
//
// $offset: default 0; determines the amount by which push and pull offset the column
// $last: default false; if true the column will be floated to the right; 

@mixin column( $span: 1, $type: none, $offset: 0, $last:false ) {
        @if $last == true {
                float: right;
        } @else {
                float: left;
        }
        width: width( $span );
        *width: width($span) - $ie_correction;
        @if $type == none {
                margin: 0 $gutter / 2;
                *margin: 0 (( $gutter / 2 ) - $ie_correction );
        } @else if $type == push {
                margin: 0 ( $gutter / 2 ) 0 ( width( $offset ) + ( $gutter * 1.5 ) );
                *margin: 0 ( ( $gutter / 2 ) - $ie_correction ) 0 ( width( $offset ) + ( $gutter * 1.5 ) - $ie_correction );
        } @else if $type == pull {
                margin: 0 ( width( $offset ) + ( $gutter * 1.5 ) ) 0 ( $gutter / 2 );
                *margin: 0 ( width( $offset ) + ( $gutter * 1.5 ) - $ie_correction ) 0 ( ( $gutter / 2 ) - $ie_correction );
        } @else if $type == center {
                diplay: block;
                width: width( $span );
                margin: 0 auto; 
                float: none !important;
        }
}

// Used to order columns right-to-left. Sets single column and determins the offset distance and direction.
//
// $span: default 1; Determins the width of the column;
// $type: default none; has three available options
//        push: pushes column to the right by the specified amount of columns
//        pull: pulls a column to the left by a specified amount of columns
//        center: centers a column of the desired size in the container
//
// $offset: default 0; determines the amount by which push and pull offset the column
// $last: default false; if true the column will be floated to the right; 

@mixin column_right( $span: 1, $type: none, $offset: 0, $last:false ) {
        @if $last == true {
                float: left;
        } @else {
                float: right;
        }
        width: width( $span );
        *width: width($span) - $ie_correction;
        @if $type == none {
                margin: 0 $gutter / 2;
                *margin: 0 (( $gutter / 2 ) - $ie_correction ) 0 (( $gutter / 2 ) - $ie_correction );
        } @else if $type == push {
                margin: 0 ( width( $offset ) + ( $gutter * 1.5 ) ) 0 ( $gutter / 2 ) ;
                *margin: 0 ( width( $offset ) + ( $gutter * 1.5 ) - $ie_correction ) 0 ( $gutter / 2 );
        } @else if $type == pull {
                margin: 0 ( $gutter / 2 ) 0 ( width( $offset ) + ( $gutter * 1.5 ) );
                *margin: 0 ( ( $gutter / 2 ) - $ie_correction ) 0 ( width( $offset ) + ( $gutter * 1.5 ) - $ie_correction );
        } @else if $type == center {
                diplay: block;
                width: width( $span );
                margin: 0 auto; 
                float: none !important;
        }
}


// Creates a grid from an elements children. By default it is designed to work
// on a unordered list, but it can work with any element type chosed by the 
// $element variable.
//
// $width: default 4; defines with amount of elemeents per row
// $margin: default $gutter variable; sets margin between each item
// $element: default li; defines the type element to target
@mixin grid( $width:4, $margin:$gutter, $element:li ) {
        @include clearfix;
        overflow: hidden;
        margin-left: -#{$margin};
        clear: both;
        & > #{$element} {
                float: left;
                display: block;
                width: ( $total_width / $width ) - $margin;
                margin: 0 0 $margin $margin;
                *width: ( $total_width / $width ) - $margin - $ie_correction;
                *margin: 0 0 ( $margin - $ie_correction ) ( $margin - $ie_correction );
                &:nth-child( #{$width}n + #{$width}) {
                        float: right;
                }
        }
}

Implementation is pretty straight forward.

column(5); // 5 column width ordered left to right
column(3, push, 3); //3 column width, pushing 3 columns from left
column(3, pull, 3); // 3 column width, pulling 3 columns from right
column(3, push, 2, true); // 3 columns, pushing 2 from left, and floated right as last column in row

column_right(5); // 5 columns ordered right to left
column_right(4, push, 3); //5 columns, right-to-left, pushing 3column widths from right

grid(4); // creates for a four up grid when applied to a ul, applies default margin
grid(5, 1%, div) // creates a five up grid with a 1% margin, which is applied to all child div elements.

I'm looking for opinions on what I can do better, and whether you think I'm overcomplicating the whole thing.

\$\endgroup\$
1
\$\begingroup\$

I think you are overcomplicating the whole thing. I have been building responsive design layouts for years, and there are really just not that many scenarios when a robust 'grid-system' isn't more work than it's worth. There isn't ever a 1 column area in a 12 column grid for example.

In my experience, there are big areas (almost like mini layouts) in your larger layout. Within those, you can stack things, and then with @media queries, float them into columns when it suites you. Then when at it's largest break-point, you can start using absolute positioning and stuff if you want to lock into a really specific layout.

Then the other situation is an actual grid of items or photos etc. That is a good time to have a little solution to split the chunks up, but really... how many do you have? 1, 2, 3, 4, 5 columns of things? Splitting them with percentages is the way to go, but depending on your markup, the gutters can be a challenge.

I have taken a few stabs at a simple grid, but they all have their own caveats. Using min and max widths for break-points can alleviate the need to overwrite nth-of-type rules. My latest favorite way to deal is to margin-right all list-items, then the actual item is usually a link - so a display block link... then the trick is to translate the whole list over to the left a little... anyways -

I think you'll find more cases where your 'grid' doesn't work than where is works perfectly and my suggestion is to break your ideas into a few different pieces.

This is my most recent build: http://codepen.io/sheriffderek/pen/azRpRM

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.