Skip to main content

User testing

Help us improve this service. Take part in a short online exercise

Layout Grid

Use the ONS grid system to lay out the content on your service’s pages.

Mobile first

We use a responsive, mobile first approach that allows layouts to change to suit the device being used to access the page. The responsive nature of the grid ensures that users have the best available experience regardless of their device or orientation.

The Grid

We have a flexible grid based on 12 columns, each column has a percentage calculated width. We use a set of device agnostic breakpoints to change the layout when best suited as opposed specific devices. The example below shows the full 12 column grid:

<div class="ons-grid">
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
</div>
{% from "foundations/layout/grid/_macro.njk" import patternLibExampleGrid %}
{{
    patternLibExampleGrid({
        "itemsList": [
            {
            'repeat': 12,
            'col': 1
            }
        ]
    })
}}
{% macro patternLibExampleGrid(params) %}
  {% if params.container -%}
    <div class="ons-container">
  {% endif -%}

  <div class="ons-grid">
      {% for item in (params.itemsList if params.itemsList is iterable else params.itemsList.items()) -%}
          {% for i in range(0, item.repeat | default(1)  ) -%}
              <div class="ons-grid__col ons-col-{{ item.col }}@m {{ item.classes }}">
                  <div class="ons-pl-grid-col">{{ item.col }} col</div>
              </div>
          {%- endfor %}
      {%- endfor %}
  </div>

  {% if params.container is defined and params.container -%}
    </div>
  {% endif -%}
{% endmacro %}

Use different column widths to make up the 12 available columns:

<div class="ons-grid">
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-1@m ">
    <div class="ons-pl-grid-col">1 col</div>
  </div>
  <div class="ons-grid__col ons-col-2@m ">
    <div class="ons-pl-grid-col">2 col</div>
  </div>
  <div class="ons-grid__col ons-col-2@m ">
    <div class="ons-pl-grid-col">2 col</div>
  </div>
  <div class="ons-grid__col ons-col-2@m ">
    <div class="ons-pl-grid-col">2 col</div>
  </div>
  <div class="ons-grid__col ons-col-2@m ">
    <div class="ons-pl-grid-col">2 col</div>
  </div>
  <div class="ons-grid__col ons-col-2@m ">
    <div class="ons-pl-grid-col">2 col</div>
  </div>
  <div class="ons-grid__col ons-col-2@m ">
    <div class="ons-pl-grid-col">2 col</div>
  </div>
  <div class="ons-grid__col ons-col-3@m ">
    <div class="ons-pl-grid-col">3 col</div>
  </div>
  <div class="ons-grid__col ons-col-3@m ">
    <div class="ons-pl-grid-col">3 col</div>
  </div>
  <div class="ons-grid__col ons-col-3@m ">
    <div class="ons-pl-grid-col">3 col</div>
  </div>
  <div class="ons-grid__col ons-col-3@m ">
    <div class="ons-pl-grid-col">3 col</div>
  </div>
  <div class="ons-grid__col ons-col-4@m ">
    <div class="ons-pl-grid-col">4 col</div>
  </div>
  <div class="ons-grid__col ons-col-4@m ">
    <div class="ons-pl-grid-col">4 col</div>
  </div>
  <div class="ons-grid__col ons-col-4@m ">
    <div class="ons-pl-grid-col">4 col</div>
  </div>
  <div class="ons-grid__col ons-col-6@m ">
    <div class="ons-pl-grid-col">6 col</div>
  </div>
  <div class="ons-grid__col ons-col-6@m ">
    <div class="ons-pl-grid-col">6 col</div>
  </div>
</div>
{% from "foundations/layout/grid/_macro.njk" import patternLibExampleGrid %}
{{
    patternLibExampleGrid({
        "itemsList": [
            {
                'repeat': 12,
                'col': 1
            },
            {
                'repeat': 6,
                'col': 2
            },
            {
                'repeat': 4,
                'col': 3
            },
            {
                'repeat': 3,
                'col': 4
            },
            {
                'repeat': 2,
                'col': 6
            }
        ]
    })
}}
{% macro patternLibExampleGrid(params) %}
  {% if params.container -%}
    <div class="ons-container">
  {% endif -%}

  <div class="ons-grid">
      {% for item in (params.itemsList if params.itemsList is iterable else params.itemsList.items()) -%}
          {% for i in range(0, item.repeat | default(1)  ) -%}
              <div class="ons-grid__col ons-col-{{ item.col }}@m {{ item.classes }}">
                  <div class="ons-pl-grid-col">{{ item.col }} col</div>
              </div>
          {%- endfor %}
      {%- endfor %}
  </div>

  {% if params.container is defined and params.container -%}
    </div>
  {% endif -%}
{% endmacro %}

Spacing

Gutters are fixed for each breakpoint. 24px for screen widths 600px and greater and 16px for below 600px. There are options for removing gutters by using modifier classes on the grid which is useful when nesting grids.

The baseline grid is based on multiples of 8px.

Viewport <300px 301 - 600 600 - 1000+
Gutter 16px 16px 24px

600 - 1000+ Grid

Laptop (including tablet in horizontal orientation) and larger resolution devices.

Grid illustration for larger screen sizes

301 - 600 and 300 Grid

12 columns with 16px fixed margins for 301-600 and 300px viewports

Grid illustration for tablet and mobile sizes

Breakpoints

There are set breakpoints that can be accessed to adapt the layout for different screen widths.

Breakpoint Variable to reference
300px xxs
400px xs
500px s
740px m
980px l
1300px xl
1600px xxl

Using the grid system

Grid columns need to be wrapped using the .ons-grid class.

Each column within .ons-grid requires the class .ons-grid__col and another class to specify the number of columns at the required breakpoint, for example .ons-col-6@m. This will provide a single column, 6 columns wide at 740px and greater. If the screen width is below 740px the column will fill 100% of the content.

A column width can also be set between two breakpoints using the class structure .ons-col-6@m@xl. This will provide a 6 column wide column between 740px and 1300px. Outside of these widths the column will fill 100% of the content.

There are additional modifiers that can add further control to the grid:

Reversible

.ons-grid--reverse - A reversed grid allows you change the source order of the markup and still keep a left-to-right layout.

Align Mid

.ons-grid--align-mid - Uses vertical-align to middle align the columns vertically.

Flexbox

.ons-grid--flex .ons-grid__col--flex - Provides a more efficient way to lay out, align and distribute space among items in a container. This is beneficial when we need to provide a layout to elements of an unknown/dynamic size. There are more flexbox modifiers which can provide the conditions required at specific breakpoints: .ons-grid--center, .ons-grid--between, .ons-grid--vertical-center, .ons-u-flex-shrink@m, .ons-u-flex-no-shrink@m, .ons-u-flex-grow@m, .ons-u-flex-no-grow@m, .ons-u-flex-no-basis@m.

Gutterless

.ons-grid--gutterless - Removes all gutters from columns.

Tight

.ons-grid--tight - Uses 1/2 sized gutters.

Loose

.ons-grid--loose - Uses double-sized gutters.

Spaced

.ons-grid--spaced - Adds gutter-sized margins beneath each column. Can be combined with other modifiers that affect margins.

Pixel Gutters

.ons-grid--pixelgutter - Sets the gutters to 1px

Push & Pull

.ons-push-1@m .ons-pull-1@m - Moves the .ons-grid__col the specified number of columns (at the specified breakpoint/s) either left or right.

Creating layouts

Layouts can be created by specifying the number of columns required. Grid based layouts should be wrapped with the class .ons-container. This will centre the layout and provide a maximum width of 1032px. There is an additional modifier class ons-container--wide which will increase the maximum width to 1280px. If your service requires a full width layout a modifier is available by using .ons-container--full-width.

A typical page layout for body content on an ONS service will use 8 columns for the main content at 740px and greater (.ons-col-8@m) as shown below:

<div class="ons-container">
  <div class="ons-grid">
    <div class="ons-grid__col ons-col-8@m ">
      <div class="ons-pl-grid-col">8 col</div>
    </div>
  </div>
</div>
{% from "foundations/layout/grid/_macro.njk" import patternLibExampleGrid %}
{{
    patternLibExampleGrid({
        'container': true,
        "itemsList": [
            {
                'col': 8
            }
        ]
    })
}}
{% macro patternLibExampleGrid(params) %}
  {% if params.container -%}
    <div class="ons-container">
  {% endif -%}

  <div class="ons-grid">
      {% for item in (params.itemsList if params.itemsList is iterable else params.itemsList.items()) -%}
          {% for i in range(0, item.repeat | default(1)  ) -%}
              <div class="ons-grid__col ons-col-{{ item.col }}@m {{ item.classes }}">
                  <div class="ons-pl-grid-col">{{ item.col }} col</div>
              </div>
          {%- endfor %}
      {%- endfor %}
  </div>

  {% if params.container is defined and params.container -%}
    </div>
  {% endif -%}
{% endmacro %}

If a sidebar is required, the main content should use 7 columns (ons-col-7@m). The sidebar should be 4 columns (.ons-col-4@m) and pushed right 1 column (ons-push-1@m) to provide a column gap between the main content and the sidebar. The example below shows the layout.

<div class="ons-container">
  <div class="ons-grid">
    <div class="ons-grid__col ons-col-7@m ">
      <div class="ons-pl-grid-col">7 col</div>
    </div>
    <div class="ons-grid__col ons-col-4@m ons-push-1@m">
      <div class="ons-pl-grid-col">4 col</div>
    </div>
  </div>
</div>
{% from "foundations/layout/grid/_macro.njk" import patternLibExampleGrid %}
{{
    patternLibExampleGrid({
        'container': true,
        "itemsList": [
            {
                'col': 7
            },
            {
                'classes': 'ons-push-1@m',
                'col': 4
            }
        ]
    })
}}
{% macro patternLibExampleGrid(params) %}
  {% if params.container -%}
    <div class="ons-container">
  {% endif -%}

  <div class="ons-grid">
      {% for item in (params.itemsList if params.itemsList is iterable else params.itemsList.items()) -%}
          {% for i in range(0, item.repeat | default(1)  ) -%}
              <div class="ons-grid__col ons-col-{{ item.col }}@m {{ item.classes }}">
                  <div class="ons-pl-grid-col">{{ item.col }} col</div>
              </div>
          {%- endfor %}
      {%- endfor %}
  </div>

  {% if params.container is defined and params.container -%}
    </div>
  {% endif -%}
{% endmacro %}

The example below shows the use of flexbox to create the layout for the phase banner.

<div class="ons-phase-banner">
  <div class="ons-container">
    <div class="ons-grid ons-grid--flex ons-grid--gutterless ons-grid--vertical-top ons-grid--no-wrap">
      <div class="ons-grid__col ons-col-auto ons-u-flex-no-grow ons-u-flex-no-shrink">
        <h3 class="ons-phase-banner__badge">Beta</h3>
      </div>
      <div class="ons-grid__col ons-col-auto ons-u-flex-shrink">
        <p class="ons-phase-banner__desc ons-u-fs-s ons-u-mb-no">This is a new service – to help improve it please <a href="#feedback">give us your feedback</a></p>
      </div>
    </div>
  </div>
</div>
{% from "components/phase-banner/_macro.njk" import onsPhaseBanner %}
{{
    onsPhaseBanner({
        "html": 'This is a new service – to help improve it please <a href="#feedback">give us your feedback</a>'
    })
}}
Name Type Required Description
html string true The text content for the phase banner. This can contain HTML.
badge string false The text for the phase banner badge. Defaults to “Beta”.
hideBadge boolean false Set to “true” to hide the phase banner badge
wide boolean false Set to “true” to increase the maximum width of the layout container to 1280px
{% macro onsPhaseBanner(params) %}
    <div class="ons-phase-banner">
        <div class="ons-container{{ ' ons-container--wide' if params.wide }}">
            <div class="ons-grid ons-grid--flex ons-grid--gutterless ons-grid--vertical-top ons-grid--no-wrap">
                {% if not params.hideBadge %}
                <div class="ons-grid__col ons-col-auto ons-u-flex-no-grow ons-u-flex-no-shrink">
                    <h3 class="ons-phase-banner__badge">{{ params.badge | default("Beta") }}</h3>
                </div>
                {% endif %}
                <div class="ons-grid__col ons-col-auto ons-u-flex-shrink">
                    <p class="ons-phase-banner__desc ons-u-fs-s ons-u-mb-no">{{ params.html | safe }}</p>
                </div>
            </div>
        </div>
    </div>
{% endmacro %}
.ons-phase-banner {
  background: $color-grey-5;
  padding: 0.5rem 0;

  &__badge {
    background: $color-black;
    color: $color-white;
    font-size: 0.85rem;
    line-height: 1em;
    margin: 0 0.5rem 0 0;
    padding: 0.4rem;
    text-transform: uppercase;
  }

  &__desc {
    margin-top: 0.3rem;
  }
}

Help improve this layout

Let us know how we could improve this layout or share your user research findings. Discuss the ‘Grid’ layout on Github 

More in ‘Foundations’

Layout

Style