@financial-times/o-layout
v5.4.0
Published
Provides page layouts and typography as a starting point to create internal tools or products.
Downloads
1,398
Readme
o-layout
Whole page layouts including typography.
Table of Contents
- Overview
- Usage
- Typography
- Messages
- Default and Bleed Layout
- Documentation Layout
- Landing Layout
- Query Layout
- Sass
- JavaScript
- Migration Guide
- Troubleshooting
- Contact
- Licence
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 |
└————————————————————┘
Skip Links
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
)
Fonts Option
By default fonts are output where the typography
feature is enabled. To avoid outputting fonts set the fonts
option to false
. This may helpful in the case that:
- Your project already outputs standard font faces via
o-fonts
, or; - You are using custom fonts.
@include oLayout(
$opts: (
'layouts': (
'documentation',
'landing',
'query',
'bleed',
),
'features': (
'sidebar-nav',
'sticky-sidebar-container',
'linked-headings',
'typography',
),
'fonts': false,
)
);
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 |
Troubleshooting
Layout of components breaks inside o-layout
Some other Origami components may appeear broken when used inside the o-layout-typography
class. This is because the class styles children elements which leads to components appearing broken. Ideally, this class should only be used with copy.
To fix this, remove the o-layout-typography
class and your components should appear as normal. If typography styiling is needed, please re-arrange your code so that the class can solely target copy that needs the styling.
You can read more about this class in the typography section of this readme.
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.