@financial-times/o-grid
Version:
A 12 column responsive, flexbox-based grid system for laying out documents, templates and components.
734 lines (554 loc) • 18.1 kB
Markdown
# o-grid
A 12 column responsive, flexbox-based grid system for laying out documents, templates and components.
- [Usage](#usage)
- [Quick Start](#quick-start)
- [Grid dimensions](#grid-dimensions)
- [General settings](#general-settings)
- [Layout sizes](#layout-sizes)
[Handover notes](#handover-notes)
- [Markup](#markup)
- [Utility classes](#utility-classes)
- [Responsive columns](#responsive-columns)
- [Examples](#examples)
- [Sass](#sass)
- [Options](#options)
- [Advanced usage](#advanced-usage)
- [Utilities](#utilities)
- [JavaScript Helpers](#javascript-helpers)
- [Grid Bookmarklet](#grid-bookmarklet)
- [Migration](#migration)
- [Contact](#contact)
- [Licence](#licence)
This component is a collection of Sass styles to build a 12 column grid system, with a few JavaScript helpers.
Our grid consists of:
- 12 columns, of equal size.
- 5 layouts (breakpoints) to support devices of various sizes.
- Gutters of variable width, that adjust according to the current layout.
- A maximum page width of 1220px, by default.
[](https://raw.githubusercontent.com/Financial-Times/origami/main/components/o-grid/img/grid-system.png)
## Usage
Check out [how to include Origami components in your project](https://origami.ft.com/documentation/components/#including-origami-components-in-your-project) to get started with `o-grid`.
## Quick Start
```scss
// your-app/main.scss
@import '@financial-times/o-grid/main';
@include oGrid();
```
```js
// your-app/main.js
// Return the current layout (e.g. default, S, M, L, XL)
import oGrid from '@financial-times/o-grid';
let currentLayout = oGrid.getCurrentLayout();
console.log(currentLayout);
// Return the current gutter (e.g. 10px, 20px)
import oGrid from '@financial-times/o-grid';
let currentGutter = oGrid.getCurrentGutter();
console.log(currentGutter);
```
## Grid dimensions
### General settings
- Minimum width: 240px
- Maximum width: 1220px
- Gutter widths (space between columns):
- 10px on small screens
- 20px on larger screens
- Number of columns: 12
### Layout sizes
- **Default** 240px - …
- **Small (S)** 490px - 739px
- **Medium (M)** 740px - 979px
- **Large (L)** 980px to 1219px
- **Extra large (XL)** 1220px
## Handover notes
Engineers may choose to use the o-grid Origami component to build a web based project to our grid, and respond to layout changes, but this may not be technically appropriate in every scenario particularly where it is appropriate to fallback to a simpler layout for older browsers.
It is important not to make assumptions about the devices our users are using or the most common screen-size, as these change. It is better to focus on the content of your design and adapt as needed when the space available to the design changes, rather than waiting to hit a specific breakpoint.
## Markup
### Utility classes
```html
<div class="o-grid-container">
<div class="o-grid-row">
<!-- two divs, spanning a total of 12 columns -->
<div data-o-grid-colspan="8">A div, 8 columns wide</div>
<div data-o-grid-colspan="4">Another div, 4 columns wide</div>
</div>
</div>
```
### Responsive columns
Set a number of columns per layout:
```html
<div class="o-grid-container">
<div class="o-grid-row">
<div data-o-grid-colspan="6 L8" class="first-column">
Half by default, then 8 columns wide on Large layout and up
</div>
<div data-o-grid-colspan="6 L4" class="second-column">
Half by default, then 4 columns wide on Large layout and up
</div>
</div>
</div>
```
```scss
div {
@include oGridContainer();
> div {
@include oGridRow();
}
}
.first-column {
// Half by default, then 8 columns wide on Large layout and up
@include oGridColspan((default: 6, L: 8));
}
.second-column {
// Half by default, then 4 columns wide on Large layout and up
@include oGridColspan((default: 6, L: 4));
}
```
#### Using numbers
- `{0-12}` - number of columns to span by default
- `S{0-12}` - number of columns to span at the small layout and up
- `M{0-12}` - number of columns to span at the medium layout and up
- `L{0-12}` - number of columns to span at the large layout and up
- `XL{0-12}` - number of columns to span at the extra large layout and up
```html
<div data-o-grid-colspan="6 L8"></div>
```
```scss
div { @include oGridColspan((default: 6, L: 8)); }
```
#### Using keywords<a name="keywords"></a>
- `hide`
- `one-half`
- `one-third`, `two-thirds`
- `one-quarter`, `three-quarters`
```html
<div data-o-grid-colspan="one-half Ltwo-thirds"></div>
```
```scss
div { @include oGridColspan((default: one-half, L: two-thirds)); }
```
### Examples
A full width column for all sizes except large screens and up, where it spans on 9 columns:
```html
<div data-o-grid-colspan="full-width L9"></div>
```
```scss
div { @include oGridColspan((default: full-width, L: 9)); }
```
A half width column that becomes full-width on medium screens and up:
```html
<div data-o-grid-colspan="one-half M12"></div>
```
```scss
div { @include oGridColspan((default: one-half, M: 12)); }
```
A column which gradually takes up a greater portion of horizontal space as the screen gets smaller:
```html
<div data-o-grid-colspan="4 M3 L2 XL1"></div>
```
```scss
div { @include oGridColspan((default: 4, M: 3, L: 2, XL: 1)); }
```
A column which has `width: auto` on small screens, and then takes half the available space on medium screens and up:
```html
<div data-o-grid-colspan="M6"></div>
```
```scss
div { @include oGridColspan((M: 6)); }
```
## Sass
To include all styles call the `oGrid` mixin.
```scss
@include oGrid();
```
### Options
`o-grid` css may be included granularly by passing options to the `oGrid` mixin.
```scss
@include oGrid($opts: (
'bleed': true,
'shuffle-selectors': true,
'friendly-selectors': true,
'surface': ('current-layout', 'layout-sizes'),
'rows': ('compact')
));
```
If you would not like to use `o-grid` markup at all, the styles for the `surface` option may be included independently to enable JavaScript features:
```scss
// Surface current breakpoint and gutter size information to JavaScript.
// Supports `getGridBreakpoints` and `enableLayoutChangeEvents`
// JavaScript methods.
@include oGridSurfaceLayoutSizes();
// Surface grid breakpoints to JavaScript.
// Supports the `getCurrentLayout` and `getCurrentGutter` JavaScript methods.
@include oGridSurfaceCurrentLayout();
```
## Advanced usage
### Utilities
#### Hiding elements
`hide` the column, show it again at Large (`L`) layout size, and hide it at the largest (`XL`) layout size:
```html
<div data-o-grid-colspan="hide L12 XLhide"></div>
```
```scss
div { @include oGridColspan((default: hide, L: 12, XL: hide)); }
```
#### Centering a column
`center` the column and `uncenter` it at Large (`L`) layout size:
```html
<div data-o-grid-colspan="center Luncenter"></div>
```
```scss
.my-column {
@include oGridCenter;
@include oGridRespondTo(L) {
@include oGridUncenter;
}
}
```
#### Push and pull columns
```html
<div data-o-grid-colspan="8 push4"></div>
<div data-o-grid-colspan="4 pull8"></div>
```
```scss
// Content is first in the source
.content {
@include oGridColspan(8);
@include oGridPush(4); // outputs left: -33.333333333%;
}
// Sidebar comes second in the source but appears first on the left
.sidebar {
@include oGridColspan(4);
@include oGridPull(8); // outputs right: -66.666666667%;
}
```
Responsively:
```html
<div data-o-grid-colspan="L8 Lpush4"></div>
<div data-o-grid-colspan="L4 Lpull8"></div>
```
```scss
// Content is first in the source
.content {
@include oGridColspan((L: 8));
@include oGridRespondTo(L) {
@include oGridPush(4); // outputs left: -33.333333333%;
}
}
// Sidebar comes second in the source but appears first on the left
.sidebar {
@include oGridColspan((L: 4));
@include oGridRespondTo(L) {
@include oGridPull(8); // outputs right: -66.666666667%;
}
}
```
#### Add space before a column
```html
<div data-o-grid-colspan="8 offset4"></div>
<div data-o-grid-colspan="L8 Loffset4"></div>
```
```scss
div {
@include oGridColspan(8);
@include oGridOffset(4); // outputs margin-left: 33.333333333%;
}
div {
@include oGridColspan((L: 8));
@include oGridRespondTo(L) {
@include oGridOffset(4); // outputs margin-left: 33.333333333%;
}
}
```
#### Compact (gutterless) rows
To remove gutters from in between columns in a row, use the `o-grid-row--compact` class or the `oGridRowCompact()` mixin:
```html
<div class="o-grid-row o-grid-row--compact">
<div data-o-grid-colspan="6">Look 'ma, no gutters</div>
<div data-o-grid-colspan="6">Look 'pa, no gutters here either</div>
</div>
```
```scss
div {
@include oGridContainer();
> div {
@include oGridRow();
@include oGridRowCompact('.column');
}
.column {
@include oGridColspan((default: full-width, S: 3));
}
}
```
#### Full bleed container
To remove gutters from the left and right sides of the grid container, use the `o-grid-container--bleed` class. Note that it is not possible to remove the outer gutters for an individual row, instead you need to start a new container.
```html
<div class="o-grid-container o-grid-container--bleed">
<div class="o-grid-row o-grid-row--compact">
<div data-o-grid-colspan="6">Look 'ma, no gutters</div>
<div data-o-grid-colspan="6">Look 'pa, no gutters here either</div>
</div>
</div>
```
#### Responsive column helper
For simplicity, examples below don't show the output code that brings support for Internet Explorer.
##### Give column properties to an element
```scss
el { @include oGridColspan(); }
```
Outputs:
```css
// Fallbacks for Internet Explorer omitted in this example
el {
position: relative;
float: left;
box-sizing: border-box;
flex: 1 1 0%;
padding-left: 10px;
}
@media (min-width: 46.25em) {
el {
padding-left: 20px;
}
}
```
##### Give a width to an element
```scss
el { @include oGridColspan($span: 4); }
```
Outputs:
```css
el {
position: relative;
float: left;
box-sizing: border-box;
flex: 1 1 0%;
padding-left: 10px;
display: block;
flex-basis: 33.33333%;
min-width: 33.33333%;
max-width: 33.33333%;
width: 33.33333%;
}
@media (min-width: 46.25em) {
el {
padding-left: 20px;
}
}
```
##### Responsive width for different layouts
```scss
el {
@include oGridColspan((
default: full-width,
M: 6
));
}
```
Outputs:
```css
el {
position: relative;
float: left;
box-sizing: border-box;
flex: 1 1 0%;
padding-left: 10px;
display: block;
flex-basis: 100%;
min-width: 100%;
max-width: 100%;
width: 100%;
}
@media (min-width: 46.25em) {
el {
display: block;
flex-basis: 50%;
min-width: 50%;
max-width: 50%;
padding-left: 20px;
}
}
```
#### Responsive layout helper
```scss
@include oGridRespondTo($from, $until) {
// Styles
}
```
To create styles that respond to the same breakpoints as the grid, this Sass mixin can be used to wrap the styles in the appropriate media query. It should be passed `S`, `M`, `L` or `XL` depending on which layout size the style should apply to e.g.
```scss
@include oGridRespondTo(S) {
.o-example-module .item-subheading {
font-size: 0.5em;
}
}
.o-example-module .item-subheading {
@include oGridRespondTo(XL) {
color: red;
}
}
.o-example-module .item-subheading {
@include oGridRespondTo($until: L) {
width: auto;
}
}
```
It relies on [Sass MQ](http://git.io/sass-mq) to output mobile-first @media queries.
`$from` is inclusive but `$until` is _exclusive_ – e.g. `@include oGridRespondTo(S, L)` matches the breakpoints `S` and `M`, but not `L`.
#### Gutters
```scss
el {
margin-left: oGridGutter();
@include oGridRespondTo(L) {
margin-left: oGridGutter(L);
}
}
```
Outputs:
```css
el {
margin-left: 10px;
}
@media (min-width: 61.25em) {
el {
margin-left: 20px;
}
}
```
#### _Unstyle_ a row or a column
```scss
.un-rowify {
@include oGridResetRow;
}
.de-columnify {
@include oGridResetColumn;
}
```
#### Variables
Some of the variables used by the grid (see [_variables.scss](https://github.com/Financial-Times/o-grid/blob/master/src/scss/_variables.scss)) can be used to customise the grid system.
Here are the most useful ones:
```scss
// Show the currently active breakpoint and output loaded settings
$o-grid-debug-mode: true;
// Gutters (distance between 2 columns), in pixels
$o-grid-gutters: (default: 10px, M: 20px);
// Grid mode
// - fluid: full width up to the largest layout's width
// - snappy fluid width until the layout defined in $o-grid-start-snappy-mode-at (default: M),
// and then snaps into a larger fixed layout at each breakpoint
// - fixed: always fixed-width with the layout defined by
// $o-grid-fixed-layout (default: L)
$o-grid-mode: fluid (default) | snappy | fixed;
// Default layouts
$o-grid-layouts: (
S: 490px,
M: 740px,
L: 980px,
XL: 1220px,
);
```
#### Adding a layout
Products who need to add other breakpoints/layouts should use the helper `oGridAddLayout()`:
```scss
@import '@financial-times/o-grid/main';
// Add various layouts
@include oGridAddLayout(
$layout-name: XS,
$layout-width: 360px
);
@include oGridAddLayout(
$layout-name: P,
$layout-width: 600px,
$gutter-width: 24px
);
// Layouts are now:
// XS: 360px,
// S: 490px,
// P: 600px,
// M: 740px,
// L: 980px,
// XL: 1220px
// Include all o-grid styles, including:
// - Surface the layout currently displayed to make it readable in JS
// - Generate grid helpers classes and data attributes.
@include oGrid();
```
#### Snappy mode
The container size can snap between fixed-widths as the viewport gets larger:
```html
<!-- Make the whole document snappy -->
<body class="o-grid-snappy">
<div class="o-grid-container">
<div class="o-grid-row">
…
</div>
</div>
</body>
<!-- Make a container snappy -->
<div class="o-grid-container o-grid-container--snappy">
<div class="o-grid-row">
…
</div>
</div>
```
#### Debug mode
Enable debug mode to see the currently active breakpoint in the top-right corner of the page (based on [sass-mq's show-breakpoints](https://github.com/sass-mq/sass-mq#seeing-the-currently-active-breakpoint) feature).
```scss
$o-grid-debug-mode: true;
```

## JavaScript Helpers
### `getCurrentLayout()`
Returns the name of the layout currently displayed.
```js
import oGrid from '@financial-times/o-grid';
console.log(oGrid.getCurrentLayout());
// > default | S | M | L | XL
```
CSS must be included so JavaScript can retrieve layout information. If using [Sass](#sass) and the `oGrid` mixin, ensure the `surface` [option](#options) includes `current-layout`; or include the `oGridSurfaceCurrentLayout` mixin if your project is not using any o-grid markup.
### `getCurrentGutter()`
Returns the width of the gutter currently displayed.
```js
import oGrid from '@financial-times/o-grid';
console.log(oGrid.getCurrentGutter());
// > 10px | 20px
```
CSS must be included so JavaScript can retrieve layout information. If using [Sass](#sass) and the `oGrid` mixin, ensure the `surface` [option](#options) includes `current-layout`; or include the `oGridSurfaceCurrentLayout` mixin if your project is not using any o-grid markup.
### `getGridBreakpoints()`
Returns the sizes of all grid breakpoints available.
```js
import oGrid from '@financial-times/o-grid';
console.log(oGrid.getGridBreakpoints());
// > { "layouts": { "S": "490px", "M": "740px", "L": "980px", "XL": "1220px" } }
```
CSS must be included so JavaScript can retrieve layout information. If using [Sass](#sass) and the `oGrid` mixin, ensure the `surface` [option](#options) includes `layout-sizes`; or include the `oGridSurfaceLayoutSizes` mixin if your project is not using any o-grid markup.
### `enableLayoutChangeEvents()`
Enable matchMedia queries that fire an `o-grid.layoutChange` event upon layout change.
```js
import oGrid from '@financial-times/o-grid';
oGrid.enableLayoutChangeEvents();
```
CSS must be included so JavaScript can retrieve layout information. If using [Sass](#sass) and the `oGrid` mixin, ensure the `surface` [option](#options) includes `layout-sizes`; or include the `oGridSurfaceLayoutSizes` mixin if your project is not using any o-grid markup.
## Grid Bookmarklet
1. Create a new Bookmark with this URL:
```js
javascript:(function(){var s=document.createElement("script");s.src="https://unpkg.com/@financial-times/o-grid@^6.0.0/bookmarklet/bookmarklet.js";document.head.appendChild(s);}());
```
2. Load a website
3. Click the bookmarklet (the overlay should appear)
4. Check the alignment of the layout on the grid

## Migration
| State | Major Version | Last Minor Release | Migration guide |
|:-------------:| :---: | :---: | :---: |
| ✨ active | 6 | N/A | [migrate to v5](MIGRATION.md#migrating-from-v5-to-v6) |
| ⚠ maintained | 5 | N/A | [migrate to v5](MIGRATION.md#migrating-from-v4-to-v5) |
| ╳ deprecated | 4 | 4.5 | [migrate to v4](MIGRATION.md#migrating-from-v3-to-v4) |
| ╳ deprecated | 3 | 3.2 | - |
| ╳ deprecated | 2 | 2.4 | - |
| ╳ deprecated | 1 | 1.4 | - |
## Contact
If you have any questions or comments about this component, or need help using it, please either [raise an issue](https://github.com/Financial-Times/o-grid/issues), visit [#origami-support](https://financialtimes.slack.com/messages/origami-support/) or email [Origami Support](mailto:origami-support@ft.com).
***
## Licence
Copyright (c) 2016 Financial Times Ltd. All rights reserved.
This software is published under the [MIT licence](http://opensource.org/licenses/MIT).