Skip to content

JSS fractional grid system built with calc(), based on Lost PostCSS grid. Supports masonry, vertical, and waffle grids.

License

Notifications You must be signed in to change notification settings

wldcordeiro/perdido

Repository files navigation

Perdido JSS Grid System

npm version

Perdido is a grid system for JSS, it is mostly a translation of the wonderful Lost PostCSS Grid (thus the name as "perdido" means lost in Portuguese and Spanish.) Perdido comes with a set of functions that you can use in your JSS to create fluid grids easily.

Perdido has requirements for the following JSS plugins, so make sure to install and initialize them.

  1. jss-extend
  2. jss-nested
  3. jss-camel-case
  4. jss-default-unit
  5. jss-vendor-prefixer

Table of Contents

  1. Example
  2. Guide
    1. Basic Columns
    2. Centering Elements
    3. Controlling Cycle
    4. Nesting
    5. Offsetting Elements
    6. Alignment
    7. Edit Mode
    8. Vertical Grids
    9. Waffle Grids
    10. Flexbox Grids
    11. Masonry Support
  3. API
    1. Perdido.utils
      1. utils.edit
      2. utils.clearFix
    2. Perdido.align(..)
    3. Perdido.center(..)
    4. Perdido.column(..)
    5. Perdido.flexContainer(..)
    6. Perdido.masonryColumn(..)
    7. Perdido.masonryWrap(..)
    8. Perdido.move(..)
    9. Perdido.offset(..)
    10. Perdido.row(..)
    11. Perdido.waffle(..)
  4. Options
  5. Contributing
  6. Thanks

Example

Say we had a simple HTML block like a section with three inner article's and we wanted to split it into a 1/3 grid. With Perdido we could do this to generate the style block containing your grid.

<section>
    <article>1</article>
    <article>2</article>
    <article>3</article>
</section>
// ES6/7/2015/whatever you call it
import jss from 'jss';
import extend from 'jss-extend';
import nested from 'jss-nested';
import camelCase from 'jss-camel-case';
import defaultUnit from 'jss-default-unit';
import vendorPrefixer from 'jss-vendor-prefixer';
import perdido from 'perdido';


jss.use(extend());
jss.use(nested());
jss.use(camelCase());
jss.use(defaultUnit());
jss.use(vendorPrefixer());


var sectionStyle = {
    section: {
        '& article': {
            ...perdido.column('1/3'),
        }
    }
}

jss.createStyleSheet(sectionStyle, {named: false}).attach();

The processed CSS that would be produced looks like this.

section article {
  width: calc(99.99% * 1/3 - (30px - 30px * 1/3));
}
section article:nth-child(n) {
  float: left;
  clear: none;
  margin-right: 30px;
}
section article:last-child {
  margin-right: 0;
}
section article:nth-child(3n) {
  float: right;
  margin-right: 0;
}
section article:nth-child(3n + 1) {
  clear: left;
}

⬆️ back to top

Guide

Basic Columns

To create a basic horizontal grid, just insert some elements into any containing element like so and pass a fraction to the Perdido.column method. To unset (or remove) a column rule, possibly at a larger breakpoint, use Perdido.column('none');

<section>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
</section>
{
    section: {
        ...perdido.utils.clearFix,
        '& div': {
           ...perdido.column('1/3'),
        }
    }
}

Perdido.utils.clearFix is just a clearfix style object since Perdido Grid elements are floated. It's a good idea to give this to the element wrapping your grid elements every time you have nested floated elements.

⬆️ back to top

Centering Elements

You can also make use of the Perdido.center property to assign a max-width and margin: auto to an element and center it on the page. clearfix will automatically be applied in this case.

{
    section: {
        ...perdido.center('980px'),
        '& div': {
            ...perdido.column('1/2'),
        }
    }
}

⬆️ back to top

Controlling Cycle

Every element gets a float: left and margin-right: gutter applied to it except the last element in the row and the last item in a container. Perdido will automatically detect the last item in a row (based on the denominator you passed) and apply a margin-right: 0 to it by default.

To override this behavior and tell Perdido to apply margin-right: 0 to a specific iteration, simply pass a cycle param to your perdido.column method. It's the second argument.

{
    div: {
        ...perdido.column('2/4', {cycle: 2}),
    }
}

This will tell Perdido to create div:nth-child(2n) { margin-right: 0; } instead of div:nth-child(4n) { margin-right: 0; } (like it would by default and break).

Using this knowledge we can create really flexible layouts with varying widths like so (this will work for a single row nicely).

<section class="row">
    <div class="quarter">1</div>
    <div class="half">2</div>
    <div class="quarter">3</div>
</section>
{
    '.row': {
        ...perdido.utils.clearFix,
    },
    '.quarter': {
        ...perdido.column('1/4', {cycle: 0}),
    },
    '.half': {
        ...perdido.column('1/2', {cycle: 0}),
    },
}

The concept of cycle is extremely important to Perdido and what sets good Perdido developers apart from great Perdido developers. Really try to grok this!

⬆️ back to top

Nesting

Nesting is simple. There is no context required.

<section>
    <div>a</div>
    <div>
        <div>b</div>
        <div>
            <div>c</div>
            <div>c</div>
        </div>
    </div>
</section>
{
    div: {
        ...perdido.column('1/2'),
    }
}

⬆️ back to top

Offsetting Elements

You can offset columns easily. To offset in the other direction, pass a negative fraction.

<section>
    <div>1</div>
    <div>2</div>
</section>
{
    div: {
        ...perdido.column('1/3'),
        '&:first-child' {
            ...perdido.offset('1/3'),
        }
    }
}

⬆️ back to top

Alignment

Easily align children elements with the Perdido.align method. It accepts options like top-left, right, center, etc.

<section>
    <div>Aligned</div>
</section>
{
    section: {
        ...perdido.align('center'),
        width: '600px',
        height: '400px',

        '& div': {
            width: '100px',
            height: '100px',
        }
    }
}

⬆️ back to top

Edit Mode

Use perdido.utils.edit on body to visualize the entire structure of your site, or just specify the areas you're working on.

<section>
    <div>1</div>
    <div>2</div>
    <div>3</div>
</section>

<section>
    <div>4</div>
    <div>5</div>
    <div>6</div>
</section>
{
    section: {
        '&:nth-of-type(1)': {
            ...perdido.utils.edit,
        },
        '&:nth-of-type(2)': {
            ...perdido.utils.edit,
        }
    }
}

⬆️ back to top

Vertical Grids

Once you've mastered the basic horizontal grid system (it shouldn't take long), you can start to make vertical grids that have the same vertical gutters as your horizontal grids. Just use the perdido.row method in place of perdido.column. These rows will stretch to fill their container's height, so if you'd like to see them take up the full height of the page, set height: 100% on your container.

<section>
    <div>1</div>
    <div>2</div>
    <div>3</div>
</section>
{
    section: {
        height: '100%',
        '& div': {
            ...perdido.row('1/3'),
        }
    }
}

⬆️ back to top

Waffle Grids

You can even make a horizontal/vertical grid (a waffle grid) which resembles a tic-tac-toe board.

<section>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
    <div>7</div>
    <div>8</div>
    <div>9</div>
</section>
{
    section: {
        height: '100%',
        '& div': {
            ...perdido.waffle('1/3'),
        }
    }
}

⬆️ back to top

Flexbox Grids

You can easily change your grids to support Flexbox by altering the perdido property flex by setting it to true. Once you do this, all grids throughout your site will use flexed elements. To make sure they are displayed as flexed elements, you need to wrap them in perdido.flexContainer or perdido.center (which includes perdido.flexContainer by default).

<section>
    <div>1</div>
    <div>2</div>
    <div>3</div>
</section>
perdido.flex = true;

{
    section: {
       ...perdido.center('980px'), 
    },
    div: {
        ...perdido.column('1/3'),
    }
}

Flexbox offers slightly cleaner output and avoids the use of clearfix and other issues with float-based layouts. It also allows you to have elements of even height rather easily, and much more. The downside is, Flexbox doesn't work in IE9 or below, so keep that in mind if you have a client that needs that kind of support.

Also note that waffle grids work well for the most part, but are somewhat finicky in fringe situations. All methods provide a way to disable or enable Flexbox per element with the flex parameter so if you'd like to disable it for a specific case you could do this:

<section>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
</section>
perdido.flex = true;

{
    section: {
       ...perdido.center('980px', {flex: false}), 
    },
    div: {
        ...perdido.waffle('1/3', {flex: false}),
    }
}

⬆️ back to top

Masonry Support

Perdido supports masonry plugins like Isotope. To accomplish this we need to change how the margins work. Instead of applying a margin-right to everything, we need to apply it to both sides. We've made a couple special methods to help with this: perdido.masonryColumn which creates a margin on the left and right of each element it's applied to, and perdido.masonryWrap which wraps your columns and applies a negative margin to the left and right to them to help line them up with containing elements.

<section>
    <div>1</div>
    <div>2</div>
    <div>3</div>
</section>
{
    section: {
        ...perdido.masonryWrap(false),
        '& div': {
            ...perdido.masonryColumn('1/3'),
        }
    }
}

⬆️ back to top

API

NOTE: Bolded arguments are the required arguments.

Perdido.utils

A general utility toolbelt for Perdido. Included are style objects that require no additional input other than being called.

utils.edit

Applies a background to the element for editing or debug purposes.

{
    section: {
        ...perdido.utils.edit,
    }
}

utils.clearFix

Applies a clear fix to the element.

{
    section: {
        ...perdido.utils.clearFix,
    }
}

⬆️ back to top

Perdido.align(..)

Align nested elements. Apply this to a parent container.

  • reset|horizontal|vertical|top-left|top-center|top|top-right|middle-left|left|middle-center|center|middle-right|right|bottom-left|bottom-center|bottom|bottom-right - The position the nested element takes relative to the containing element.
  • true|false - Determines whether this element should use Flexbox or not.
{
    parent: {
        ...perdido.align('right'),
        width: '400px',
        height: '600px',
    },
    child: {
        width: '300px',
        height: '150px',
    }
}

⬆️ back to top

Perdido.center(..)

Horizontally center a container element and apply padding to it.

  • max-width - A max-width to assign. Can be any unit.
  • padding - Padding on the left and right of the element. Can be any unit.
  • true|false - Determines whether this element should use Flexbox or not.
{
    section: {
        ...perdido.center('980px'),
    },
    section: {
        ...perdido.center('1140px', {padding: '30px', flex: true}),
    },
}

⬆️ back to top

Perdido.column(..)

Creates a column that is a fraction of the size of its containing element's width with a gutter.

  • fraction - This is a simple fraction of the containing element's width.
  • gutter - The margin on the right side of the element used to create a gutter. Typically this is left alone and the default gutter will be used, but you can override it here if you want certain elements to have a particularly large or small gutter (pass 0 for no gutter at all).
  • cycle - Perdido works by assigning a margin-right to all elements except the last in the row. It does this by default by using the denominator of the fraction you pick. To override the default use this param., e.g.: `{'.foo': { ...perdido.column('2/4' 2)}}``
  • true|false - Determines whether this element should use Flexbox or not.
  • none - Resets the column (back to browser defaults)
{
    div: {
        ...perdido.column('1/3'),
    },
    div: {
        ...perdido.column('2/6', {cycle: 3, gutter: '60px', flex: false}),
    }
}

⬆️ back to top

Perdido.flexContainer(..)

Creates a Flexbox container.

  • row|column - The flex-direction the container should create. This is typically opposite to the element you're creating so a row would need perdido.flexContainer('column').
{
    section: {
        ...perdido.flexContainer('row'),
    },
    div: {
        ...perdido.column('1/3'),
    }
}

⬆️ back to top

Perdido.masonryWrap(..)

Creates a wrapping element for working with JS Masonry libraries like Isotope. Assigns a negative margin on each side of this wrapping element.

  • true|false - Determines whether this element should use Flexbox or not.
  • gutter - How large the gutter involved is, typically this won't be adjusted and will inherit settings.gutter, but it's made available if you want your masonry grid to have a special gutter, it should match your masonry-column's gutter.
{
    section: {
        ...perdido.masonryWrap({flex: false}),
    },
    div: {
        ...perdido.masonryColumn('1/3'),
    }
}

⬆️ back to top

Perdido.masonryColumn(..)

Creates a column for working with JS masonry libraries like Isotope. Assigns a margin to each side of the element.

  • fraction - This is a simple fraction of the containing element's width
  • gutter - How large the gutter involved is, typically this won't be adjusted and will inherit settings.gutter, but it's made available if you want your masonry grid to have a special gutter, it should match your masonry-row's gutter.
  • true|false - Determines whether this element should use Flexbox or not.
{
    section: {
        ...perdido.masonryWrap(true, '60px'),
    },
    div: {
        ...perdido.masonryColumn('1/3', {gutter: '60px', flex: true}),
    }
}

⬆️ back to top

Perdido.move(..)

Source ordering. Shift elements left, right, up, or down, by their left or top position by passing a positive or negative fraction.

  • fraction - Fraction of the container to be shifted.
  • row|column - Direction the grid is going. Should be the opposite of the column or row it's being used on.
  • gutter - Adjust the size of the gutter for this movement. Should match the element's gutter.
{
    div: {
        ...perdido.column('1/2'),

        '&:first-child': {
            ..perdido.move('1/2'),
        },
        '&:last-child': {
            ..perdido.move('-1/2'),
        }
    }
}

note: If a gutter is set, perdido.move will not retain it and will need to be set manually

{
    div: {
        ...perdido.column('1/2', {gutter: '0'}),

        '&:first-child': {
            ..perdido.move('1/2', {gutter: '0'}),
        },
        '&:last-child': {
            ..perdido.move('-1/2', {gutter: '0'}),
        }
    }
}

⬆️ back to top

Perdido.offset(..)

Margin to the left, right, bottom, or top, of an element depending on if the fraction passed is positive or negative. It works for both horizontal and vertical grids but not both.

  • fraction - Fraction of the container to be offset.
  • row|column - Direction the grid is going. Should be the opposite of the column or row it's being used on. Defaults to row.
  • gutter - How large the gutter involved is, typically this won't be adjusted, but if you have set the elements for that container to have different gutters than default, you will need to match that gutter here as well.
{
    '.two-elements': {
       ...perdido.column('1/3'), 
       '&:first-child': {
            ...perdido.offset('1/3')
       } 
    }
}

⬆️ back to top

Perdido.row(..)

Creates a row that is a fraction of the size of its containing element's height with a gutter.

  • fraction - This is a simple fraction of the containing element's height.
  • gutter - The margin on the bottom of the element used to create a gutter. Typically this is left alone and the default gutter will be used, but you can override it here if you want certain elements to have a particularly large or small gutter (pass 0 for no gutter at all).
  • true|false - Determines whether this element should use Flexbox or not.
{
    section: {
        height: '100%',
    },
    div: {
        ...perdido.row('1/3'),
    }
}

⬆️ back to top

Perdido.waffle(..)

  • fraction - This is a simple fraction of the containing element's width and height.
  • cycle - Perdido works by assigning a margin-right/margin-bottom to all elements except the last in the row. It does this by default by using the denominator of the fraction you pick. To override the default use this param., e.g.: `{'.foo': { ...perdido.waffle('2/4' 2)}}``
  • gutter - Typically this is left alone and the default gutter will be used, but you can override it here if you want certain elements to have a particularly large or small gutter (pass 0 for no gutter at all).
  • true|false - Determines whether this element should use Flexbox or not.
{
    section: {
        height: '100%',
    },
    div: {
        ...perdido.waffle('1/3'),
    }
}

⬆️ back to top

Options

Perdido comes with some default settings that can be changed to your liking.

// ES6/2015
import {create} from 'perdido';

const perdido = create({gutter: '20px', flex: true, cycle: 3, offsetDir: 'column'});
  • Perdido.gutter accepts any unit value (default: '30px')

  • Perdido.flex accepts a boolean value (default: false)

  • Perdido.cycle accepts a integer value (default: -1 for auto cycle)

  • Perdido.offsetDir accepts a string of either 'row' or 'column' (default: row)

⬆️ back to top

Contributing

Contributions are very welcome, and always appreciated! Every bit helps, and credit will always be given.

⬆️ back to top

Thanks

⬆️ back to top

About

JSS fractional grid system built with calc(), based on Lost PostCSS grid. Supports masonry, vertical, and waffle grids.

Resources

License

Stars

Watchers

Forks

Packages

No packages published