Visual Architecture

Visual architecture

Note: the below describes a few ideals that have not yet been implemented, but it will give us and others direction.

The architecture we have composed consists of two parts. Structure and Style.


App shell

The app shell contains parts of the layout that rarely change as the app is used.

This may contain small state changes, such as the selected state of a navigation changing.

The app shell will also have a placeholder for the page.

The app shell may also contain layouts.

You can read this article for a more detailed description for an app shell model and it's benefits.


The page is the content that is loaded dependent on the route requested by the client, e.g. /explore.

The page can consist of one or more layouts.

The page will rarely, if ever, have styles.

Layout elements

Elements are intentionally stupid objects, including:

  • Rows: allows styling of full width
  • Containers: Constrains the contained content to a certain width or behavior.

Layout elements may contain components, but may not contain themselves.

Layout elements will always manage their own style, but have access to global styles.


Components are the pieces of the puzzle that make up the great chunk of information within the application. TODO: add info.


Global style

Globally accessible, reusable styles are defined in_root-scope-classes.scss.

Where possible, we want to limit the amount of styles that need to be written when creating a new component. To this end, we have created a finite set of spacing (margin/padding) and typography classes, as well as class utility functions that simplify the process of adding these classes directly to the markup.

Typography classes

We have a predefined set of typography styles. This means we can avoid redeclaring font properties every time we create a new component.

Instead, there is a class for each typography style at each breakpoint, and a font function that simplifies the process of adding these classes to the markup.

Each typography style has a name, e.g. WB3 (the third largest Wellcome Bold style). If we want the same typography style to be output at every breakpoint, we can write the following:

font({s: 'WB3'})

Alternatively, if we want to have the same style to cover both the small and medium breakpoints, and another to cover both the large and xlarge breakpoints we can write:

font({s: 'WB4', l: 'WB2'})

Occasionally, we may want to reset a type style's line-height to 1, to prevent it from introducing extra space when used in non-flowing copy. For this, we have the line-height-1 class.

Spacing classes

In a similar manner to the typography classes above, we have helper classes that apply various amounts of margins and padding to an element at each breakpoint.

Where possible, these classes should be used in preference to adding margins and padding within component scss files.

There is also a spacing function which should be used to apply these classes to the markup. The resulting classes apply multiples of our base spacing unit (6px) to any margin or padding direction up to 60px.

The filter operates on an object of breakpoint keys and values. It also takes an object as an argument, which can contain 'margin' and/or 'padding' keys, which in turn take an array of directions ('top', 'bottom', 'left', 'right') on which to operate. The breakpoint values are multiplied by our base spacing unit (6px) and the resulting amount will be used as the value for whichever properties are specified in the parameter object.

For example, if an element should have 12px top and bottom padding at the small and medium breakpoints, then 24px top and bottom padding at large and xlarge breakpoints, we can write:

spacing({s: 2, l: 4}, {padding: ['top', 'bottom']})

Or if an element should have 6px, 12px, 24px and 48px bottom margin at small, medium, large and xlarge breakpoints respectively, we can write:

spacing({s: 1, m: 2, l: 3, xl: 4}, {margin: ['bottom']})



The layout has a maximum width of 1338px.


The layout utilises 4 breakpoints:

  • small: >= 0
  • medium: >= 600px
  • large: >= 960px
  • xlarge: > 1338px

Grid columns/spacing

The grid consists of 12 columns and breakpoints determine the spacing between the columns, i.e. gutters, and the space either side of the layout, i.e. margins.

  • s: 18px gutters, 18px margins
  • m: 24px gutters, 42px margins
  • l: 30px gutters, 60px margins
  • xl: 30px gutters, 60px margins

Page layout

Pages with a right-hand rail (article, work, exhibition, event) have standard column-widths at common breakpoints.

Breakpoint Main columns Aside columns
Small s: 12 s: 12
Medium m: 10, shiftM: 1 m: 10, shiftM: 1
Large l: 7 l: 5
Extra large l: 7 l: 5