back to module

Smashing Workshops

Flex & Containers

Arrows navigate, cmd/ctrl-k for settings

display: flex Content Sharing Space

I mentioned that Grids are ‘block-like’ by default – with a layout layer defined on the parent. In many ways, Flexbox is more inline-like – not describing a layout, but allowing items to negotiate their own space.

Flexbox is inline-ish: present, debug

Items flow on a primary axis, that optionally wraps at the edge of the container.

  • container controls -flow (-direction & -wrap) & gap
  • Any explicit sizes have to be set on items
css
.container { display: flow-root; }
.item {
  float: left;
  width: 23.7288136%;
  margin-right: 1.6949153%;
}

If you were around for the old days of floated grid layouts, flexbox is a pretty direct 1-to-1 mental model –

css
.container {
  display: flex;
  gap: 1em;
}
.item { flex: 1 1 25%; }

but with more flexible boxes. Like floated layouts, any resulting structure on the page comes from each element being individually sized and positioned.

Flex (live): present, debug

We can revisit the same layout from yesterday, and get a similar result – but this time there’s no internal layout structure and no parental controls. Children have to define their own position in space.

Not intrinsic vs extrinsic, but… Structured vs Negotiated

The difference is not intrinsic and extrinsic sizing – both grid and flexbox can mix explicit and fluid sizes. The difference is grid has an internal layout structure that is separate from the size of individual elements.

avatar

There is no layout in a flexbox layout, but a layout grid lays out.

— Miriam Suzanne

With flexbox, there’s no structure, just items taking up space.

Flexbox alignment: present, debug

Because of that difference, flexbox has fewer alignment options than grid.

  • We can still align or justify the ‘content’
  • And we can align-items or align-self on the cross-axis
  • But there’s nothing for individual items to justify- against
  • There’s no cell, the item is creating its own space
css
.defaults {
  flex-basis: auto; /* starting width */
  flex-shrink: 1; /* distribution factor */
  flex-grow: 0; /* distribution factor */
}
Flex Items…

We get what we asked for: flexible boxes.

  • There are three underlying controls: basis, shrink, and grow
  • By default, items start from their auto content basis
  • And shrink equally (factor of 1) when we run out of space
  • But they don’t grow at all (factor of 0)
The Flex highlighter, Flex Container pane, and Flex Item pane in Firefox developer tools
Firefox Flexbox Inspector

We can see what’s happening most clearly in the Firefox flex inspector.

Other browsers provide an overlay on the parent, but only Firefox explains where each item gets its size.

Four flex Shorthand Values

initial | auto | none | 1 (any number)

shorthand values designed to handle the majority of use-cases

I find that complex flex settings often mean I should be using grid instead. That’s not universal, just a hint to reconsider. In fact, flexbox was designed with four special shorthands to cover most common cases. I especially rely on auto and 1.

initial Shrink, If Necessary

Same as 0 1 auto

  • Initial, the default
  • No growth, shrink as needed, auto basis
  • Great for distributing space around or between elements

auto Shrink or Grow

Same as 1 1 auto

  • Auto allows growth as well
  • Distributing extra space into elements

none Don’t Flex

Same as 0 0 auto

Instead of adding growth to the initial value, we can remove shrinking – so boxes don’t flex in either direction.

<number> Share Space Equally

Same as <number> 1 0

  • A single number (usually 1)
  • Fully flexible, growing from 0 basis
  • This removes the auto-content sizing,
  • So every element starts from the same place
CSS gradient-art decorations: present, debug

Note that values less than 1 are also useful! Items can stretch to take up half the remaining space, for example.

Random flex: present, debug
Flexbox is inline-ish: present, debug
  • initial
  • auto
  • none
  • <grow>

Generally… I Avoid Flex-Basis

Not a strict rule, just a hint!

  • Generally I avoid explicit flex-basis
  • Not because it’s bad to use, go for it!
  • But if I want more control over explicit sizes…

I probably Want Grid Instead

  • I probably want grid instead
  • Probably! Not always.
  • This is not a strict rule,
  • There’s nothing wrong with flex-basis

flexbox is For Sharing Space

grid is For Sharing Structure

flex & grid… Better Together

  • And they go great together
  • We can nest either inside the other
  • To get powerful results!
  • These were always meant to be a pair
Flex-basis layouts?: present, debug

Andy Bell makes a case for ‘automatic’ layouts using flex-basis as a sort of container-query. It’s very clever, but… if we know the sizes, I prefer clarity. I would only use this if we don’t know the sidebar size in advance.

Handling change… Container Queries

Otherwise, we might want a container query. So let’s look at them.

All of these tools are designed to handle change and uncertainty in various ways, responding to different conditions, like the size of the viewport…

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)
  • Or any other extrinsic constraints
  • But also the intrinsic sizes of things
  • This constant push and pull negotiation
A hand throwing multicolored water balloons in the air
credit: Sebastián León Prado
  • Web layout is like filling a balloon with water.
  • The contents have to change shape to fit inside,
  • But the container also changes shape,
  • and if we’re not careful…
CSS is Rad: present, debug
  • Things can go wrong
Responsive Web Design
2010 [Ethan Marcotte, Responsive Web Design]
  • When coining the term Responsive Web Design
  • Ethan mentions several tools for responsiveness…
  • Percentage-based image and layout sizes are central
  • But then media queries to handle bigger shifts
  • What we call breakpoints,
  • (At the point where something breaks, we apply a query)
  • This is the same year that media queries became available!
Media vs Container: live, present, debug
  • And that’s extremely handy!
  • But there’s a small issue
  • What if we have nested components?
  • It’s not the viewport size that matters,
  • But the size of the container
Github page for an Initial demo commit to the ahume/selector-queries repo on July 14, 2011 - showing html for a Responsive Containers Test Page
Selector Queries by Andy Hume, 2011
  • People pointed that out right away
  • And started asking for better options
  • selector queries, element queries, container queries
  • Whatever we call them,
  • we need some way to know about nested context
Statue of The Thinker
with a scribbled thought bubble asking:
do containers know stuff?
credit: Avery Evans
  • We need some way to query containers
  • And the browsers heard us asking
  • And responded together

NO.

— The Browsers

Not Ever.

— The Browsers

Stop Asking.

— The Browsers
Please don't feed the animals hand-painted sign, scribbled over to say: please don't query the containers

Container queries will never be possible on the web. They would cause infinite layout loops.

— The Browsers
A hand throwing multicolored water balloons in the air
credit: Sebastián León Prado
  • And the answer makes sense when you think about it.
  • How do you measure a water balloon?
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)

If we can query the size of the container, and you use that information to change the size of the content…

The intrinsic/extrinsic diagram with red circles and arrows and question-marks scribbled all over it

That would change the size of the container again, and we’re stuck in a loop! But then some folks pointed out…

Inline Flow: present, debug

We’re not dealing with fluid dynamics here. We know that inline elements use the contents for inline size –

Block Flow: present, debug

And block elements only rely on contents for the block axis. So web layouts generally get their width externally, and allow content to resize the height. Maybe we can measure one axis, and change the other?

Container Size Queries

Browser support for Container Size Queries
Media vs Container (Live Demo): present, debug
The thinker
with a red scribbled thought bubble:
how?!
  • So how do we make sure there’s no loops?

*Some Restrictions Apply

We can’t change Anything We Want to Query

Directly or indirectly

We can’t query Anything We Can Change

Directly or indirectly

We Need to Turn Off Intrinsic Sizing

  • We can’t rely on the fact
  • That we’re mostly measuring an extrinsic axis
  • We have to be clear about it
The intrinsic/extrinsic diagram
with the intrinsic content sizing
scribbled out
  • And turn off any ability
  • For an element to be resized by content

CSS Containment

contain: size | layout | style | paint;

Avoid internal impacts on external elements…
  • First we got the containment features
  • Which are useful on their own for handling extreme
  • performance optimizations
  • but…
CSS is Rad: present, debug
  • Maybe a bit too dangerous
  • For us to use in container queries

We can only Measure The Axis We Contain

Contain inline-size For Most Containers

Also need to Contain Layout* & Style

*This is being relaxed!
Understanding containment: present, debug
  • Containers should no longer apply layout containment!
  • Still create ‘formatting context’
  • Still contain counters

👍🏼 Inline-Only Containment

Ancestor Layout Loops with Single-Axis Containment

👎🏼 Block-Only Containment

Contain size For Scroll Containers

Containing Size: present, debug

Since size… Containment is Invasive

We create Explicit Containers

css
container-type: inline-size;
contain: inline-size layout style;

Recommended… Name Your Containers

css
main {
  container: layout main / inline-size;
}
container-name [/ container-type]?
css
@container layout (min-width: 40em) {
  .conditional { /* … */ }
}

@container main (min-width: 40em) {
  .conditional { /* … */ }
}

Finding Containers

  1. For each matched element…
  2. Find the nearest ancestor that has…
    • Any required container name
    • Any required container types

Containers Can’t Self-Query

(That would introduce loops!)

Always Measuring an Ancestor

(can’t change what you measure!)

Enter the 36 Chambers: present, debug

Always Measuring an Element

Bonus! Container Queries Measure Actual Styles

Computed values on the container element
Size queries, relative/var units: present, debug

Grid Tracks & Flex Sizing?

No element to measure…

Three mud turtles
on a small log
surrounded by water.
Flexbox cards, with Container Queries: present, debug
Custom Element w/ Container Query: present, debug

For legacy reasons… No Default Containers

(we shouldn’t rely on body style propagation)
css
body > :is(header, main, nav, footer) {
  container: layout / inline-size;
}

also… Container Query Units

cqw | cqh | cqi | cqb | cqmin | cqmax

Default unit container The Small Viewport

On an example phone,
the large viewport fills the full screen
with all browser chrome hidden -
the small viewport fills the remaining space
when top and bottom browser chrome are visible
The Large, Small, and Dynamic Viewports by Bramus Van Damme
cat in a box, thinking
'OMG I have so many questions for this damn box'
Photo by Sahand Babali on Unsplash
Name-only queries: present, debug

Name-Only Container Queries

Browser support for Name-Only Container Queries
Web component style query parameters: present, debug

Container Style Queries

Browser support for Container Style Queries

No Containment Needed

Default… Queries Direct Parent

Style Queries… Only Custom Properties*

* for now **
** but maybe forever?

List outdent with range style queries: present, debug

Range Syntax in Style Queries

Browser support for Range Syntax in Style Queries
Style queries and computed values: present, debug

State Queries

CSSWG issue for state queries
css
@container scroll-state(stuck) { … }
@container scroll-state(snapped) { … }
@container scroll-state(scrollable) { … }
@container scroll-state(scrolled) { … }
Scroll-state: present, debug

Container Scroll-State Queries

Browser support for Container Scroll-State Queries
Using Container Scroll-State Queries
MDN, Using Container Scroll-State Queries
cat in a box, thinking
'OMG I have so many questions for this damn box'
Photo by Sahand Babali on Unsplash
  • We’ll see what else comes out of this!
  • I imagine there are a lot more questions worth asking
Please do query the containers now actually, thanks!
  • But for now,
  • Please do query the containers actually, thanks!

Next module… Poetic CSS

« back to resources
SlideDeck Controls

View

Keyboard shortcuts
cmd/ctrl-k:
Toggle this control dialog
cmd/ctrl-shift-enter:
presentation (from first slide)
cmd/ctrl-enter:
presentation (from active slide)
alt-enter:
in speaker view (following active slide)

Color Settings