Material Design
Google's design language that combines flat design principles with subtle depth through shadows, motion, and the metaphor of physical materials.
Core Principles
1. Material as Metaphor
Inspired by paper and ink. Surfaces and shadows provide visual meaning based on physical world rules.
2. Bold, Graphic, Intentional
Uses print design principles: typography, grids, space, scale, color, and imagery.
3. Motion Provides Meaning
Motion respects and reinforces the user as the prime mover. Transitions are quick, clear, and cohesive.
Key Concepts
Elevation and Shadows
Material Design uses elevation (z-axis depth) to create hierarchy:
/* Material elevation levels */
.elevation-0 { box-shadow: none; }
.elevation-1 {
box-shadow: 0 1px 3px rgba(0,0,0,0.12),
0 1px 2px rgba(0,0,0,0.24);
}
.elevation-2 {
box-shadow: 0 3px 6px rgba(0,0,0,0.15),
0 2px 4px rgba(0,0,0,0.12);
}
.elevation-3 {
box-shadow: 0 10px 20px rgba(0,0,0,0.15),
0 3px 6px rgba(0,0,0,0.10);
}
.elevation-4 {
box-shadow: 0 15px 25px rgba(0,0,0,0.15),
0 5px 10px rgba(0,0,0,0.05);
}
.elevation-5 {
box-shadow: 0 20px 40px rgba(0,0,0,0.2);
}
Elevation Usage
| Level | Use Case |
|---|---|
| 0 | Static content, backgrounds |
| 1 | Cards at rest |
| 2 | Raised buttons, cards on hover |
| 3 | FAB (Floating Action Button) at rest |
| 4 | FAB on hover, app bars |
| 5 | Dialogs, navigation drawer |
Material Surfaces
<div class="material-surface">
<h2>Card Title</h2>
<p>Content goes here...</p>
</div>
.material-surface {
background: white;
border-radius: 4px;
padding: 16px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1),
0 2px 4px rgba(0,0,0,0.06);
transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.material-surface:hover {
box-shadow: 0 4px 8px rgba(0,0,0,0.15),
0 2px 4px rgba(0,0,0,0.12);
}
Color System
Primary, Secondary, Surface Colors
:root {
/* Primary color - main brand color */
--primary: #6200ee;
--primary-light: #9d46ff;
--primary-dark: #0a00b6;
--on-primary: #ffffff;
/* Secondary color - accent */
--secondary: #03dac6;
--secondary-light: #66fff9;
--secondary-dark: #00a896;
--on-secondary: #000000;
/* Surface colors */
--surface: #ffffff;
--on-surface: #000000;
/* Background */
--background: #f5f5f5;
--on-background: #000000;
/* Error */
--error: #b00020;
--on-error: #ffffff;
}
Color Usage
.primary-action {
background-color: var(--primary);
color: var(--on-primary);
}
.secondary-action {
background-color: var(--secondary);
color: var(--on-secondary);
}
.surface-card {
background-color: var(--surface);
color: var(--on-surface);
}
Typography
Material Design uses the Roboto font family.
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');
body {
font-family: 'Roboto', sans-serif;
}
/* Material type scale */
.headline-1 { font-size: 96px; font-weight: 300; line-height: 112px; letter-spacing: -1.5px; }
.headline-2 { font-size: 60px; font-weight: 300; line-height: 72px; letter-spacing: -0.5px; }
.headline-3 { font-size: 48px; font-weight: 400; line-height: 56px; }
.headline-4 { font-size: 34px; font-weight: 400; line-height: 42px; }
.headline-5 { font-size: 24px; font-weight: 400; line-height: 32px; }
.headline-6 { font-size: 20px; font-weight: 500; line-height: 28px; }
.subtitle-1 { font-size: 16px; font-weight: 400; line-height: 24px; letter-spacing: 0.15px; }
.subtitle-2 { font-size: 14px; font-weight: 500; line-height: 20px; letter-spacing: 0.1px; }
.body-1 { font-size: 16px; font-weight: 400; line-height: 24px; letter-spacing: 0.5px; }
.body-2 { font-size: 14px; font-weight: 400; line-height: 20px; letter-spacing: 0.25px; }
.button-text { font-size: 14px; font-weight: 500; line-height: 16px; letter-spacing: 1.25px; text-transform: uppercase; }
.caption { font-size: 12px; font-weight: 400; line-height: 16px; letter-spacing: 0.4px; }
.overline { font-size: 10px; font-weight: 400; line-height: 16px; letter-spacing: 1.5px; text-transform: uppercase; }
Components
Material Button
<!-- Contained button (high emphasis) -->
<button class="mdc-button mdc-button--raised">
<span class="mdc-button__label">Button</span>
</button>
<!-- Outlined button (medium emphasis) -->
<button class="mdc-button mdc-button--outlined">
<span class="mdc-button__label">Button</span>
</button>
<!-- Text button (low emphasis) -->
<button class="mdc-button">
<span class="mdc-button__label">Button</span>
</button>
.mdc-button {
padding: 0 16px;
height: 36px;
border-radius: 4px;
font-size: 14px;
font-weight: 500;
letter-spacing: 1.25px;
text-transform: uppercase;
border: none;
background: transparent;
color: var(--primary);
cursor: pointer;
transition: background 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.mdc-button--raised {
background: var(--primary);
color: var(--on-primary);
box-shadow: 0 2px 4px rgba(0,0,0,0.14),
0 3px 4px rgba(0,0,0,0.12),
0 1px 5px rgba(0,0,0,0.2);
}
.mdc-button--raised:hover {
box-shadow: 0 4px 8px rgba(0,0,0,0.16),
0 6px 8px rgba(0,0,0,0.14),
0 2px 10px rgba(0,0,0,0.22);
}
.mdc-button--outlined {
border: 1px solid rgba(0, 0, 0, 0.12);
}
/* Ripple effect */
.mdc-button::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.mdc-button:active::before {
width: 300px;
height: 300px;
}
Material Card
<div class="mdc-card">
<div class="mdc-card__media">
<img src="image.jpg" alt="Card image">
</div>
<div class="mdc-card__content">
<h2 class="mdc-card__title">Card Title</h2>
<p class="mdc-card__subtitle">Subtitle text</p>
<p class="mdc-card__description">
Description text that provides more information about the card content.
</p>
</div>
<div class="mdc-card__actions">
<button class="mdc-button">Action 1</button>
<button class="mdc-button">Action 2</button>
</div>
</div>
.mdc-card {
background: var(--surface);
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1),
0 2px 4px rgba(0,0,0,0.06);
overflow: hidden;
transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.mdc-card:hover {
box-shadow: 0 4px 8px rgba(0,0,0,0.15),
0 2px 4px rgba(0,0,0,0.12);
}
.mdc-card__media {
position: relative;
padding-top: 56.25%; /* 16:9 aspect ratio */
background-size: cover;
background-position: center;
}
.mdc-card__media img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.mdc-card__content {
padding: 16px;
}
.mdc-card__title {
margin: 0 0 8px 0;
font-size: 24px;
font-weight: 400;
line-height: 32px;
}
.mdc-card__subtitle {
margin: 0 0 8px 0;
font-size: 14px;
font-weight: 500;
color: rgba(0, 0, 0, 0.6);
}
.mdc-card__description {
margin: 0;
font-size: 14px;
line-height: 20px;
color: rgba(0, 0, 0, 0.87);
}
.mdc-card__actions {
padding: 8px;
display: flex;
gap: 8px;
border-top: 1px solid rgba(0, 0, 0, 0.12);
}
Floating Action Button (FAB)
<button class="mdc-fab" aria-label="Add">
<span class="mdc-fab__icon">
<svg><!-- Plus icon --></svg>
</span>
</button>
.mdc-fab {
width: 56px;
height: 56px;
border-radius: 50%;
background: var(--secondary);
color: var(--on-secondary);
border: none;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 6px 10px rgba(0,0,0,0.14),
0 1px 18px rgba(0,0,0,0.12),
0 3px 5px rgba(0,0,0,0.2);
transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1),
transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.mdc-fab:hover {
box-shadow: 0 8px 14px rgba(0,0,0,0.16),
0 2px 22px rgba(0,0,0,0.14),
0 4px 8px rgba(0,0,0,0.22);
transform: scale(1.05);
}
.mdc-fab__icon svg {
width: 24px;
height: 24px;
fill: currentColor;
}
/* Mini FAB */
.mdc-fab--mini {
width: 40px;
height: 40px;
}
/* Extended FAB */
.mdc-fab--extended {
width: auto;
padding: 0 20px;
border-radius: 28px;
}
Text Field
<div class="mdc-text-field">
<input type="text" id="my-input" class="mdc-text-field__input">
<label for="my-input" class="mdc-text-field__label">Label</label>
<div class="mdc-text-field__line"></div>
</div>
.mdc-text-field {
position: relative;
display: inline-flex;
flex-direction: column;
width: 100%;
}
.mdc-text-field__input {
padding: 20px 0 6px 0;
border: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.42);
font-size: 16px;
background: transparent;
transition: border-color 0.2s;
}
.mdc-text-field__input:focus {
outline: none;
border-bottom-color: var(--primary);
}
.mdc-text-field__label {
position: absolute;
left: 0;
top: 20px;
color: rgba(0, 0, 0, 0.6);
font-size: 16px;
pointer-events: none;
transition: all 0.2s;
}
.mdc-text-field__input:focus + .mdc-text-field__label,
.mdc-text-field__input:not(:placeholder-shown) + .mdc-text-field__label {
top: 0;
font-size: 12px;
color: var(--primary);
}
.mdc-text-field__line {
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background: var(--primary);
transition: width 0.2s;
}
.mdc-text-field__input:focus ~ .mdc-text-field__line {
width: 100%;
}
Motion and Animation
Easing Curves
Material Design defines specific easing functions:
/* Material easing curves */
:root {
--ease-standard: cubic-bezier(0.4, 0.0, 0.2, 1);
--ease-deceleration: cubic-bezier(0.0, 0.0, 0.2, 1);
--ease-acceleration: cubic-bezier(0.4, 0.0, 1, 1);
--ease-sharp: cubic-bezier(0.4, 0.0, 0.6, 1);
}
/* Usage */
.element {
transition: transform 0.3s var(--ease-standard);
}
Duration Guidelines
| Element | Duration |
|---|---|
| Small elements (icons, buttons) | 100-200ms |
| Medium elements (cards, menus) | 200-300ms |
| Large elements (dialogs, sheets) | 300-400ms |
| Full screen transitions | 400-500ms |
Shared Axis Transition
/* Element leaving */
.exit {
animation: exit-transition 300ms var(--ease-acceleration);
}
@keyframes exit-transition {
from {
opacity: 1;
transform: translateX(0);
}
to {
opacity: 0;
transform: translateX(-30px);
}
}
/* Element entering */
.enter {
animation: enter-transition 300ms var(--ease-deceleration);
}
@keyframes enter-transition {
from {
opacity: 0;
transform: translateX(30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
Layout Grid
Material Design uses an 8dp grid system:
/* 8dp baseline grid */
:root {
--spacing-1: 8px; /* 1 unit */
--spacing-2: 16px; /* 2 units */
--spacing-3: 24px; /* 3 units */
--spacing-4: 32px; /* 4 units */
--spacing-6: 48px; /* 6 units */
--spacing-8: 64px; /* 8 units */
}
/* Responsive columns */
.mdc-layout-grid {
display: grid;
gap: 16px;
padding: 16px;
}
/* Phone */
@media (max-width: 599px) {
.mdc-layout-grid {
grid-template-columns: repeat(4, 1fr);
}
}
/* Tablet */
@media (min-width: 600px) and (max-width: 1023px) {
.mdc-layout-grid {
grid-template-columns: repeat(8, 1fr);
gap: 24px;
padding: 24px;
}
}
/* Desktop */
@media (min-width: 1024px) {
.mdc-layout-grid {
grid-template-columns: repeat(12, 1fr);
gap: 24px;
padding: 24px;
max-width: 1200px;
margin: 0 auto;
}
}
When to Use Material Design
Perfect For
- Android apps: Native Material components
- Google ecosystem: Consistent with Google products
- Enterprise applications: Professional, trustworthy
- Cross-platform apps: Works well on web and mobile
- Dashboard/Admin interfaces: Clear hierarchy
Real-World Examples
- Gmail: Material redesign
- Google Drive: File management interface
- Android OS: System UI
- YouTube: Video platform interface
Pros and Cons
Advantages
- ✅ Complete design system with components
- ✅ Extensive documentation and guidelines
- ✅ Accessible by default
- ✅ Works across platforms
- ✅ Recognizable and trusted
- ✅ Motion guidelines included
- ✅ Mature component libraries available
Disadvantages
- ❌ Can look "too Google"
- ❌ Requires learning the system
- ❌ Heavy component libraries
- ❌ Can feel corporate/generic
- ❌ Shadows add visual weight
Implementation Resources
Official Libraries
# Material Components Web
npm install @material/button @material/card @material/textfield
# Or full library
npm install material-components-web
Frameworks
- Angular Material: Official Angular implementation
- Vuetify: Material Design for Vue.js
- React Material-UI (MUI): React implementation
- Material Design Lite: Lightweight vanilla implementation
Checklist for Material Design
- [ ] Uses elevation system (shadows) appropriately
- [ ] Follows 8dp baseline grid
- [ ] Implements material motion principles
- [ ] Uses Roboto font (or system alternative)
- [ ] Color system follows primary/secondary/surface pattern
- [ ] Ripple effects on interactive elements
- [ ] Touch targets at least 48x48dp
- [ ] Follows material typography scale
- [ ] Meets accessibility standards
- [ ] Responsive across breakpoints
Resources
Official
Tools
- Material Theme Editor: Customize Material themes
- Material Icons: 2000+ official icons
- Material Palette: Color scheme generator
Further Reading
- Material Design by Google Design
- Material Design blog posts on Medium