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

LevelUse Case
0Static content, backgrounds
1Cards at rest
2Raised buttons, cards on hover
3FAB (Floating Action Button) at rest
4FAB on hover, app bars
5Dialogs, 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

ElementDuration
Small elements (icons, buttons)100-200ms
Medium elements (cards, menus)200-300ms
Large elements (dialogs, sheets)300-400ms
Full screen transitions400-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