Every foundations, styles and components page of m3.material.io (238, from the sitemap) extracted into docs/reference/m3, five audit reports with 142 findings in docs/audits/m3-alignment, and the 2.0.0 plan in docs/plans/material-3-alignment.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
319 lines
22 KiB
Markdown
319 lines
22 KiB
Markdown
# Material Design 3 — Styles Supplement (Spacing; Color additions; Motion transition patterns)
|
||
|
||
Extraction from sitemap pages `reference-styles.md` did not cover (fetched directly, not via in-site
|
||
navigation). Same structure as the reference. Only material **not** already in `reference-styles.md` is
|
||
included; where a fetched page turned out to be a duplicate of an already-covered page, that is noted
|
||
instead of repeating it.
|
||
|
||
**Duplicate pages found (no new content beyond what's already in the reference):**
|
||
- `styles/color/system/overview` — byte-identical to `styles/color/system` (already in the reference's
|
||
Color section / Source URLs), *except* it also carries a Resources table not previously captured — see
|
||
Color § Values below.
|
||
- `styles/color/advanced/overview` — byte-identical to `styles/color/advanced` (already in the reference's
|
||
Color § Source URLs; its linked sub-pages apply-colors/define-new-colors/adjust-existing-colors are
|
||
already the basis of the reference's "Advanced customization best practices" rules).
|
||
- `styles/color/dynamic/choosing-a-source` — byte-identical to `styles/color/dynamic` (already in the
|
||
reference's Color § Source URLs), *except* it's the canonical location for the source-selection
|
||
decision criteria — see Color § Dynamic sources below (the reference didn't extract these criteria).
|
||
- `styles/motion/easing-and-duration/applying-easing-and-duration` — its "Suggested easing and duration
|
||
pairs" table, "Choosing an easing set", "Choosing an easing type" (by transition direction), and
|
||
"Choosing a duration" (by size / enter vs. exit) sections are already reproduced verbatim in the
|
||
reference's Motion § Rules and § Values. The only new fact is an M2-vs-M3 style comparison — see
|
||
Motion § Principles below.
|
||
|
||
---
|
||
|
||
## Spacing
|
||
|
||
Absent from `reference-styles.md` entirely — no Spacing section existed. This is a full addition.
|
||
|
||
### Principles
|
||
|
||
- Spacing is applied to the margins, padding, and gaps of a component, UI element, or layout.
|
||
- Spacing adapts to different values based on context, like mobile vs. desktop, or density settings.
|
||
- The spacing system is measured on an **8dp scale**, where **space100 = 8dp**.
|
||
- Spacing is applied to the flow of elements (horizontal, vertical) or in relation to elements (leading,
|
||
trailing, top, bottom, gap).
|
||
- Unlike the color system (which adjusts light/dark theme logic across all components at once), spacing
|
||
logic is tailored and built within each component individually — there's no single global spacing
|
||
transform.
|
||
- Components have padding/margin/gap tokens that map to system spacing tokens, which resolve to final dp
|
||
values (component token → system token → value).
|
||
|
||
### Rules (Google's wording)
|
||
|
||
- Spacing has three categories: **padding** (space inside an element), **gap** (space between elements in
|
||
a grid or container), and **margin** (space outside an element). Position can be vertical, top, bottom,
|
||
horizontal, leading, or trailing. **Leading**/**trailing** swap sides in RTL languages.
|
||
- **Do** define padding and gaps on the parent container to organize all elements inside.
|
||
- **Don't** define margins on child elements — they usually aren't uniform and require more tokens.
|
||
- **Use padding & gaps before using margins**: Material rarely uses margins in components; padding/gaps
|
||
apply spacing more uniformly. Only use margins for spacing beyond the parent container's padding, or in
|
||
layouts.
|
||
- Use a horizontal/vertical gap for simple components where gaps are always the same size; complex
|
||
components with many different gaps should name them by the elements on each side (e.g. "icon-label
|
||
gap") rather than a single generic gap token.
|
||
- When text is scaled up to 200%, the same spacing should be preserved by default (spacing does not scale
|
||
with text).
|
||
- What to use, in priority order:
|
||
1. **Pre-tokenized components** — some Material components map to spacing system tokens out of the box
|
||
(work is ongoing to hook up all components; this mapping can be customized for form factor/density).
|
||
2. **System tokens** — apply these to custom components/layouts, replacing hardcoded values.
|
||
3. If the right system token doesn't exist, **customize the system** (see below) and add your own.
|
||
- Customizing the system (three approaches, by scope):
|
||
- **Customize Material's existing component spacing** — remap a component attribute to a different
|
||
system token product-wide (e.g. change "button top padding" from **space125** to **space200** for a
|
||
taller default button).
|
||
- **Add custom system spacing & patterns** — when you need units beyond what Material provides, or have
|
||
a recurring adaptive pattern. Follow the multiplier convention for new tokens (e.g. **space225 = 18dp**
|
||
= 8dp × 2.25). Product-specific recurring patterns can get their own pattern token (e.g. if cards and
|
||
sheets always adapt horizontal content padding the same way, create a **surface-content padding
|
||
horizontal** token for that pattern).
|
||
- **Add adaptive layout & density** — map the same component to different system tokens per device type
|
||
(mobile vs. desktop), and/or adapt vertical padding to different values per density setting, while
|
||
keeping the same core component.
|
||
- **Note:** system spacing tokens are currently only used on **Jetpack Compose** (see Availability below)
|
||
— this is a stronger platform restriction than color/elevation/shape, which have broader (if uneven)
|
||
support.
|
||
|
||
### Values
|
||
|
||
#### Availability
|
||
|
||
| Type | Resource | Status |
|
||
| --- | --- | --- |
|
||
| Implementation | Android Views (MDC-Android) | Unavailable |
|
||
| Implementation | Jetpack Compose | Available |
|
||
| Implementation | Web | Unavailable |
|
||
|
||
#### Spacing scale
|
||
|
||
The site does not render the token→dp table as text (it's an image diagram); the following is
|
||
reconstructed from the images' alt-text and from dp values cited inline elsewhere on the page, and should
|
||
be treated as inferred, not a verbatim site table:
|
||
|
||
| Token | Multiplier | Value |
|
||
| --- | --- | --- |
|
||
| space25 | 0.25× | 2dp |
|
||
| space50 | 0.5× | 4dp |
|
||
| space75 | 0.75× | 6dp |
|
||
| **space100** | **1×** | **8dp (base unit, `md.sys.measurement.space100`)** |
|
||
| space125 | 1.25× | 10dp |
|
||
| space200 | 2× | 16dp |
|
||
| space300 | 3× | 24dp |
|
||
| space400 | 4× | 32dp |
|
||
| space500 | 5× | 40dp |
|
||
| space600 | 6× | 48dp |
|
||
| space700 | 7× | 56dp |
|
||
| space800 | 8× | 64dp |
|
||
| space900 | 9× | 72dp |
|
||
|
||
Basis for this reconstruction: the overview page's scale diagram alt-text reads "a spacing scale shows 2,
|
||
4, 6, and 8 at the bottom range and 48, 56, 64, and 72 at the top of the range"; the tokens page states the
|
||
main range "covers 0x to 9x" of the 8dp base unit and separately defines nested sub-1x units at "0.25x,
|
||
0.5x, 0.75x, 1.25x"; the overview page separately lists the same nested dp values ("2dp, 4dp, 6dp, and
|
||
10dp"). Values beyond space900 (e.g. the 18dp/space225 example) are explicitly presented as **custom**,
|
||
not part of the default set. Material only defines the nested/nonstandard units it actively uses — the
|
||
scale is not a complete arithmetic progression at every step.
|
||
|
||
#### Component spacing — naming convention
|
||
|
||
| | Going forward | Legacy |
|
||
| --- | --- | --- |
|
||
| Prefix | `padding`, `margin`, `gap` | `space` |
|
||
| Positional modifiers | horizontal, vertical, leading, trailing, top, bottom | leading-space, trailing-space, top-space, bottom-space, between-space |
|
||
| Example | "Medium button: leading padding" | "Medium button: leading space" |
|
||
|
||
#### Parts of spacing — example (Search)
|
||
|
||
The search container: 8dp vertical padding, 8dp horizontal gaps, 24dp horizontal margins by default
|
||
(narrows to 12dp when focused, while padding/gaps stay the same). The 24dp default margin exists
|
||
specifically "to ensure accurate placement from the screen edge."
|
||
|
||
#### Spacing concepts diagrammed on the site (numbered image captions — anatomy, not values)
|
||
|
||
- Component layout: (1) vertical padding top & bottom, (2) vertical gap, (3) horizontal padding leading &
|
||
trailing, (4) horizontal gap.
|
||
- Page layout: (1) margin, (2) top padding, (3) horizontal padding leading & trailing, (4) spacer/gap,
|
||
(5) vertical gap. Layouts additionally use **panes** (layout containers, which can be fixed, flexible,
|
||
floating, or semi-permanent) and **spacers** (space between two panes; contains a drag handle if the
|
||
panes are resizable).
|
||
|
||
### M3 vs M3 Expressive differences
|
||
|
||
No Expressive-specific spacing changes are called out on these pages (unlike shape/motion/typography,
|
||
spacing carries no "M3 Expressive" labelled update section). The system is presented as a single,
|
||
version-agnostic linear scale.
|
||
|
||
### Accessibility
|
||
|
||
- Spacing must be preserved (not scaled) when text is scaled up to 200%, so layouts stay stable and
|
||
legible as text grows — spacing is a support mechanism for text-resizing accessibility, not something
|
||
that competes with it.
|
||
|
||
### Source URLs
|
||
|
||
- https://m3.material.io/styles/spacing/overview
|
||
- https://m3.material.io/styles/spacing/applying-spacing
|
||
- https://m3.material.io/styles/spacing/tokens
|
||
|
||
---
|
||
|
||
## Color — additions
|
||
|
||
### Static: Custom brand color scheme
|
||
|
||
Not previously fetched. Supplements the reference's Color section (which covers baseline/static generally
|
||
but not the brand-specific workflow).
|
||
|
||
**Principles**
|
||
- A **brand-based static scheme** is hand-picked by the product team to align with the product's brand
|
||
color(s), as opposed to the **baseline** static scheme (Material's own default) or a **dynamic** scheme.
|
||
It requires greater ongoing investment since the team creates and maintains it entirely.
|
||
- End-users see: an accessible UI with static colors, and "a product that looks like its brand."
|
||
|
||
**Rules (Google's wording)**
|
||
- Brand schemes are still generated through the same tonal-palette machinery as dynamic color: you can
|
||
set a **custom source color independently for each of the 6 palette groups** — Primary, Secondary,
|
||
Tertiary, Error, Neutral, and Neutral Variant — not just Primary. Setting only Primary and leaving the
|
||
rest defaulted is also valid ("use the scheme as-is").
|
||
- Workflow (Material Theme Builder Figma plugin): add a new theme, name it (the name becomes the color
|
||
role prefix in Figma), set a custom Hex source color for Primary (and optionally Secondary/Tertiary/
|
||
Error/Neutral/Neutral Variant) → generates a full custom color scheme with the same role set as baseline.
|
||
- Enabling "Generate State Layers" in the plugin settings when creating the theme is called out as
|
||
necessary groundwork for interaction-state design (cross-references state layers).
|
||
- Point of escalation: "want to further adjust your brand color scheme?" and "need to make adjustments?"
|
||
both route to **Advanced customizations** (apply/define/adjust colors) — i.e. custom-brand is the
|
||
starting point, advanced customization is the refinement path.
|
||
- Develop: export the branded scheme from Material Theme Builder for Jetpack Compose, Android Views,
|
||
Flutter, Web, or as a JSON file.
|
||
|
||
**Source URLs**
|
||
- https://m3.material.io/styles/color/static/custom-brand
|
||
|
||
### Dynamic: choosing and using a source
|
||
|
||
Two new sub-pages (content-based-source, user-generated-source) plus decision criteria from
|
||
choosing-a-source that the reference's Color section states only as a single pipeline description, not as
|
||
selection criteria.
|
||
|
||
**Principles**
|
||
- Both user-generated and content-based color go through the same pipeline: the image is digitally
|
||
analyzed through **quantization**, a single color is selected as the source color, and tones are chosen
|
||
and assigned to each color role (this is the concrete mechanism behind the "dynamic color pipeline"
|
||
already summarized in the reference).
|
||
- **User-generated color**: sourced from the user's wallpaper.
|
||
- **Content-based color**: sourced from in-app content — an album thumbnail, a logo, a video preview.
|
||
|
||
**Rules (Google's wording) — decision criteria (not previously captured)**
|
||
|
||
| Source type | Choose it if… |
|
||
| --- | --- |
|
||
| User-generated | Users would benefit from a personalized experience that's well-tested; you want to showcase the latest Material features |
|
||
| Content-based | Content is front-and-center in the product; the team can do some advanced customization; it supports usability of content-centric features like media players; best applied to contained screen elements adjacent to the source image (the source image itself need not stay visible) |
|
||
| Multiple sources | Product requirements meet more than one of the above criteria and the team doesn't mind extra customization work; get started with user-generated color first, then customize |
|
||
|
||
- Example of multiple sources coexisting: a photo app derives content-based color (green) for edit buttons
|
||
from the in-app photo, while wallpaper-derived user-generated color (red) drives share buttons elsewhere
|
||
in the same screen.
|
||
- Content-based color guidance: apply it where it enhances brand identity and personalization (e.g. a
|
||
music app deriving color from album artwork; a news app differentiating publications by their content
|
||
color).
|
||
- QA/testing step for user-generated color (Figma workflow): use the Material Theme Builder's "Dynamic"
|
||
mode, add a real image or use the Shuffle icon for a random source color, swap it onto frames, and
|
||
**repeat across a range of colors** to get a sense of how the product will appear across different
|
||
users' devices/wallpapers — i.e. dynamic-color design review should be done across many source colors,
|
||
not just one or two.
|
||
- Android implementation reference specifically for content-based color: MDC-Android's
|
||
"Content-based dynamic color" doc (separate from the general dynamic-color doc already cited).
|
||
|
||
**Source URLs**
|
||
- https://m3.material.io/styles/color/dynamic/choosing-a-source
|
||
- https://m3.material.io/styles/color/dynamic/content-based-source
|
||
- https://m3.material.io/styles/color/dynamic/user-generated-source
|
||
|
||
---
|
||
|
||
## Motion — Transitions (supplement)
|
||
|
||
The reference's Motion section already reproduces the easing/duration Rules and Values from
|
||
`applying-easing-and-duration` verbatim, and names the six transition patterns in one summary line without
|
||
detail. This section supplies the missing detail: what each pattern is for, what it's commonly used with,
|
||
platform (Android/iOS) differences, and the accessibility/consistency criteria for transitions overall —
|
||
which also fills the gap the reference explicitly flagged ("No general reduced-motion policy was found
|
||
stated on `styles/motion` itself").
|
||
|
||
**Naming note:** the current M3 site does **not** use the older M2 terms "shared axis / fade through /
|
||
fade." The current (2026) taxonomy is: **Container transform**, **Forward and backward** (≈ old shared
|
||
axis), **Lateral**, **Top level** (≈ old fade through), **Enter and exit** (subsumes old "fade" cases), and
|
||
**Skeleton loaders** (new, not an M2 concept). Anyone looking for "shared axis"/"fade through"/"fade" by
|
||
name should map to this table.
|
||
|
||
### Principles — what makes a good transition
|
||
|
||
- **Follows accessibility settings**: when a platform's reduced-motion setting is on, transitions should
|
||
use subtle fades instead of intense sliding/scaling, and disable decorative effects like parallax or
|
||
shape morphing. *(This is the missing general reduced-motion policy for `styles/motion` — previously
|
||
only found at the component level, e.g. carousel/menus.)*
|
||
- **Consistent**: applying the same transition type consistently for the same kind of navigation makes
|
||
apps feel cohesive and predictable (e.g. multiple Android apps sharing one forward/backward transition).
|
||
- **Stable layouts**: use skeleton loaders (subtle pulsing) so content doesn't shift position or pop in
|
||
abruptly as it loads.
|
||
- **No jarring jump cuts**: avoid instant, uncued transitions by default — they're disorienting. Exception:
|
||
a jump cut may be preferred when pure efficiency is the top priority (e.g. opening a menu in a
|
||
productivity app).
|
||
- **Coherent spatial model**: transitions should help users understand an app's physical/spatial layout
|
||
(e.g. keep a consistent axis when moving between collapsed/expanded carousel views; don't flip between
|
||
horizontal and vertical layouts).
|
||
- **Unified direction**: elements are grouped and move along one primary axis rather than independently;
|
||
only genuinely persistent elements (e.g. a hero image) should remain visible throughout — animating many
|
||
persistent elements independently is distracting.
|
||
- **Clean fades**: fully fade out old content before fading in new content; avoid overlapping
|
||
partially-transparent frames. If a cross-fade is unavoidable, keep it quick and hide it during the
|
||
fastest part of the transition (e.g. a dialog entering mid-screen should not slowly fade on top of
|
||
content — use a short fade to hide the overlap).
|
||
- **Simple style**: transitions are frequent and utility-driven, not a showcase for stylized motion — avoid
|
||
overt effects like bouncy springs on common transitions.
|
||
|
||
### Rules — per-pattern guidance (Google's wording)
|
||
|
||
| Pattern | Use for | Commonly used with | Do / Don't / Caution |
|
||
| --- | --- | --- | --- |
|
||
| **Container transform** | Seamlessly transforming an element to show more detail (e.g. a card expanding into a details page); hero moments that should be expressive; shallow hierarchies (expand for detail, then collapse); creating a seamless connection between elements. Most dramatic/expressive pattern — reserve for the right context. | Cards, lists, image galleries, search boxes, sheets, FABs, chips | **Do** use it for hero moments instead of a forward/backward transition. **Don't** use it in apps with deep hierarchies (motion becomes excessive) or in utility-focused navigation (style mismatch). |
|
||
| **Forward and backward** | Navigating between screens at consecutive hierarchy levels (e.g. inbox → message thread) | Lists, cards, buttons, links | **Do** use platform defaults — easy to implement, stays current with platform updates. Android fades content as screens slide (reduces motion vs. a full-width slide); iOS uses parallax (background slides slower than foreground). **Caution**: container transform requires custom implementation and can feel excessive if overused for this role. |
|
||
| **Lateral** | Navigating between peer content at the same hierarchy level (e.g. swiping tabs in a content library) | Tabs, carousels, image galleries | Elements are grouped and slide in unison with **no fade or parallax**, creating a strong peer relationship and hinting at swipe-ability. **Caution**: fading content while it slides weakens the peer/swipe cue and can be confused with forward/backward. **Don't** use for hierarchical navigation — full-width sliding is excessive and wrongly implies a peer (non-hierarchical) relationship. |
|
||
| **Top level** | Navigating between top-level destinations (e.g. tapping a nav bar/rail/drawer item) | Navigation bar, navigation rail, navigation drawer | Exiting screen quickly fades out, then the entering screen fades in — intentionally **no** grouping or persistent elements, since top-level destinations aren't necessarily related. **Don't** use a lateral transition here — it wrongly implies you can swipe between top-level destinations, conflicting with carousel/list swipe gestures. |
|
||
| **Enter and exit — within screen bounds** | Introducing/removing a component in the context of the main UI (modal, e.g. a dialog; or non-modal, e.g. a bottom sheet coexisting with content) | FABs, dialogs, menus, snackbars, time pickers, tooltips | Android: expand/collapse along x or y axis only (scale and z-axis motion are avoided — they'd imply an elevation change, which conflicts with M3's reduced-elevation model). iOS: uniform scale to enter, fade to exit. Enter direction is informed by on-screen location, expanding away from the device edge (e.g. a top menu expands downward; a bottom snackbar expands upward). **Don't** use this pattern for navigating hierarchical screens — full-height sliding is excessive and creates an unclear screen-to-screen relationship. |
|
||
| **Enter and exit — beyond screen bounds** | Components that slide fully on/off screen | App bars, banners, navigation bar, navigation rail, navigation drawer, sheets | Android: expand/collapse along x or y axis while sliding on/off (adds shape emphasis). iOS: slides on/off without changing shape. Coplanar side sheets shrink the available content area rather than overlaying it. Can be scroll-driven (e.g. a top app bar or nav bar sliding off/on during scroll, to reclaim screen space). Entry/exit location establishes spatial memory: notifications enter from the top (matches the pull-down drawer), a nav drawer enters from the left (matches its off-screen position), a bottom sheet/keyboard enters from the bottom (easiest to reach). |
|
||
| **Skeleton loaders** | Transitioning from a temporary loading state to the fully loaded UI | Used in combination with other transition patterns | Subtle pulsing animation indicates indeterminate progress, animating from top-left to bottom-right. Once content loads, it quickly fades in **on top of** the skeleton loader (not instantly popping in). |
|
||
|
||
### Values
|
||
|
||
Durations and easing for these patterns are governed by the already-referenced tables (Suggested
|
||
easing/duration pairs; legacy duration tokens) — no separate duration table is given per pattern on these
|
||
pages. The pattern choice itself is the "value" documented here; see the Rules table above for the
|
||
authoritative per-pattern mapping (this *is* the durations/patterns cross-reference the task asked for —
|
||
the site does not tie a specific numeric duration to "container transform" etc. beyond the general
|
||
begin/end-on-screen vs. enter vs. exit rules already in the reference).
|
||
|
||
### M2 vs M3 easing note (from `applying-easing-and-duration`; not an M3-vs-Expressive distinction)
|
||
|
||
- Compared to M2's more utilitarian easing style, **M3 easing is more expressive**: transitions have
|
||
"snappy take-offs and very soft landings."
|
||
- **M3 durations are slightly longer than M2's**, deliberately, to give transitions time to come to a
|
||
gentle rest without feeling abrupt.
|
||
|
||
### Accessibility requirements
|
||
|
||
- General reduced-motion policy for transitions (see Principles above): substitute subtle fades for
|
||
intense sliding/scaling, and disable decorative effects (parallax, shape morphing) when a platform's
|
||
reduced-motion setting is on. This generalizes — and predates in priority — the component-level
|
||
reduced-motion notes already in the reference (carousel, menus).
|
||
|
||
### Source URLs
|
||
|
||
- https://m3.material.io/styles/motion/transitions/applying-transitions
|
||
- https://m3.material.io/styles/motion/transitions/transition-patterns
|
||
- https://m3.material.io/styles/motion/easing-and-duration/applying-easing-and-duration (mostly duplicate
|
||
of already-referenced content; see M2-vs-M3 note above for the one new fact)
|