« resources

Company Workshop

Modes & Contexts

How CSS properties relate

workshops.oddbird.net/kc24/context/

Cmd/Ctr-K for Controls
Resilient CSS [present, debug]
  • We’ve talked about our code being suggestions
  • Which the browser can ignore
css…
/* a 'declaration' */
width: 500px;
  • But we also referred to declarations
  • As style hints

width: 500px;

  • Sometimes they carry
  • Seemingly simple concepts
  • width of a box

text-wrap: pretty;

  • More abstract concepts
  • wrapping text so it looks ‘pretty’
  • (whatever that means)

width: 500px;

Zoom, zoom, and zoom by Miriam
  • But even ‘simple’ declarations contain subtext
  • What do we mean by a pixel?
  • Should this box get smaller on a screen with higher resolution?
  • How should it respond to zooming in and out?
Diagram of an element box, with content, padding, border, and margin -- width and height labels are applied to the content only
The content-box model
  • Are we setting the width of the content box?
  • (so padding and border are added to our width)
Diagram of an element box, with content, padding, border, and margin -- width and height labels are applied to everything except the margin
The border-box model
  • Or the width of the entire box,
  • so padding and border are subtracted to get the content size?

inline-size: 500px;

  • Maybe it’s not the width we care about exactly,
  • that’s just the direction text flows.
  • Are we trying to set the length of a line of text?

inline-size: 45em;

  • Should it be based on the size of the font?

width: min-content;
width: max-content;

  • Or maybe the box should re-size based on the contents inside?
  • Their minimum or maximum size?

width: 100%;
width: 90vw;
width: 80cqi;

  • Or based on context
  • a parent element, viewport, or container

width: min(45em, 100%);

  • Or some combination
  • Like the minimum, of two values

Graphic design of unknown content with unknown collaborators, on an infinite and unknowable canvas, across operating systems, interfaces, languages, and writing modes

— me

  • If we’re really trying to do this
  • [Graphic design etc]

There are too many variables to consider. The point of CSS is to make it so you don’t have to worry about them all.

— Keith J Grant

Resilient, Declarative, Contextual
  • There will be too many variables for us to consider on our own
  • But the browser has all the context
  • This is the strength of a declarative language…

width: auto;

  • Where we describe the behavior we want to opt into
  • Rather than the steps to achieve that behavior
  • We don’t have to plan for all the outcomes, step by step
  • most useful tools in CSS
  • express somewhat abstract concepts
  • let the browser work out details

The fact we can control a paper page is really a limitation of that medium.

— John Allsopp, A Dao of Web Design

  • it’s powerful because we’re giving up control
  • the browser knows more than we do

It takes craft to set up the circumstances that are simple and yet contain the ambiguities and the incongruity of human experience.

— Anne Bogart

A Director Prepares
  • To quote a book on directing for the theater…
  • [quote]
  • That’s our job, as UX designers & engineers
  • To allow for that breadth of human experience
  • Across different web contexts

CSS is expressive Like Language

  • like theater, or language generally, CSS relies on subtext
  • We don’t just state the outcome (a box that is 500px wide)
  • But we provide hints about how we got to that result

Subtext… 16px != 1em

CSS Values & Units Level 4
  • Sometimes two words can have the same surface meaning
  • But they carry different implications
  • In CSS, units are great at this
  • (It’s why we have so many)
  • 1em sometimes gives the same result as 16px
  • But they have different meaning
  • So they will adapt differently to context

In CSS… flex != grid

  • Similar with layout methods
  • We can sometimes get the same result
  • using either flexbox or grid (for example)
  • but they move differently
  • Respond to context and content differently

Like poetry Say More with Less

  • So, like writing poetry
  • We want to be careful in our choice of words
  • To say more, without adding unnecessary constraints
  • Providing subtle hints will often take us farther
  • That a brute force approach

CSS properties Are Not Pure Functions

  • As a result of this declarative model,
  • CSS properties tend to be intertwined
  • Their behavior isn’t isolated,
  • (and can’t be isolated by using extreme conventions)

CSS is Modal

Mostly based on formatting contexts

Understanding Layout Algorithms by Josh Comeau
  • In fact, many CSS properties are modal
  • Some properties are used to set the current mode
  • And some properties only apply in specific modes
  • Or behave differently depending on the mode
New CSS Demo [present, debug]
  • Most obvious with display properties…

demo:

  • create span with text & outline
  • add width
  • add height
  • add display: block, then display: list-item
  • not just display of the element itself…
  • add body { display: flex; }
  • remove display: block etc
  • change width to be large
  • add float
  • remove body display value

display is a Shorthand

primarily inside and outside modes

  • So the display property is doing multiple things.
  • We usually set a single value,
  • but it acts like a shorthand
  • Setting the outer mode of the element,
  • (how it behaves in the parent context)
  • And the inner mode…

Inner display creates Formatting Context

  • Normal Flow (block/inline)
  • Multi-Column (block/inline)
  • Grid
  • Flex
  • Table
  • Which describe a formatting context for children
  • A way of ‘flowing’ elements together,
  • So that each element takes the space it needs,
  • And pushes the other elements aside, to avoid overlap
  • In CSS, we’re almost always in one of these modes,
  • unless we explicitly…

Pulling elements Out-Of-Flow

  • Absolute Positioning (including fixed)
  • Floats (only in ‘normal flow’)
  • Pull elements out of the flow
  • Which can be done element-by-element
  • Using ‘floats’ or ‘absolute’ positioning
  • Which are their own sort of layout modes
  • With their own rules
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)
  • This push and pull of context and content
  • is the fundamental tension of CSS
  • We have some amount of space available
  • And some amount of content to fit in that space

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

  • This is true at every level of the document
  • Which is 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
  • That sounds daunting,
  • But we interact with that canvas…
Earth seen through a window on the international space station
  • Through a finite viewport
  • Our ‘window’ for viewing a website
Two-Dimensional Viewport [Physical Dimensions]
  • The parent of the root element
  • We can’t style (directly)
  • Has a finite width/height
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)
  • Provides the ‘initial’ containing block
  • The outermost context
  • For our tree of boxes
  • Part of that context is…

Every document Has a Flow

  • The document flow
  • The way that documents are written
  • In English we start at the top left,
  • and move towards the bottom right
Text lines use inline axis [demo link]
  • With words that stack together into lines
  • We call the direction of text flow the ‘inline axis’
  • But that 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 of text
  • But the direction of flow is reversed
Blocks of text stack… [demo link]
  • As lines fragment, they stack together on the block axis
  • Forming block boxes
  • Again the axis and direction of block flow
  • Depends on the language and writing mode
  • For English, it’s a vertical axis, top to bottom
  • But in Korean, Chinese, and Japanese languages
  • Where the lines of text can flow vertically
  • The resulting blocks would stack horizontally (right to left)
[Physical Dimensions]
  • So in addition to our physical dimensions,
  • Width and height, which are fixed in place
  • We can talk about…
Flow-relative [Logical Dimensions]
  • The ‘flow-relative’ or ‘logical’ dimensions
  • Based on the flow of text in a given writing mode
  • English flows in lines from left to right
  • And stacks in blocks from top to bottom
  • (Horizontal, top to bottom)
  • These are not fixed, but change based on the language
Logical (flow-relative) Sides [present, debug]
  • That also gives us four logical 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
  • Most design is relative to flow
  • English sites put the logo top right
  • Because that’s where we start reading English documents
  • There are a few exceptions (eg shadows)
  • 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
  • We can start to replace our habits & old code
  • Reaching for the logical equivalents instead
  • Replacing properties like margin-right with 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 time if they will conflict
  • Because the writing mode has to cascade as well
  • If they do conflict, we compare cascade priority again
  • Determine which should apply

…A tree of elements… and text nodes

  • Inside of that flow,
  • We have this tree of elements and text nodes

Elements Generate Boxes

  • Every element generating it’s own 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
  • Each box has four 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…

Text nodes Have an Anonymous Box

  • Even text nodes inside of elements
  • Get anonymous boxes
  • Just means we can’t select or style them directly
  • Have to select the parent element instead

display property Box Generation Values

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

display: none Removes Box Tree

Content is also removed
  • Display-none will remove the box
  • (including everything inside)
  • So neither the box or the contents are rendered.

display: contents Removes Box

Content remains
  • Display-contents will remove the box
  • But leave the contents in place
  • This can be helpful in some situations,
  • But we have to be careful…

Historically… ⚠️ Severe A11y Issues

Contents-display support data
  • Can cause major accessibility issues in some browsers
  • Removing the semantics of the element
  • Or the elements inside, which is bad!
  • Much of that has been fixed in recent releases,
  • But not everyone is on the latest browsers, and…

Currently avoid… ⚠️ On Buttons & Tables

Contents-display support data
  • Most browsers still have issues on HTML buttons and tables
  • So never use display:contents on those elements
  • And be cautious on other semantic elements
  • (links, lists, etc)
  • Mostly use 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 display
  • Generates an additional ::marker box
  • Which we can move in or out of the principle box
  • Let’s see all this in practice…
Flow (boxes) [present, debug]
  1. Box tree of elements and text nodes
  2. 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 (inside the content-box)
  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

Default layout mode Normal Flow

  • The boxes that remain have to be laid out somehow
  • And the default layout mode is called normal flow
  • Designed to feel somewhat invisible and obvious
  • It’s just the way we write documents…
inline boxes [demo link]
  • Some boxes flow in line with the text
block boxes [demo link]
  • And some stack up, wrapping entire blocks

display property Outer Display Values

inline or block

  • Which gives us the outer display values
The original CSS proposal document with all styles removed so that it's an unreadable wall of text
  • As we saw earlier,
  • The initial display value is inline,
  • So all our boxes flow with the text by default
  • Until the browser comes along…
screenshot
[CHSS Proposal]
  • And defines some block boxes for us
  • With space between them
  • To make the document more readable

These are Distinct Layout Models

  • Even though these are both part of Normal Flow
  • They form somewhat distinct layout modes,
  • Each with different rules
  • Let’s take a look…
Flow (inline) [live code, present, debug]
  • Inline boxes flow with text nodes
  • Have an intrinsic size
  • Determined by the content inside
  • Boxes expand (and stack together) ‘in lines’
  • When a box reaches a container edge, it will fragment
  • Creating a new ‘line’
  • Can set line-height (initial normal from font metrics)
  • But explicit boxes sizes are ignored
  • Contribute border/padding/margins on the inline axis only
  • Always participate in inline layout
  • (add display block to get anonymous boxes)

participate In Inline Flow

  • Inline boxes participate in an inline flow
  • And only interact with other inline boxes
  • If we mix block and inline boxes together
  • we get a block flow with ‘anonymous boxes’ around text
Flow (block) [live code, present, debug]
  • Take their inline-size from context (extrinsic)
  • Always stretch by default
  • Take their block-size from content (intrinsic)
  • Blocks expand and stack flow on the block axis
  • Contribute padding/margins on both axis
  • Adjacent margins collapse
  • Can be explicitly sized (intrinsic or extrinsic)

Participate In Block Flow

  • Block boxes always participate in block layout,
  • And as we saw earlier
  • Will force a block layout when they show up,
  • even if that requires extra anonymous boxes around text

Inline boxes… Get inline-size
from Content

look down to children…
  • Inline boxes and text nodes get their inline size
  • From the text itself, the contents of the box
  • Explicit sizes are ignored

Block boxes… Get block-size
from Content

look down to children…
  • Take their block-size from 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)
  • This is the intrinsic size
  • To find it, look down the tree at child boxes
  • The content pushing out, taking up space

Primary box axis Sized By Contents

Cross axis Sized By Context

Inline boxes… Get block-size
from Line Height etc

  • Inline boxes get their block size from the line itself
  • It doesn’t really matter what we put in there,
  • the height of the box is the height of the line

Block boxes… Get inline-size
from Context

look up to parents…

  • By default, blocks…
  • Take their inline-size from context
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)
  • Extrinsic sizing, we look up the tree, at the parent box
  • There’s always a container pushing in, providing limits
  • Extrinsic constraints
  • And always content pushing out, taking up space
  • An intrinsic size determined by whatever’s in there

We can also Provide Extrinsic Sizes

  • But extrinsic sizes don’t only come from the browser
  • Any size that we set explicitly will be extrinsic
  • It doesn’t come from the natural size of the content,
  • But is imposed from the outside

All CSS 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)

Outer display Often Ignored

  • The outer display values are sometimes ignored
  • If we move an element into a grid
  • No longer inline or block, just a ‘grid item’
  • In a flex context, it becomes a ‘flex item’ (and so on)
  • An inline element in a block context can be ‘blockified’

Inner display Flex, Grid, Table-*, Flow

  • These are ‘inner’ display values
  • We set them on the parent, and they establish context for children
  • Different formatting contexts or layout modes
  • Such as flex, grid, table, or even ‘flow’
  • You’ve maybe never set that last one explicitly
  • Because keyword is newer, but…

block ➡️ block flow
inline ➡️ inline flow \

  • It’s the default when we only define an outer value
  • block or inline means block flow, and inline flow
  • Flow is the default, if we don’t specify another mode…

grid ➡️ block grid
flex ➡️ block flex
table ➡️ block table

  • Flex, or grid, or some form of table display
  • When we just set an inner value (like grid or flex)
  • Those come with a default block outer value
  • And so we usually only set a single value
  • Except in special cases…
Margin collapse & float overflow [present, debug]
  • In normal flow,
  • 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 into discrete blocks
  • Historically, solved floats with a ‘clearfix’
  • Or overflow: hidden;

Display: Flow-Root

“A mini layout in your layout”…

  • Now we can ask for this explicitly
  • Flow-root not just creating a new flow context
  • But isolating it from outside interactions
  • “a mini layout in your layout”

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
  • And some other ‘clearfix’ techniques
Understanding CSS Layout And The Block Formatting Context [present, debug]
  • Rachel Andrew has an excellent article
  • With various demos to show what a BFC does
  • Keeping floats contained
Understanding CSS Layout And The Block Formatting Context [present, debug]
  • Keeping external floats out
Understanding CSS Layout And The Block Formatting Context [present, debug]
  • The same with margins
  • Don’t interact or collapse across the boundary

Flow-Root boxes… Can have Explicit Size

  • While inline 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
Support data from CanIUse.com on the flow-root feature
[Can I Use]
  • Well supported since 2019

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

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)

Out-of-flow Block-ification

Relationship between display, position, and float
  • Let’s look a bit closer at elements pulled out of flow
  • With absolute positioning or floats
  • These are specialized modes, with complex interactions
  • Sometimes overriding the element’s outer display
  • And often overriding the parent context as well
  • There’s a chart in the CSS 2 spec
  • For how these properties interact

Display none Overrides Position or Floats

Floats only work In Normal Flow

Parent context can override

Position absolute…* Overrides Floats

*Position fixed Is Spicy-Absolute

  • The spec considers fixed and absolute position
  • To be variants of the same thing
  • Not different ‘layout modes’
  • Only different positioning anchors

Either way… Outer Display is Blockified

inline & inline-* ➡️ block & *

Out-of-flow elements…ShrinkWrap’ To Contents

clamp(min-content size, stretch-fit size, max-content size)

Out of Flow [present, debug]
  • abspos overrides float
  • both blockify the element
  • change the anchor
  • fit-content sizing

Box Overflow

overflow-x/-y | overflow-inline/-block

Default Visible

Acts like auto when single-axis

Protect the content!

Overflow Hidden

  • no scroll bar
  • clipped at padding-box edge
  • programmatic scrolling is allowed

Overflow Clip

  • no scroll bar
  • clipped at padding-box + overflow-clip-margin edge
  • programmatic scrolling not allowed
Polypane website hero area,
with a 3d browser window
popping out of the content area,
but clipped at the page edge
From Polypane

Can I use… Overflow Clip?

Overflow Scroll / Auto

(usually auto…)

Text-Overflow

clip | ellipsis

What to do with extra text

Ellipsis Not a Content St…

Overflow-Wrap

break-word | anywhere

Overflow-Wrap [present, debug]

Design For Change

  • All these tools help us express
  • The intent of a layout
  • The choices that we’re making
  • And what to prioritize
CSS is Rad [present, debug]
  • This meme perfectly captures what is actually awesome about CSS – and how we can go wrong by taking too much control without considering the consequences. So how can we lighten our grip here?

[demo] change to use intrinsic sizes

« resources
Bring this workshop to your company.
Slide Controls

View:

Navigate slides using the arrow-keys.