Skip to content

Step 9: Improve Visual Design

Time: ~10 minutes | Type: Styling | Concepts: Spacing, hover states, shadows, mobile responsiveness

What We're Building

Visual polish to make your app look professional:

  • Consistent spacing scale (4/8/16/24px)
  • Hover states on interactive elements
  • Focus states for keyboard navigation
  • Subtle shadows for depth
  • Basic mobile responsiveness

The Prompt for AI

💡 Ask AI to help you improve visual design:

I want to improve the visual design of my todo app.

Current issues:
- Inconsistent spacing between elements
- No hover states on buttons
- No focus indicators
- Flat design (no depth)
- Doesn't work well on mobile

I need CSS improvements for:
1. Consistent spacing scale (4px increments)
2. Hover states (buttons, links, cards)
3. Focus states for accessibility
4. Subtle shadows on cards/buttons
5. Mobile responsive layout (smaller screens)
6. Better typography (font sizes, line height)

Can you provide CSS updates to make the app look more polished?
Don't change HTML structure, just improve CSS.

Wait for AI's response, then apply the CSS updates.

Part 1: Create Spacing Scale

Add CSS variables for consistent spacing:

css
/* src/index.css or src/App.css */

/* Spacing Scale */
:root {
  --spacing-1: 4px;
  --spacing-2: 8px;
  --spacing-3: 12px;
  --spacing-4: 16px;
  --spacing-5: 20px;
  --spacing-6: 24px;
  --spacing-8: 32px;
  --spacing-10: 40px;
  --spacing-12: 48px;

  /* Colors */
  --color-primary: #3b82f6;
  --color-primary-hover: #2563eb;
  --color-danger: #ef4444;
  --color-danger-hover: #dc2626;
  --color-success: #10b981;
  --color-border: #e5e7eb;
  --color-text: #1f2937;
  --color-text-light: #6b7280;

  /* Shadows */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
}

Use spacing in your layouts:

css
/* Container spacing */
.container {
  padding: var(--spacing-6);
  max-width: 800px;
  margin: 0 auto;
}

/* Form spacing */
form {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-4);
}

/* List spacing */
.todo-list {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-3);
}

Part 2: Add Hover States

Make interactive elements respond to hover:

css
/* Button Hover States */
button {
  padding: var(--spacing-2) var(--spacing-4);
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.2s ease;
}

button:hover:not(:disabled) {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}

button:active:not(:disabled) {
  transform: translateY(0);
}

button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* Primary Button */
.button-primary {
  background: var(--color-primary);
  color: white;
}

.button-primary:hover:not(:disabled) {
  background: var(--color-primary-hover);
}

/* Danger Button */
.button-danger {
  background: var(--color-danger);
  color: white;
}

.button-danger:hover:not(:disabled) {
  background: var(--color-danger-hover);
}

/* Link Hover */
a {
  color: var(--color-primary);
  text-decoration: none;
  transition: color 0.2s ease;
}

a:hover {
  color: var(--color-primary-hover);
  text-decoration: underline;
}

/* Card Hover */
.todo-card {
  padding: var(--spacing-4);
  background: white;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  transition: all 0.2s ease;
}

.todo-card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--color-primary);
}

Part 3: Add Focus States

Ensure keyboard navigation is visible:

css
/* Focus Styles for Accessibility */
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
a:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Remove default focus outline, replace with better one */
*:focus {
  outline: none;
}

*:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

What this does:

  • Removes default browser outline (often ugly)
  • Adds visible blue outline when navigating with keyboard
  • :focus-visible only shows when using keyboard (not mouse clicks)

Part 4: Add Shadows for Depth

Add subtle shadows to create visual hierarchy:

css
/* Card Shadows */
.card {
  background: white;
  padding: var(--spacing-6);
  border-radius: 8px;
  box-shadow: var(--shadow-sm);
}

/* Elevated Card (on hover or important) */
.card-elevated {
  box-shadow: var(--shadow-lg);
}

/* Input Shadows */
input,
textarea {
  padding: var(--spacing-2) var(--spacing-3);
  border: 1px solid var(--color-border);
  border-radius: 6px;
  font-size: 14px;
  transition: all 0.2s ease;
}

input:focus,
textarea:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
}

Part 5: Mobile Responsiveness

Make the app work on smaller screens:

css
/* Mobile Responsive Layout */

/* Container adapts to screen size */
.container {
  padding: var(--spacing-4);
  max-width: 100%;
}

/* Responsive breakpoint for tablets and phones */
@media (max-width: 768px) {
  /* Smaller spacing on mobile */
  .container {
    padding: var(--spacing-3);
  }

  /* Stack buttons vertically on mobile */
  .button-group {
    flex-direction: column;
    width: 100%;
  }

  .button-group button {
    width: 100%;
  }

  /* Smaller font sizes on mobile */
  h1 {
    font-size: 24px;
  }

  h2 {
    font-size: 20px;
  }

  /* Full-width forms on mobile */
  form {
    width: 100%;
  }

  input,
  textarea {
    width: 100%;
    font-size: 16px; /* Prevent zoom on iOS */
  }

  /* Smaller todo cards */
  .todo-card {
    padding: var(--spacing-3);
  }

  /* Toast notifications - smaller on mobile */
  .toast {
    min-width: auto;
    max-width: 90%;
  }
}

Part 6: Typography Improvements

Better font sizing and spacing:

css
/* Typography */
body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  color: var(--color-text);
  line-height: 1.6;
}

h1 {
  font-size: 32px;
  font-weight: 700;
  margin: 0 0 var(--spacing-6) 0;
  color: var(--color-text);
}

h2 {
  font-size: 24px;
  font-weight: 600;
  margin: 0 0 var(--spacing-4) 0;
  color: var(--color-text);
}

h3 {
  font-size: 18px;
  font-weight: 600;
  margin: 0 0 var(--spacing-3) 0;
  color: var(--color-text);
}

p {
  margin: 0 0 var(--spacing-4) 0;
  color: var(--color-text-light);
}

Verification

Test visual improvements:

Test 1: Spacing Consistency

  1. Open your app
  2. Look at spacing between elements
  3. Expected:
    • [ ] Consistent gaps (not random)
    • [ ] Form inputs evenly spaced
    • [ ] Cards have consistent padding
    • [ ] Page margins look balanced

Test 2: Hover States

  1. Hover over buttons

  2. Expected:

    • [ ] Button lifts slightly (translateY)
    • [ ] Shadow appears
    • [ ] Color darkens
    • [ ] Smooth transition (not instant)
  3. Hover over links

  4. Expected:

    • [ ] Color changes
    • [ ] Underline appears
    • [ ] Smooth transition
  5. Hover over todo cards

  6. Expected:

    • [ ] Shadow appears
    • [ ] Border color changes to blue
    • [ ] Smooth transition

Test 3: Focus States (Keyboard Navigation)

  1. Press Tab to navigate
  2. Expected:
    • [ ] Blue outline appears on focused element
    • [ ] Outline visible and clear
    • [ ] Can navigate through all interactive elements
    • [ ] Current focus always visible

Test 4: Shadows

  1. Look at cards, buttons, inputs
  2. Expected:
    • [ ] Subtle shadows (not too harsh)
    • [ ] Creates sense of depth
    • [ ] Shadows darken on hover
    • [ ] Looks polished

Test 5: Mobile Responsiveness

  1. Open browser DevTools (F12)
  2. Toggle device toolbar (Ctrl+Shift+M)
  3. Set to "iPhone SE" or similar small screen
  4. Expected:
    • [ ] Content fits screen (no horizontal scroll)
    • [ ] Buttons stack vertically
    • [ ] Font sizes readable
    • [ ] Touch targets large enough (44px minimum)
    • [ ] Form inputs full width
    • [ ] Spacing appropriate for mobile

Test 6: Typography

  1. Check all text on the page
  2. Expected:
    • [ ] Headings have clear hierarchy
    • [ ] Body text readable (not too small)
    • [ ] Line height comfortable (not cramped)
    • [ ] Colors have good contrast

Common Issues

Hover States Not Working

Problem: Missing transition or selector wrong.

Fix:

css
button {
  transition: all 0.2s ease;  /* Must be on base element */
}

button:hover:not(:disabled) {  /* Don't forget :not(:disabled) */
  /* hover styles */
}

Focus Outline Not Showing

Problem: Using :focus instead of :focus-visible.

Fix:

css
*:focus-visible {  /* Use focus-visible, not just focus */
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

Mobile Layout Broken

Problem: Missing max-width: 100% or viewport meta tag.

Fix:

  1. Check HTML has viewport meta tag:
html
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
  1. Make sure elements don't exceed screen:
css
.container {
  max-width: 100%;
  padding: var(--spacing-4);
}

Shadows Too Harsh

Problem: Shadow opacity too high.

Fix: Lower opacity in shadow definition:

css
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);  /* 0.1 is subtle */

Understanding Check

Before moving on, make sure you understand:

💡 Ask yourself:

  1. Why use CSS variables for spacing? (Consistency, easy to change)
  2. What does transition: all 0.2s ease do? (Smooths all property changes)
  3. Why use :focus-visible instead of :focus? (Only shows for keyboard, not mouse)
  4. How do media queries make sites responsive? (Apply different CSS at different screen sizes)
  5. Why use translateY for hover effect? (Creates subtle lift, feels interactive)

What You Learned

At this point you should have:

  • ✅ Consistent spacing scale (CSS variables)
  • ✅ Hover states on all interactive elements
  • ✅ Focus states for keyboard navigation
  • ✅ Subtle shadows for depth
  • ✅ Mobile responsive layout
  • ✅ Better typography
  • ✅ Professional visual design
  • ✅ Smooth transitions

Next Step

Now let's add basic accessibility improvements for screen readers and keyboard users:

Step 10: Add Accessibility →

Built for learning | Open source on GitHub