« resources

Smashing Workshop

Flowing & Flexing

distributing content on the page

workshops.oddbird.net/smashing24/flex/

Cmd/Ctr-K for Controls
  • This week:
  • Starting to look at web layout
  • How things fit on a page

Design Unknown Content
On An Unknown Canvas

  • And since we often don’t know
  • Details about the final page
  • Or the exact content inside it
  • We have to develop layout systems
A pink box labeled
context (defines available space),
and blue text overflowing the box
in the style of the awesome meme says
this content (takes up space)
  • That can manage this back and forth negotiation
  • Between context and content
The pink box is now labeled
extrinsic size (imposed from outside),
and the oveflowing blue text
now has a dashed box and says
intrinsic size (from the content)
  • One pushing in,
  • Imposing extrinsic constraints (context)
  • The other pushing out,
  • An intrinsic size determined by content
  • How the two forces ‘flow’ by default
  • And how we can manipulate that flow

CSS takes a source document organized as a tree of elements… and text nodes… and renders it onto a canvas such as your screen.

CSS Display Module Level 4

  • Starting from a source document (html)
  • Organized into a nested ‘tree’
  • of Elements & Text Nodes
  • Rendered onto…

The document canvas is the infinite surface over which the document is rendered.

CSS Backgrounds and Borders

  • An infinite canvas!
The Crab Nebula photo: Webb Space Telescope
  • So… that’s daunting
  • But there are some constraints…
Earth seen through a window on the international space station
  • Browser provides a finite viewport
  • The window we look through to see…
Two-Dimensional Viewport [Physical Dimensions]
  • Our document rendered on this 2-dimensional canvas
  • Gives us a finite width/height to start from
  • Viewport is kinda like a div, outside our document
  • Parent of the root element
  • We can’t style (directly)
  • Establishes a flow
Flow (boxes) [present, debug]
  1. Box tree of elements and text nodes
  2. Each box has four areas: content, padding, border, & margin
  3. Four edges: content-box, padding-box, border-box, margin-box
  4. Each box provides a context for nested content to flow
  5. HTML box is contained by Viewport
  6. Display:none; (head/style) removes box & subtree
  7. Display:contents; (figure?) removes box
  8. Display:list-item; (li) generates a second ::marker box
  9. List-style-position moves ::marker in or out of primary box

Elements Generate Boxes

  • Every element generates a box by default
Diagram of the CSS box model, an inner content area surrounded by padding, a border, and margin – each area is labeled with arrows showing the space covered
Box Model Areas
  • With four box areas
  • (content, border, padding, and margin)
  • (B/P/M have their own properties)
  • But each of them…
Diagram of the CSS box model, with arrows to each box-edge: from an inner content-box edge around the content area, then (working out) a padding-box edge around the padding area, a border-box edge, and a margin-box edge
Box Model Edges
  • Has an outer box edge that we can reference
  • Using keywords
  • In addition to the box properties & keywords…

display property Box Generation Values

  • We can use the display property
  • To manipulate box generation…

display: none Removes Box Tree

Content also removed
  • Display-none will remove the box
  • (and its entire subtree)
  • So neither the box or anything inside is rendered.

display: contents Removes Box

Content remains
  • Display-contents will remove the box
  • But leave the contents in place
  • We’ll use this in flex/grid later,
  • But there have been some browser bugs…

Historically… ⚠️ Severe A11y Issues

Contents-display support data
  • Originally causing major accessibility issues
  • On a range of elements
  • Some of that has been fixed in recent releases, but…

Currently avoid… ⚠️ On Buttons & Tables

Contents-display support data
  • Most browsers still have issues
  • If you use this on buttons or tables
  • So don’t.
  • And moving forward, test
  • I find this most useful for adding/removing
  • ‘wrapper’ divs when doing layout

display: list-item Adds Marker Box

Outside (or inside) the principle box
  • In addition to removing element boxes
  • We can add them!
  • The list-item keyword
  • Generates an additional ::marker box
  • Which we can move in or out of the principle box

Two Outer Display Roles

inline or block

  • If we do want a box
  • We can also use the display prop
  • To select one of two outer display roles
  • Inline or block
  • Describe how our box behaves in a flow layout
  • First, inline-boxes and text nodes behave similarly…
Flow (inline) [present, debug]
  1. Text is written in lines (part of a ‘line box’)
  2. We can add (and nest) elements in-line with the text
  3. Inline content flows (expands/stacks) on the inline axis
  4. Line length intrinsic from contents
  5. Line height determined by line-height
  6. Explicit box sizes don’t apply
  7. Contribute border/padding/margins on the inline axis only
  8. Content fragments across new lines at container edge

Inline boxes… Sized by Content

Intrinsic sizes
  • Inline boxes as text nodes have intrinsic size
  • Determined by the content inside, and
  • line-height (initial normal from font metrics)
  • Explicit sizes are ignored
Text lines use inline axis [demo link]
  • These boxes flow & stack together in lines
  • We call the direction of that flow
  • The ‘inline axis’
  • It depends on…
Inline axis depends on writing mode [demo link]
  • …The writing mode of the language
  • So the inline axis is not always the width
  • Some languages are written in vertical lines
  • So the inline-axis will be the height instead
  • But flow doesn’t only have an axis…
Inline flow depends on language direction [demo link]
  • …It has a direction,
  • Which can also change based on the language
  • A right-to-left language (like Arabic)
  • will have horizontal lines
  • But the direction of flow is reversed

Inline boxes… Fragment Onto New Lines

Intrinsic sizes
  • When text lines reach a container edge
  • They fragment onto new lines…
Blocks of text stack… [demo link]
  • And stack together into blocks
  • The direction that lines stack is the block axis
  • Depends on language and writing mode
  • For English, it’s a vertical axis
  • But in Korean, Chinese, and Japanese languages
  • Blocks might stack from right to left
Flow (block) [present, debug]
  1. Blocks flow on the block axis
  2. Take their inline-size from external context (extrinsic)
  3. Take their block-size from internal content (intrinsic)
  4. Contribute padding/margins on both axis
  5. Adjacent margins collapse
  6. Can be explicitly sized (intrinsic or extrinsic)

Block boxes… Get inline-size from Context

look up to parents…

  • By default, blocks…
  • Take their inline-size from context
  • (Extrinsic, look up the tree, parent box)

Block boxes… Get block-size from Content

look down to children…

  • Take their block-size from content
  • (Intrinsic, look down the tree, child boxes)

Participate In Block Layout

Box display None or Contents

  • We’ve talked about display values
  • That turn off box generation
  • (display:none; display:contents)

Marker display List-Item

  • Or generate an additional marker box
  • (display:list-item)

Outer display Inline or Block

  • Or the two outer box roles
  • Inline or block
  • These apply to items in a flow layout
  • (The default for web layout)
  • How those items behave in their parent context
  • Their ‘outer’ behavior

Inner display Flex, Grid, Table-*

  • But display also defines ‘inner’ behavior
  • What layout mode should be applied to children
  • By default, boxes have an inner flow layout
  • Unless we explicitly set another layout type
  • Flex, or grid, or some form of table display

Inner display Flow or Flow-Root

More recent additions
  • But we can be more explicit now
  • Setting flow or flow-root

By default… Inner Display Flow

  • Flow is our default inner display value

display: block display: block flow;

Same inline » inline flow
  • When we set display to block
  • Implicitly setting inner value to flow
  • Same with setting inline
  • If we don’t set an inner value (flex, grid, table)
  • We get an inner value of flow

Flow Is ‘Normal

  • Flow is so ‘default’ we don’t see it as ‘layout’
  • This is just ‘how text works’
  • And the underlying boxes tend to disappear
Margin collapse & float overflow [present, debug]
  • Margins collapse to give us reasonable spacing
  • And floats ‘flow’ through neighboring boxes
  • Pushing inline-content to one side, continuing to wrap
  • But sometimes we want to break up our flow
  • Historically, solved floats with a ‘clearfix’
  • Or overflow: hidden;

Now… Display: Flow-Root

“A mini layout in your layout”…

  • Now we can be more explicit
  • Establishing not just a new flow
  • But a new flow-root
  • The flows are distinct, and should not overlap
Support data from CanIUse.com on the flow-root feature
[Can I Use]
  • Well supported since 2019

Flow-Root Block Formatting Context

Understanding CSS Layout And The Block Formatting Context
  • Generates a new Block Formatting Context
  • This is also what happens with overflow:hidden
Understanding CSS Layout And The Block Formatting Context [present, debug]
Understanding CSS Layout And The Block Formatting Context [present, debug]
Understanding CSS Layout And The Block Formatting Context [present, debug]

Flow-Root boxes… Can have Explicit Size

  • While inline flow boxes are always sized to content
  • Block and inline-block (or block flow-root) boxes
  • Can have explicit sizes
  • And contribute to the layout of both dimensions
  • Allows nesting other layouts inside a line box…

Inline & block Flows Separate

  • Which is otherwise not possible
  • Since inline & block flow on a different axis
  • The two don’t normally mix
  • They separate (oil and water)
Inline Splitting [present, debug]
  • If we put a block box inside an inline box
  • Browsers add ‘anonymous’ blocks to separate
  • Make it inline-block
  • It joins the inline flow
  • While still acting like a block box internally

Grid and flex Also Formatting Contexts

  • Other layout containers (grid, flex)
  • Also generate formatting contexts by default
  • No margin collapsing, or floats
  • So they don’t need special root values

By default… Outer Display Block

  • When define set these inner display values
  • Without defining an outer box role
  • The default outer display is block

display: flex display: block flex;

Same grid » block grid
  • A display of flex or grid
  • Implicitly sets outer value to block
  • Block flex, and block grid

Inline Layout Variants

inline-flex, inline-grid, inline-block

  • Why we have inline-flex, inline-grid, inline-block
  • Create more complex layouts, that participate…

Display-outside Inline

  • As inline-level boxes
  • In a parent flow of inline content
  • The outer display is ‘inline’

Display-inside Flex, Grid, or Flow-Root

  • But their inside display value
  • The layout context they create for children
  • Is flex or grid or flow-root
  • block » block flow
  • flow-root » block flow-root
  • inline » inline flow
  • flex » block flex
  • grid » block grid
  • list-item » block flow list-item
  • inline-block » inline flow-root
  • inline-flex » inline flex
  • inline-grid » inline grid
Single to multi-value display conversion
  • So these can get added to our list
  • Single display values that represent
  • Longer multi-value display behavior

display: list-item display: block flow list-item;

  • Along with list-item
  • Which we can define, implying both
  • Inner (flow) and outer (block) display defaults
  • A ‘block flow list-item’
[List Item Marker]
  • The element behaves as a block in the outer context
  • We get both a marker box and primary box
  • And inside the primary box,
  • Nested content continues to flow

Can I use… Multi-Value Display?

  • We call this new syntax multi-value display
  • It is new, but becoming widely supported

Fine to Use Single-Values

  • Don’t need to use new syntax
  • Helpful to understand display
  • Provide more clarity
  • Flexibility to mix and match (if needed)
A pink box labeled
context (defines available space),
and blue text overflowing the box
in the style of the awesome meme says
this content (takes up space)
  • Flow layout model specialized
  • To flow arbitrary content (text, images)
  • Through an unpredictable canvas
  • Without needing much input from us
The pink box is now labeled
extrinsic size (imposed from outside),
and the oveflowing blue text
now has a dashed box and says
intrinsic size (from the content)
  • The context defines the inline axis (width)
  • Starting from the viewport, out of our control
  • (extrinsic size, pushing in, setting line length)
  • And content defines the block axis (height)
  • (intrinsic size, wrapping to new lines, expanding boxes)

Historically… Extrinsic Size Units

Including % and other ‘relative’ units

Intrinsic Size Keywords

min-content |max-content | fit-content

See MDN Support
  • Have access to intrinsic sizing keywords
  • Min-content, max-content, and fit-content
Intrinsic Sizing [present, debug]

box-sizing property… Selects Box Edge for Sizing

  • We can also now select
  • The box-edge to size from
css…
* { box-sizing: border-box; }

/* ::before, ::after {
  box-sizing: border-box;
} */
  • The default is content-box
  • (useful for defining containers by the size of content)
  • But it’s common to change that default
  • With box-sizing: border-box on all elements
  • You can include before & after pseudos if you want
  • But I find they don’t usually need it (depends)
Static [Physical Dimensions]
  • Similar, historically physical
  • But that’s a real problem…
[demo link]
  • For a web that’s meant to be world wide
  • So now we have access to a wide range of…
  • Flow-relative (logical) properties
  • That change orientation…
[demo link]
  • And direction
  • Based on the current writing mode and language
Flow-relative [Logical Dimensions]
  • Not just the two dimensions
  • (Inline and block)…
Logical (flow-relative) Sides [present, debug]
  • But also the four sides
  • Top, right, bottom, and left are fixed in place
  • But block-start, block-end,
  • Inline-start, and inline-end
  • Orient us based on writing axis and direction

flow-relative Logical Properties

CSS logical properties and values on MDN
  • There are a few physical situations (eg shadows)
  • Mostly design is relative to flow
  • As always, CSS is expressive
  • Best to say what you mean
  • width -> inline-size
  • height -> block-size
  • top -> block-start
  • bottom -> block-end
  • left -> inline-start
  • right -> inline-end
e.g margin-right -> margin-inline-end
  • For English and other latin writing modes
  • We can start to replace our habits & old code
  • Reaching for the logical equivalents instead
  • A prop like margin-right, margin-inline-end
  • It will help if you ever provide page translations
  • But also as browsers auto-translate
Logical properties [present, debug]
  • Design interfaces that re-orient efficiently
  • Without making other changes in CSS
Block & Inline Shorthands [present, debug]
  • While some of the long-hands are a bit longer
  • We don’t only save time doing multi-lingual sites
  • We also get handy block and inline shorthands
  • e.g. margin-block, padding-inline, border-block
  • I use these all the time!
css…
input {
  margin-inline-end: 1em;
  margin-left: 0;
}
  • Note that they cascade separately
  • We don’t know until layout if they will conflict
  • Because the writing mode has to cascade as well
  • If they do conflict, we compare cascade weight again
  • Determine which should apply

Flexbox & Alignment

  • All of this sets us up
  • For flexbox and alignment

Flexbox… Content Sharing Space

  • Like ‘flow’ layout
  • Flexbox is a content-driven approach
  • Designed around intrinsic sizing
  • How do we take different-sized boxes
  • And distribute them in the available space?

Wraps In Lines

  • Like inline layout
  • Flex items flow along a primary axis
  • Forming one or more ‘flex lines’
  • With optional line-wrapping
  • At the edge of the container

Use the Firefox Flex Inspector

Flex Container display: flex

block flex or inline flex
css…
.default-values {
  flex-direction: row; /* column[-reverse] */
  flex-wrap: nowrap; /* wrap | wrap-reverse */
}
Flex Container
Flex-flow [present, debug]
  1. Creating a flex container
  2. Gaps are controlled by the container
  3. Establishing the ‘flow’ (axis and wrapping)
  4. Default flexing: auto basis, shrink, don’t grow

Default items… Shrink, Don’t Grow

Flex Items flex-grow: <number>

Distribution of Available Space

Flex Items flex-shrink: <number>

Distribution of Unavailable Space

Flex Items flex-basis: auto

The ideal starting width, before flexing

Four Flex Shorthand Values

initial | auto | none | <grow>

shorthand values designed to handle the majority of use-cases

Initial Shrink, If Necessary

Same as 0 1 auto

Auto Shrink or Grow

Same as 1 1 auto

None Don’t Flex

Same as 0 0 auto

<grow> Share Space Equally

Same as <grow> 1 0

Flex-flow [present, debug]
  1. Creating a flex container
  2. Gaps are controlled by the container
  3. Establishing the ‘flow’ (axis and wrapping)
  4. Default flexing: auto basis, shrink, don’t grow

Generally… I Avoid Flex-Basis

  • Generally I avoid explicit flex-basis
  • Not because it’s bad to use, go for it!
  • But if I don’t want intrinsic size
  • I probably want grid instead
  • (But there are exceptions!)

Box Alignment

distributing extra space

  • Box alignment
  • Proposed/implemented along side flexbox
  • Not just for flexbox, also works in grid
  • And (in beta) for block and absolute positioning!
  • Helps us distribute leftover space
  • Between and around items
  • (Or move items around in space, same idea)

Position Values

start | center | end

  • We can position boxes
  • On either axis
  • Using the position values
  • Start, center, or end

Distribution Values

stretch | space-between | space-around | space-evenly

  • Or distribute them with space between,
  • Space around, or ‘evenly spaced’
  • Which takes their size into account
  • We can also tell them to stretch
  • Filling what space is available

Two Overlapping Concepts

First… Placing Content
vs.
Placing Items

What boxes are we positioning?

  • First, placing content vs placing items
  • Easiest to understand in grid…
Alignment: placing content vs items [present, debug]
  • Content: the entire grid moves
  • Using flow-relative values
  • Both axis, or main then cross-axis
  • Items: grid stays put, items move in cells
  • Controlled by the container
  • Self: Overrides the default from ‘items’

Second… Align-* vs Justify-*

Which axis are we manipulating?

  • Second, we can target each axis individually
  • But people often forget, it’s not obvious
  • justify-* props apply to the ‘main’ axis
  • align-* props apply to the ‘cross’ axis
  • ‘Main’ is usually ‘inline’ axis
  • In flexbox, depends on flex-direction
  • For block layout…

Details differ Across Layout Contexts

See CSS Box Alignment
  • But the details are slightly different
  • Depending on the layout context

Grid supports… All Variations

Content, items, & self – on either axis

Block Box Alignment [present, debug]
  • Browsers now supporting align-content only
  • (Maybe most useful for centering?)
  • Treats the entire contents as a unit
  • And doesn’t support distribution, only placement
Absolute Position Box Alignment [present, debug]
  • With abspos: no container
  • Only supports ‘self’ properties
  • On either axis, or both
  • Must have an inset (or tlbr)
  • (Opts out of static position)
Flex-flow [present, debug]
  • With flexbox
  • Can’t justify an individual item,
  • Because it doesn’t have it’s own container
  • Nothing to justify it in relation to
  • Need to justify the whole line

Overflow Keywords

safe | unsafe

Flex-flow [present, debug]
  • Demo: safe and unsafe alignment
  • Center or end aligned

Baseline Values

baseline | first baseline | last baseline

Baseline Values [present, debug]

CSS Tricks Complete Guide to Flexbox

Aside… wpt.fyi

  • While researching this
  • No support info on MDN or CanIUse
  • Could look at release notes or browser blogs?
  • Web Platform Tests!
« resources
Bring this workshop to your company.
Slide Controls

View:

Navigate slides using the arrow-keys.