Overview.

Get started by adding a class of grid to your target element. Voilà, we have a grid! Iota's fallback var() values can be overwritten at each defined breakpoint using CSS custom properties. Items have their own set of custom properties, which allow you to control layout on both the X and Y axis. Take advantage true source order independence by plotting each item to specific tracks on the grid. 🙌 Using auto-fit / auto-fill with minmax() will layout items based on their size rather than breakpoints. Tap into justify-content and align-content to position spaced items relative to the grid. Additionally, justify-items and align-items can orient item content for the grid as a whole, or… Use justify-self and align-self to position the content of individual items on a case by case basis. We've only begun to scratch the surface here! Keep scrolling to learn more about how Iota works.

1
2
3
4
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>
1
2
3
4
<div class="grid" style="--cols-xssmmdlgxl: 2;">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>
1
2
3
4
<div class="grid" style="--cols-xssmmdlgxl: 2;">
  <div style="--row-xssmmdlgxl: span 2">1</div>
  <div>2</div>
  <div>3</div>
  <div style="--col-xssmmdlgxl: span 2">4</div>
</div>
1
2
3
4
5
<div class="grid" style="--cols-xssmmd: 2;--cols-lgxl: 3;">
  <div style="--col-xssmmd: 2/3; --row-xssmmd: 2/3;--col-lgxl: 1/2; --row-lgxl: 1/2;">1</div>
  <div style="--col-xssmmd: 1/2; --row-xssmmd: 1/7;--col-lgxl: 3/4; --row-lgxl: 1/4;">2</div>
  <div style="--col-xssmmd: 1/2; --row-xssmmd: 7/8;--col-lgxl: 2/3; --row-lgxl: 1/3;">3</div>
  <div style="--col-xssmmd: 2/3; --row-xssmmd: 3/8;--col-lgxl: 1/3; --row-lgxl: 3/4;">4</div>
  <div style="--col-xssmmd: 2/3; --row-xssmmd: 1/2;--col-lgxl: 1/2; --row-lgxl: 2/3;">5</div>
</div>
1
2
3
4
5
6
<div class="grid" style="--cols-xssmmdlgxl: auto-fit; --cols-size-xssmmdlgxl: minmax(220px, 1fr);">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
</div>
1
2
3
4
5
6
<div class="grid" style="--jc-xssmmdlgxl: start;">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
</div>
1
2
3
<div class="grid" style="--ji-xssmmdlgxl: center; --ai-xssmmdlgxl: center;">
  <div style="--col-smmd: span 2;">1</div>
  <div style="--col-smmdlgxl: span 2;">2</div>
  <div style="--col-smmd: span 2;">3</div>
</div>
1
2
3
<div class="grid">
  <div style="--col-smmd: span 2; --js-xssmmdlgxl: start; --as-xssmmdlgxl: start;">1</div>
  <div style="--col-smmdlgxl: span 2;">2</div>
  <div style="--col-smmd: span 2; --js-xssmmdlgxl: end; --as-xssmmdlgxl: end;">3</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
<div class="grid" style="--cols-xssmmdlgxl: 34;">
  <div style="--col-xs: 1; --row-xs: 1;--col-smmdlgxl: 1; --row-smmdlgxl: 1;">1</div>
  <div style="--col-xs: 2; --row-xs: 1;--col-smmdlgxl: 2; --row-smmdlgxl: 1;">2</div>
  <div style="--col-xs: 3; --row-xs: 1;--col-smmdlgxl: 3; --row-smmdlgxl: 1;">3</div>
  <div style="--col-xs: 3; --row-xs: 2;--col-smmdlgxl: 4; --row-smmdlgxl: 1;">4</div>
  <div style="--col-xs: 3; --row-xs: 3;--col-smmdlgxl: 4; --row-smmdlgxl: 2;">5</div>
  <div style="--col-xs: 3; --row-xs: 4;--col-smmdlgxl: 4; --row-smmdlgxl: 3;">6</div>
  <div style="--col-xs: 3; --row-xs: 5;--col-smmdlgxl: 4; --row-smmdlgxl: 4;">7</div>
  <div style="--col-xs: 2; --row-xs: 5;--col-smmdlgxl: 3; --row-smmdlgxl: 4;">8</div>
  <div style="--col-xs: 1; --row-xs: 5;--col-smmdlgxl: 2; --row-smmdlgxl: 4;">9</div>
  <div style="--col-xs: 1; --row-xs: 4;--col-smmdlgxl: 1; --row-smmdlgxl: 4;">10</div>
  <div style="--col-xs: 1; --row-xs: 3;--col-smmdlgxl: 1; --row-smmdlgxl: 3;">11</div>
  <div style="--col-xs: 1; --row-xs: 2;--col-smmdlgxl: 1; --row-smmdlgxl: 2;">12</div>
</div>

More information.

What's the big deal about this little framework?

Low overhead.

While traditional class-based grids often produce excessive amounts of unused styles, Iota eliminates this overhead by leveraging the flexibility of CSS custom properties to create a responsive wrapper for the grid spec so that each page of your website uses only what it needs.

Rapid prototyping.

Since all of Iota's properties are manipulated via inline styles, it is ideal for layout experimentation. This is particularly effective when combined with a component-based system like React, but works equally well for traditional website layouts.

Highly declarative.

Because of the way the grid spec works and how Iota is setup, there is essentially no guesswork to be done with how styles are affecting the layout. Overall grid structure is defined on the parent element and can be overwritten per item as needed.

Extensible.

Because CSS custom properties are just that—properties—you can take Iota's general framework and extend it however you see fit by creating classes that encapsulate layout patterns you wish to reuse.

Setting up a base grid.

Consider how you will most likely use grids throughout the majority of your project and use that to inform the property fallbacks for each value and breakpoint when you setup Iota. This will help to keep overwrites to a minimum.

Inheritance.

Values set for a custom property will be inherited by children using the same properties. For example, if you overwrite a parent grid to have 2 columns, any nested grids will inherit that layout unless otherwise specified.

Properties != classes.

With most mobile-first frameworks, classes applied at breakpoint typically apply to higher breakpoints as well. Overwrites for Iota's custom properties must be set at each level and do not affect other breakpoints.

Browser support.

Support for both the CSS grid spec as well as custom properties is limited to Edge 16+, Firefox 52+, Chrome 57+, Safari 10.1+, and Opera 44+. If you need to support Internet Explorer, you will need to implement layout fallbacks.

Reference.

Documentation for all custom properties as well as information on how to customize Iota.


Introduction.

Iota is a responsive, mobile-first framework for the grid spec powered by CSS custom properties.

In the code example, you will see the $iota_grid Sass map that sets up Iota's grid, which contains nested maps for each desired breakpoint and the default values of each property at that breakpoint. This is used to define the “baseline” grid that will be output every time the .grid class is used.

For example, you may decide that you want the number of columns at each breakpoint to look like:

xs sm md lg xl
1 2 2 4 4

you can setup your defaults as such and then overwrite them using Iota's custom properties when needed.

// Class
// ===========================================
// Defines the CSS class used for Iota's grid.

$iota_class:    grid;


// Enable
// ===========================================
// Turn various features on/off as needed.

$iota_enable_grid_column_property:     true;
$iota_enable_grid_row_property:        true;
$iota_enable_justify_self_property:    true;
$iota_enable_align_self_property:      true;


// Grid Data
// ===========================================
// Defines the number of breakpoints and
// defaults used for each property at that
// breakpoint. The slug for each breakpoint
// will be used in the custom properties as a
// responsive reference (e.g. "--gap-xs"). The
// value of the first breakpoint must be set
// to "0" to assign the mobile-first values.

$iota_grid: (
  "xs": (
    "breakpoint"          : 0,
    "grid_gap"            : 2rem,
    "grid_auto_flow"      : row,
    "grid_auto_columns"   : auto,
    "grid_auto_rows"      : auto,
    "repeat_columns"      : 1,
    "repeat_columns_size" : 1fr,
    "justify_content"     : space-evenly,
    "justify_items"       : stretch,
    "align_content"       : center,
    "align_items"         : stretch,
    "grid_column"         : auto,
    "grid_row"            : auto,
    "justify_self"        : auto,
    "align_self"          : auto,
  ),
  "sm": (
    "breakpoint"          : 640px,
    "grid_gap"            : 2rem,
    "grid_auto_flow"      : row,
    "grid_auto_columns"   : auto,
    "grid_auto_rows"      : auto,
    "repeat_columns"      : 2,
    "repeat_columns_size" : 1fr,
    "justify_content"     : space-evenly,
    "justify_items"       : stretch,
    "align_content"       : center,
    "align_items"         : stretch,
    "grid_column"         : auto,
    "grid_row"            : auto,
    "justify_self"        : auto,
    "align_self"          : auto,
  ),
  "md": (
    "breakpoint"          : 860px,
    "grid_gap"            : 2rem,
    "grid_auto_flow"      : row,
    "grid_auto_columns"   : auto,
    "grid_auto_rows"      : auto,
    "repeat_columns"      : 2,
    "repeat_columns_size" : 1fr,
    "justify_content"     : space-evenly,
    "justify_items"       : stretch,
    "align_content"       : center,
    "align_items"         : stretch,
    "grid_column"         : auto,
    "grid_row"            : auto,
    "justify_self"        : auto,
    "align_self"          : auto,
  ),
  "lg": (
    "breakpoint"          : 1080px,
    "grid_gap"            : 2rem,
    "grid_auto_flow"      : row,
    "grid_auto_columns"   : auto,
    "grid_auto_rows"      : auto,
    "repeat_columns"      : 4,
    "repeat_columns_size" : 1fr,
    "justify_content"     : space-evenly,
    "justify_items"       : stretch,
    "align_content"       : center,
    "align_items"         : stretch,
    "grid_column"         : auto,
    "grid_row"            : auto,
    "justify_self"        : auto,
    "align_self"          : auto,
  ),
  "xl": (
    "breakpoint"          : 1300px,
    "grid_gap"            : 2rem,
    "grid_auto_flow"      : row,
    "grid_auto_columns"   : auto,
    "grid_auto_rows"      : auto,
    "repeat_columns"      : 4,
    "repeat_columns_size" : 1fr,
    "justify_content"     : space-evenly,
    "justify_items"       : stretch,
    "align_content"       : center,
    "align_items"         : stretch,
    "grid_column"         : auto,
    "grid_row"            : auto,
    "justify_self"        : auto,
    "align_self"          : auto,
  ),
);

Overwriting defaults.

Expanding on the example above, let's say that for the lg and xl breakpoints you wish to use three columns instead of the default value. To do this you would use the --cols-@ custom property for each breakpoint as seen in the code sample here.

Keep in mind that with custom properties, overwrites must be applied at each level you wish to use a new value at, otherwise the default is used.

Note: @ represents the slug for each breakpoint set.

<div class="grid" style="--cols-lg: 3; --cols-xl: 3;">
  <!-- grid items -->
</div>

Reusable patterns.

Taking our example one step further, let's say that you have decided the three column layout from above is one you wish to use on a few different pages throughout your site. Those custom properties used can be abstracted into a class and utilized wherever desired.

.custom {
  --cols-lg: 3;
  --cols-xl: 3;
}

<div class="grid custom">
  <!-- grid items -->
</div>

Mix and match.

Remember that Iota's custom properties are meant to augment—not replace—standard grid properties by providing some sensible defaults along with a responsive wrapper for properties that you need to change at different breakpoints.

In situations where you don't need the responsiveness, feel free to utilize standard CSS properties instead to save on having to rewrite the same declaration over and over. For example, if you know that you'd like to have a grid with no spacing between cells all the time, using grid-gap instead of --gap-@ at each breakpoint will work perfectly.

.custom {
  grid-gap: 0;
  --cols-lg: 3;
  --cols-xl: 3;
}

<div class="grid custom">
  <!-- grid items -->
</div>

.grid

This class sets up the grid and enables the use of Iota's custom properties. You can also use the modifier class .is-inline, which will allow the grid to display as an inline element rather than block level.

The core focus of Iota centers around templating layouts. Out of the box, Iota uses the repeat() function for its column layouts, with 1fr as the default item size. This makes component composition more streamlined, as many times you may find you only wish to change the number of columns, but not the item size. This initial setup will keep you from having to rewrite the whole function each time an overwrite is desired.

If a completely custom structure is desired, using the --template-cols-@ property will fully overwrite the repeat statement at that breakpoint. For instance, you may wish to have three columns setup with different values each, like so: 200px 1fr 5rem.

There is no default row template as the majority of layouts tend to be structured using columns, but one can be specified using --template-rows-@. Keep in mind that there is no default abstraction for repeating rows using this property, so the entire row template must be specified at each breakpoint as desired.

Beyond templating, you have full access to other grid features such as gap size, content alignment, and more.

Note: @ represents the slug for each breakpoint set.

General
--gap-@

gap between grid items using grid-gap

--flow-@

uses grid-auto-flow to adjust the placement of grid items not explicitly positioned with any grid placement properties

--auto-cols-@

specifies the size of auto-generated grid tracks along the column axis using grid-auto-columns

--auto-rows-@

specifies the size of auto-generated grid tracks along the row axis using grid-auto-rows

Templating
--cols-@

number of columns available, first parameter of repeat()

--cols-size-@

size of each repeated track, second parameter of repeat()

--template-cols-@

if a custom column template is desired, specifying this property will overwrite the default repeating template for columns and will set a new grid-template-columns value

--template-rows-@

while there is no default row template, one can be set using this property to specify a grid-template-rows value

Alignment
--jc-@

aligns all grid items relative to the grid along the row axis using justify-content (the size of the grid must be smaller than the grid container for this to work)

--ac-@

aligns all grid items relative to the grid along the column axis using align-content (the size of the grid must be smaller than the grid container for this to work)

--ji-@

aligns the content inside all grid items along the row axis using justify-items

--ai-@

aligns the content inside all grid items along the column axis using align-items


.grid > *

Any direct child of the .grid element is a grid item, which receives a few minor normalization styles in addition to the custom properties found in this section.

Note: @ represents the slug for each breakpoint set.

Templating
--col-@ indicates the column grid lines where a grid item starts and ends using grid-column
--row-@ indicates the row grid lines where a grid item starts and ends using grid-row
Alignment
--js-@ aligns the content inside an individual grid item along the row axis using justify-self
--as-@ aligns the content inside an individual grid item along the column axis using align-self

What next?

Go further by reading through the selected works and projects that helped to inspire Iota.