@financial-times/o-layout

5.3.4 • Public • Published

o-layout

Whole page layouts including typography.

Table of Contents

Overview

o-layout provides page layouts and typography as a starting point for new pages. Layouts provided vary per brand and include:

layout description core brand internal brand whitelabel brand
default An empty layout with contained content well.
bleed An empty layout with full-width "bleed" content.
documentation A documentation/blog page layout.
landing A landing/homepage layout.
query A search/query page layout.

Usage

Check out how to include Origami components in your project to get started with o-layout.

Typography

When writing large amounts of copy, such as in documentation, typographic elements may be styled using the o-layout-typography class on a containing element.

<div class="o-layout-typography">
	<h1>Page title</h1>
	<p>Some body copy.</p>
	<ul>
		<li>item a</li>
		<li>item b</li>
	</ul>
</div>

This will style child headings, paragraphs, lists, anchor, and more tags but will also affect the style of child components. The .o-layout__unstyled-element class may be used to opt-out of typography styling on a specific element. However we recommend only using o-layout-typography on elements with copy.

<div class="o-layout-typography">
	<h1>Page title</h1>
	<p>Some body copy.</p>
	<ul>
		<li>item a</li>
		<li>item b</li>
	</ul>
</div>

<!-- No `.o-layout-typography` container -->
<div class="o-example-component">
	<p>A complex component.</p>
	<a href="#">example</a>
</div>

<div class="o-layout-typography">
	<p>Body copy continues.</p>
</div>

To style typographic elements individually see the o-typography component.

<h1 class="o-typography-heading-level-1">Page title</h1>
<p class="o-typography-body">Some body copy.</p>

Messages

All layouts include a header and footer area. These can be thought of as "top" and "bottom" areas that may include multiple components. For example the header area may include a heading component such as o-header-services and a full bleed alert such as from o-message.

Default And Bleed Layout

The default layout is intended for flexible use when another layout isn't suitable. We recommend using the documentation, landing, or query layout where possible.

The default layout has a single content area "Main Content"

┌————————————————————————————┐
|           HEADER           |
├————————————————————————————┤
|        MAIN CONTENT        |
|                            |
|                            |
|                            |
├————————————————————————————┤
|           FOOTER           |
└————————————————————————————┘
<div class="o-layout" data-o-component="o-layout">
	<div class="o-layout__header">
		<!-- Your header, navigation, and full-bleed alert messages here. -->
	</div>
	<div class="o-layout__main o-layout-typography">
		<!-- Your page content here. -->
	</div>
	<footer class="o-layout__footer">
		<!-- Your footer & navigation here. -->
	</footer>
</div>

The content area has a max width by default. To make the content area full width use the bleed layout. To use the bleed layout add a modifier class o-layout--bleed. Do not use the bleed layout with any other layout. Note: If you are using o-header-services as your header set it to bleed also.

-<div class="o-layout" data-o-component="o-layout">
+<div class="o-layout o-layout--bleed" data-o-component="o-layout">
</div>

Documentation Layout

The documentation layout is intended for text-heavy pages, such as technical documentation or blog posts. The documentation layout includes the following areas (in addition to a heading and footer):

  • Main Content
  • Sidebar (optional)
┌————————————————————————————┐
|           HEADER           |
├————————————————————————————┤
| SIDE  |    MAIN CONTENT    |
| BAR   |                    |
|       |                    |
|       |                    |
├————————————————————————————┤
|           FOOTER           |
└————————————————————————————┘
<div class="o-layout o-layout--docs" data-o-component="o-layout">
	<div class="o-layout__header">
		<!-- Your header, navigation, and full-bleed alert messages here. -->
	</div>
	<div class="o-layout__sidebar o-layout-typography">
		<!-- Your sidebar here (optional). -->
	</div>
	<div class="o-layout__main o-layout-typography">
		<!-- Your page content here. -->
	</div>
	<footer class="o-layout__footer">
		<!-- Your footer & navigation here. -->
	</footer>
</div>

Main Content

On large viewports the main content area (o-layout__main) is split into two columns.

┌————————————————————————————┐
|                            |
├————————————————————————————┤
|       |   col 1    | col 2 |
|       |            |       |
|       |            |       |
|       |            |       |
├————————————————————————————┤
|                            |
└————————————————————————————┘

Most content is placed into column 1 by default. The exceptions are the aside element, which is placed in column 2; and the table element, which spans both columns.

Use a containing div with class o-layout__main__single-span to constrain elements to column 1. Use a o-layout__main__full-span container to expand elements to span both columns.

<!-- Your page content here. -->
<div class="o-layout__main o-layout-typography">
	<!-- Most content is placed in column 1 -->
	<h2>A Title</h2>
	<p>Some content.</p>
	<!-- Asides are placed in column 2 by default -->
	<aside>An aside</aside>
	<!-- Tables span columns 1 & 2 by default -->
	<table></table>
	<!-- The class "o-layout__main__single-span" constrains elements to column 1 -->
	<div class="o-layout__main__single-span">
		<!-- Your elements -->
	</div>
	<!-- The class "o-layout__main__full-span" expands elements to span columns 1 & 2 -->
	<div class="o-layout__main__full-span">
		<!-- Your elements -->
	</div>
</div>

Sidebar

By default o-layout will generate a sidebar navigation for the documentation layout. This feature is also supported by the query layout but is disabled by default. You will need to include an empty <div class="o-layout__sidebar> somewhere before your main content. The sidebar links to any <h2> or <h3> element within the main content area, providing it has an id.

If you wish to display headings other than <h2> and <h3> in the navigation, you can customise the selector that's used with the data-o-layout-nav-heading-selector data attribute. For example, to select only headings which have the class nav-heading, use the following:

+ <div class="o-layout" data-o-component="o-layout" data-o-layout-nav-heading-selector=".nav-heading">
- <div class="o-layout" data-o-component="o-layout">

To customise your sidebar navigation entirely, add the data attribute data-o-layout-construct-nav="false" to the root o-layout element. Then add your own nav element within the sidebar, with the class o-layout__navigation and a child list.

Altogether, a customised navigation should look like this:

+<div class="o-layout" data-o-component="o-layout" data-o-layout-construct-nav="false">
	<div class="o-layout__header">
		<!-- o-header-services markup goes here -->
	</div>

	<div class="o-layout__sidebar">
+		<nav class="o-layout__navigation">
			<!-- this can be an <ol> or a <ul> -->
+			<ol>
+				<li>
+					<a href="#this-is-a-title">This is a title</a>
+				</li>
+			</ol>
+		</nav>
	</div>

	<div class="o-layout__main">
		<h2 id="this-is-a-title">This Is A Title</h2>
	</div>

	<footer class="o-layout__footer"></footer>
</div>

Alternatively you can customise the navigation via JavaScript.

Landing Layout

The landing layout is ideal for a homepage or other key category / directory pages. The landing layout provides two areas (in addition to a header and a footer):

  • Hero (optional)
  • Main Content
┌————————————————————————————┐
|           HEADER           |
├————————————————————————————┤
|            HERO            |
├————————————————————————————┤
|         MAIN CONTENT       |
├————————————————————————————┤
|           FOOTER           |
└————————————————————————————┘
<div class="o-layout o-layout--landing" data-o-component="o-layout">
	<div class="o-layout__header">
		<!-- Your header, navigation, and full-bleed alert messages here. -->
	</div>
	<div class="o-layout__hero o-layout-typography">
		<!-- Your hero content here (optional). -->
	</div>
	<div class="o-layout__main o-layout-typography">
		<!-- Your landing page content here. -->
	</div>
	<footer class="o-layout__footer">
		<!-- Your footer & navigation here. -->
	</footer>
</div>

When the landing page is a sub-page of the site, the hero area may create a visual conflict with the homepage (e.g. on a category / directory page). To reduce the impact of the hero area on sub pages add the modifier class o-layout__hero--muted.

 <div class="o-layout o-layout--landing" data-o-component="o-layout">
	 <div class="o-layout__header">
		 <!-- Your header, navigation, and full-bleed alert messages here. -->
	 </div>
+	 <div class="o-layout__hero o-layout__hero--muted o-layout-typography">
-	 <div class="o-layout__hero o-layout-typography">
		 <!-- Your hero content here (optional). -->
	 </div>
	 <div class="o-layout__main o-layout-typography">
		 <!-- Your landing page content here. -->
	 </div>
	 <footer class="o-layout__footer">
		 <!-- Your footer & navigation here. -->
	 </footer>
 </div>

Overview Sections

Within the main content area the landing layout provides an overview section. The overview section is ideal for outlining key points of the landing page.

Any number of items are allowed within an overview section, but will wrap onto a new row if there are more than 4.

Overview with 3 items:

├———————————————————————————————————————┤
|  content  |   content   |   content   |
├———————————————————————————————————————┤
	<div class="o-layout__main o-layout-typography">
		<!-- Your landing page content here. -->
		<!-- Overview -->
		<div class="o-layout__overview">
			<div class="o-layout-item">
				<h2>Great For This</h2>
				<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
			</div>
			<div class="o-layout-item">
				<h2>Good For That</h2>
				<p>Blanditiis, dolor. Autem recusandae vero ut labore?</p>
			</div>
			<div class="o-layout-item">
				<h2>And More</h2>
				<p>Corrupti nemo voluptate aperiam explicabo vitae cupiditate atque fugiat dignissimos.</p>
			</div>
		</div>
	</div>

There is also an actions overview. These support a footer, which is useful for highlighting calls to action with links or buttons.

Actions overview with 4 items with footer:

├———————————————————————————————————————┤
| content | content | content | content |
| content |         | content | content |
| content |         | content |         |
├ ——————— | ——————— | ——————— | ——————— ┤
| footer  | footer  | footer  | footer  |
├———————————————————————————————————————┤
	<!-- Your landing page content here. -->
	<div class="o-layout__main o-layout-typography">
		<!-- Actions Overview -->
		<div class="o-layout__overview o-layout__overview--actions">
			<div class="o-layout-item">
				<div class="o-layout-item__content">
					<h3>Here's A Thing</h3>
					<p>Lorem ipsum dolor sit amet consectetur adipisicing elit.</p>
				</div>
				<div class="o-layout-item__footer">
					<a href="#">Take An Action</a>
				</div>
			</div>
			<div class="o-layout-item">
				<div class="o-layout-item__content">
					<h2>And Another</h2>
					<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Deleniti, numquam!</p>
				</div>
				<div class="o-layout-item__footer">
					<a href="#">Do A Thing</a>
				</div>
			</div>
			<div class="o-layout-item">
				<div class="o-layout-item__content">
					<h2>And More Choices</h2>
					<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, voluptatibus?</p>
				</div>
				<div class="o-layout-item__footer">
					<a href="#">Do A Different Thing</a>
				</div>
			</div>
			<div class="o-layout-item">
				<div class="o-layout-item__content">
					<h2>What To Do</h2>
					<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Natus, voluptatibus?</p>
				</div>
				<div class="o-layout-item__footer">
					<a href="#">Learn More</a>
				</div>
			</div>
		</div>
	</div>

Sometimes a page may have multiple overview sections. In this case it can appear odd to have three overview items followed by a separate section with four more narrow items. To enforce that the items in each overview section have the same width apply the o-layout__overview--consistent-columns modifier class.

	<!-- Your landing page content here. -->
	<div class="o-layout__main o-layout-typography">
		<!-- Actions Overview 1 -->
		<div class="o-layout__overview o-layout__overview--consistent-columns">
			<!-- 3 o-layout-item items (see above example) -->
		</div>

		<!-- Actions Overview 2 -->
		<div class="o-layout__overview o-layout__overview--consistent-columns">
			<!-- 4 o-layout-item items (see above example) -->
		</div>
	</div>
├———————————————————————————————————————┤
| content | content | content |         |
| content |         | content |         |
| content |         | content |         |
├———————————————————————————————————————┤

├———————————————————————————————————————┤
| content | content | content | content |
| content | content | content | content |
| content |         | content |         |
├———————————————————————————————————————┤

See the registry demos for an example landing page.

Article List

The landing layout can also be used to display a list of articles. This is useful for a blog for example, especially when combined with the muted hero element o-layout__hero--muted.

To list articles within the hero layout remove the o-layout-typography class from the o-layout__main element. Then add a child unordered list element ul with class o-layout__listing and a number of list items, as shown in the following example:

 <div class="o-layout o-layout--landing" data-o-component="o-layout">
	<div class="o-layout__header">
		<!-- Your header, navigation, and full-bleed alert messages here. -->
	</div>
	<div class="o-layout__hero o-layout__hero--muted o-layout-typography">
		<!-- Your hero content here.  -->
	</div>
	 <div class="o-layout__main">
		<ul class="o-layout__listing">
			<li class="o-layout__listing__item">
				<h2 class="o-layout__listing__item__title">
					<a href="#">Example Article Title</a>
				</h2>
				<p class="o-layout__listing__item__description">Example article description / blurb.</p>
				<p class="o-layout__listing__item__meta">
					Posted <time datetime="2020-10-28T00:00:00Z">20 November 2020</time>
					by Author Name. Tagged: <span>Newsletter</span>.
				</p>
			</li>
		</ul>
	 </div>
	<footer class="o-layout__footer">
		<!-- Your footer & navigation here. -->
	</footer>
 </div>

Query Layout

The query layout is intended for search, filter, and result pages. It provides four areas (in addition to a header and a footer):

  • Heading
  • Query Sidebar
  • Main Content
  • Aside Sidebar (optional)
<div class="o-layout o-layout--query" data-o-component="o-layout">
	<div class="o-layout__header">
		<!-- Your header, navigation, and full-bleed alert messages here. -->
	</div>
	<div class="o-layout__heading o-layout-typography">
		<!-- Your title / heading content here. -->
	</div>
	<div class="o-layout__query-sidebar o-layout-typography">
		<!-- Your search or filter inputs. -->
	</div>
	<div class="o-layout__main o-layout-typography">
		<!-- Your search results or other main content. -->
	</div>
	<div class="o-layout__aside-sidebar o-layout-typography">
		<!-- Your asides / additional information (optional). -->
	</div>
	<div class="o-layout__footer">
		<!-- Your footer & navigation here. -->
	</div>
</div>

Query Sidebars

The query sidebar supports a generated navigation like the documentation layout but it is disabled by default and must be turned on with data-o-layout-construct-nav="true":

<div class="o-layout o-layout--query" data-o-component="o-layout" data-o-layout-construct-nav="true">
	<!-- query layout -->
</div>

Alternatively the .o-layout-sticky-sidebar-container class may be used as a child of the query sidebars. Its contents will stick to the top of the viewport as the user scrolls.

<div class="o-layout o-layout--query" data-o-component="o-layout">
	<!-- ... -->
	<div class="o-layout__aside-sidebar o-layout-typography">
		<!-- Sticky container for sidebar content (optional) -->
		<div class="o-layout-sticky-sidebar-container">
			<!-- Your asides / additional information (optional). -->
		</div>
	</div>
	<!-- ... -->
</div>

Large Viewports

┌————————————————————————————┐
|           HEADER           |
├————————————————————————————┤
|       |  HEADING   |       |
|       ├————————————┤       |
| QUERY |  MAIN      | ASIDE |
| SIDE  |  CONTENT   | SIDE  |
| BAR   |            | BAR   |
|       |            |       |
├————————————————————————————┤
|           FOOTER           |
└————————————————————————————┘

This layout may be used without a right-hand side bar. To remove it, delete the aside sidebar element o-layout__aside-sidebar.

┌————————————————————————————┐
|           HEADER           |
├————————————————————————————┤
|       |  HEADING           |
|       ├————————————————————|
| QUERY |  MAIN              |
| SIDE  |  CONTENT           |
| BAR   |                    |
|       |                    |
├————————————————————————————┤
|           FOOTER           |
└————————————————————————————┘

Medium Viewports

┌————————————————————————┐
|          HEADER        |
├————————————————————————┤
|       |  HEADING       |
|       ├————————————————┤
|       |                |
| QUERY |  MAIN          |
| SIDE  |  CONTENT       |
| BAR   |                |
|       ├————————————————┤
|       | ASIDE SIDE     |
|       | BAR            |
├————————————————————————┤
|          FOOTER        |
└————————————————————————┘

Small Viewports

┌————————————————————┐
|       HEADER       |
├————————————————————┤
| HEADING            |
├————————————————————┤
| QUERY SIDE BAR     |
├————————————————————┤
| MAIN CONTENT       |
├————————————————————┤
| ASIDE SIDE BAR     |
├————————————————————┤
|       FOOTER       |
└————————————————————┘

To add a skip link to your project, place a link with the o-layout-skip-link class at the top of the page. It is important the link comes before the nav or any other tab-able content.

<a class="o-layout-skip-link" href="#o-layout-main-content">
	Skip to Content
</a>

To ensure the link navigates to the right place, give the main content an id. The id must correspond to the skip link’s href.

<main id="o-layout-main-content">
	<!-- ... -->
</main>

Sass

You can include o-layout styles with the oLayout mixin.

As o-layout only supports the internal brand, your project must also set its brand to internal $o-brand: 'internal';.

$o-brand: 'internal';
@import '@financial-times/o-layout/main';

@include oLayout();

If your project does not use all layouts or other features provided by o-layout, include them selectively with an $opts argument.

Layout Options

  • documentation
  • landing
  • query
  • bleed

Feature Options

  • sidebar-nav (enables the generated sidebar navigation for the query layout. Styles for the sidebar navigation are included by default with the documentation layout.)
  • sticky-sidebar-container (A containing element for use within o-layout sidebars. Sticks to the top of the viewport as the user scrolls. See query layout examples.)
  • linked-headings (enables clickable / highlighted anchors on the page)
  • typography (enables body typography applied with the class o-layout-typography)
@include oLayout($opts: (
	'layouts': ('documentation', 'landing', 'query', 'bleed'),
	'features': ('sidebar-nav', 'sticky-sidebar-container', 'linked-headings', 'typography')
));

The landing layout supports an extra option, which sets a background image on the hero area:

@include oLayout($opts: (
	'layouts': ('documentation', 'landing', 'query', 'bleed'),
	'features': ('linked-headings', 'typography'),
	'hero-image': 'https://example.com/image.png',
));

JavaScript

No code will run automatically unless you are using the Build Service. You must either construct an o-layout object manually or fire an o.DOMContentLoaded event, which o-layout listens for.

Use the following to initialise your layout manually:

import oLayout from '@financial-times/o-layout';
oLayout.init();

Custom Navigation

The documentation layout uses JavaScript to construct a sidebar navigation out of headings (h1, h2 and h3) in the content, and to highlight those items depending on the scroll position. The query layout also supports a generated nav but by default it is disabled.

To generate a nav for the query layout, or turn it off for the documentation layout, explicitly set the "construct navigation" option to true or false. Either declaritively in your html with the data-o-layout-construct-nav attribute:

<div class="o-layout o-layout--query" data-o-layout-construct-nav="true" data-o-component="o-layout">
	<!-- Layout markup. -->
</div>

Or imperatively with JavaScript, by setting the constructNav option:

import oLayout from '@financial-times/o-layout';
oLayout.init(null, { constructNav: true });

If you would like to change what items show in the generated navigation, set the "navigation heading selector" option to any valid CSS selector. Do this declaritively in your html with the data-o-layout-nav-heading-selector attribute:

<div class="o-layout o-layout--query" data-o-layout-nav-heading-selector="h1, h2, .nav-heading" data-o-component="o-layout">
	<!-- Layout markup. -->
</div>

Or imperatively with JavaScript, by setting the navHeadingSelector option:

import oLayout from '@financial-times/o-layout';
oLayout.init(null, { navHeadingSelector: 'h1, h2, .nav-heading' });

Linking Headings

Heading elements such as h1, h2, etc that have an id attribute are made linkable by default. The heading can then be clicked to update the URL with a hash, for sharing a direct link to that heading.

To customise which headings can be clicked and linked to directly, set the linkedHeadingSelector option to any valid CSS selector string:

import oLayout from '@financial-times/o-layout';
oLayout.init(null, { linkedHeadingSelector: 'h1, h2, .link-heading' });

Turn off linkable headings by setting linkHeadings to false:

import oLayout from '@financial-times/o-layout';
oLayout.init(null, { linkHeadings: true });

Migration Guide

State Major Version Last Minor Release Migration guide
✨ active 5 N/A migrate to v5
⚠ maintained 4 N/A migrate to v4
╳ deprecated 3 3.3 migrate to v3
╳ deprecated 2 2.2.5 migrate to v2
╳ deprecated 1 1.3.4 N/A

Contact

If you have any questions or comments about this component, or need help using it, please either raise an issue, visit #origami-support or email Origami Support.

Licence

This software is published by the Financial Times under the MIT licence.

Package Sidebar

Install

npm i @financial-times/o-layout

Weekly Downloads

1,589

Version

5.3.4

License

MIT

Unpacked Size

109 kB

Total Files

28

Last publish

Collaborators

  • robertboulton
  • seraph2000
  • hamza.samih
  • notlee
  • emmalewis
  • aendra
  • the-ft
  • rowanmanning
  • chee
  • alexwilson