Skip to content

Instantly share code, notes, and snippets.

@gulbanana
Created November 21, 2020 03:23
Show Gist options
  • Save gulbanana/d741b6b189edbf6f431a942607978537 to your computer and use it in GitHub Desktop.
Save gulbanana/d741b6b189edbf6f431a942607978537 to your computer and use it in GitHub Desktop.

CSS layout has a lot of legacy complexity but has mostly been retroactively explained as a consistent cross-browser model. This document lists the concepts we care about today, and the way they're used in widget design.

LAYOUT MODELS

There are three general-purpose algorithms used by an element to lay out its children: Flow, Flex and Grid. Flow is the original HTML layout model, intended for text-based documents; the others are newer and often more suitable for application layouts. Grid is also useful for large-scale layout of document-like pages, and Flex is generally the most suitable for composable widgets, but all three are relevant.

For historical reasons, the detail of Flow layouts is controlled by the layout of their child elements - each either a 'block' or an 'inline' - as well as the float and clear properties on those children. These properties are difficult to use correctly and should be avoided in favour of flex/grid.

Flex and Grid layouts are configured using the box alignment properties (see https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Box_Alignment) as well as various flex-[..] and grid-[..] properties. Confusingly, the grid shorthand property combines the layout properties of the outer element, but the flex shorthand property is for flex items to configure their role within a flex layout. This is essentially the difference between the two modern layouts: a Grid specifies templates and regions within which its children just select an slot (using grid-column, grid-row or grid-area). A Flow sets alignment and wrapping rules (as does Grid) but the formation of 'rows' and 'columns' is up to its children.

The display property is effectively shorthand for display-inside and display-outside, as well as several other more obscure properties. display-inside controls the layout of an element's children, and display-outside controls the layout of the element itself if it is part of a flow layout. Generally we will only use the higher level display:, which is idiomatic and has better browser support (since the other two are retcons). We're mostly interested in the following values:

  • display: flow - this is the default and is not usually explicitly set as it doesn't specify display-outside. Instead, use one of the next two values.
  • display: block - Flow layout inside; box outside.
  • display: inline - Flow layout inside; inline outside.
  • display: flex - Flex layout inside; box outside.
  • display: grid - Grid layout inside; box outside.

For building inlines, the following shorthand values may also be useful:

  • display: inline-block - New flow layout inside, not part of the existing formatting tree; inline outside.
  • display: inline-flex - Flex layout inside; inline outside.
  • display: inline-grid - Grid layout inside; inline outside. They're being obsoleted in favour of the explicit outside/inside settings inline/flow-root, inline/flex and inline/grid, but the new version is not well supported.

There are also some special display values which are retconned shorthand for display-box:

  • display: none - Nothing is rendered at all. This is the most complete way to 'toggle off' a subtree of DOM elements.
  • display: content - The element is replaced by its children. Used for semantic 'markers', but it has a number of special cases and bugs.

COMPONENT DESIGN

By default, all components in the framework are built as 'boxes' which are suitable for use in any of the major layout models, except for components specifically intended to be used as 'inlines' in a Flow layout. These unusual components will generally be wrappers around some sort of primitive (NavLink, TextInput) or or will be part of a family like FooField.

What this means in practice is that the top level of most components should be a block-level element (div, p, article etc) and/or should have a display value like block, flex or grid. The top level element of inline components should be an inline element (span, a, em etc) or have a display value such as inline-flex or inline-grid. It's preferable to use an element of the right type, making the markup comprehensible and easier to style, but this isn't a hard rule - if you want display: inline-block you aren't going to find some sort of built in <divspan>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment