Color Mode

Custom Properties and Math Functions Practice

This assignment gives you hands-on practice with CSS custom properties and math functions. You will build a small component system that uses custom properties for theming, implements fluid typography and spacing with clamp(), and creates component variations using scoped custom properties. The result will be a responsive, maintainable design system built entirely with modern native CSS.

By the end of this assignment, you will have practical experience creating flexible design systems that adapt to different contexts without media queries or preprocessors.

Assignment Overview

You will create a single HTML file with embedded CSS that demonstrates a complete design system built with custom properties and math functions. The page will include navigation, card components, buttons with state variations, and fluid typography that scales smoothly across viewport sizes.

All styling should be accomplished using custom properties defined in :root for global values and scoped to specific elements for variations. You will use clamp() for fluid sizing and calc() for derived values.

Starter Files

Download the starter HTML file below. It contains a basic page structure with navigation, hero section, card grid, and buttons. Your job is to style it entirely using custom properties and math functions.

Download Starter HTML File

The starter file includes the HTML structure but minimal CSS. You will add all custom properties, styling, and theming from scratch.

Assignment Instructions

1. Create Your Design System Foundation

Add a <style> section to your HTML file (or use an embedded style tag if one exists). Define a comprehensive set of custom properties in :root that will serve as your design system foundation.

Your design system should include:


      :root {
          /* Colors */
          --color-primary: #3498db;
          --color-secondary: #2ecc71;
          --color-background: #ffffff;
          --color-text: #2c3e50;
          
          /* Fluid Spacing (scales with viewport) */
          --spacing-xs: clamp(0.25rem, 1vw, 0.5rem);
          --spacing-sm: clamp(0.5rem, 2vw, 1rem);
          /* Add more spacing values... */
          
          /* Fluid Typography */
          --font-size-base: clamp(1rem, 2.5vw, 1.125rem);
          --font-size-lg: calc(var(--font-size-base) * 1.25);
          /* Add more type sizes... */
          
          /* Layout */
          --max-width: 1200px;
          --border-radius: 0.5rem;
          /* Add more layout values... */
      }
  
Fluid Values with clamp()

Use clamp(min, preferred, max) for spacing and typography that scales smoothly. The preferred value should use viewport units (vw) so it grows with screen size, while min and max keep it readable on all devices.

2. Style the Navigation

Style the navigation component using your custom properties. The navigation should have a background color, padding using your spacing scale, and links that use your color system.

Requirements:

3. Implement Fluid Typography

Apply your typography scale to the page content. Headings should use larger sizes from your scale, body text should use the base size, and all sizes should scale fluidly with the viewport.

Requirements:

4. Build Card Components with Variations

Style the card components using custom properties. Then create variations by scoping custom properties to modifier classes.

Requirements:


      .card {
          --card-bg: var(--color-background);
          --card-text: var(--color-text);
          --card-border: var(--color-primary);
          
          background: var(--card-bg);
          color: var(--card-text);
          border-left: 4px solid var(--card-border);
          padding: var(--spacing-md);
          border-radius: var(--border-radius);
          /* More styles... */
      }
      
      .card-featured {
          --card-bg: var(--color-primary);
          --card-text: white;
          --card-border: var(--color-secondary);
      }
  

5. Create Button System with State Variations

Style buttons using custom properties and create hover/active states that adjust colors dynamically using color-mix() or relative color syntax.

Requirements:


      .btn {
          --btn-bg: var(--color-primary);
          --btn-text: white;
          
          background: var(--btn-bg);
          color: var(--btn-text);
          padding: var(--spacing-sm) var(--spacing-md);
          border: none;
          border-radius: var(--border-radius);
          cursor: pointer;
          transition: background 0.2s;
      }
      
      .btn:hover {
          background: color-mix(in oklch, var(--btn-bg) 85%, black);
      }
      
      .btn:active {
          background: color-mix(in oklch, var(--btn-bg) 70%, black);
      }
  

6. Add Dark Theme Support

Create a dark theme by redefining your color custom properties when a data-theme="dark" attribute is present on the root element.

Requirements:


      [data-theme="dark"] {
          --color-background: #1a1a1a;
          --color-text: #f0f0f0;
          --color-primary: #5dade2;
          /* Redefine other colors for dark mode... */
      }
  
Automatic Theme Switching

Because your components reference custom properties, changing the theme values automatically updates the entire page. You do not need to modify individual component styles. This is the power of custom properties.

7. Add Reflection Comment

At the top of your CSS (inside the <style> tag), add a multiline comment reflecting on your experience with this assignment.

Address these points:


      /*
       * REFLECTION
       * 
       * Custom Properties vs Hard-coded Values:
       * [Your thoughts here...]
       * 
       * Using clamp() for Fluid Design:
       * [Your thoughts here...]
       * 
       * Scoped Custom Properties:
       * [Your thoughts here...]
       * 
       * Theme Switching:
       * [Your thoughts here...]
       */
  

Submission Requirements

Submit a single HTML file to Canvas with:

Your file should be functional when opened in a modern browser. Test it by resizing the browser window to see your fluid typography and spacing in action.

Evaluation Criteria

Your assignment will be evaluated on:

Tips for Success

Start with the Design System

Define all your custom properties first before writing any component styles. This forces you to think systematically about your design values and ensures consistency.

Test Fluid Sizing

Resize your browser window frequently to see how your clamp() values behave. Adjust the min, preferred, and max values until the scaling feels natural.

Use DevTools

Browser DevTools can show you the computed values of custom properties. This is invaluable for debugging and understanding how values cascade and resolve.

Keep Calculations Simple

When using calc() to derive values, keep expressions straightforward. Complex nested calculations are hard to debug and maintain.

Test Both Themes

To test your dark theme, manually add data-theme="dark" to the <html> tag in your HTML file. Remember to remove it before submission unless you want dark mode as the default.

Optional Enhancement: Theme Toggle

If you want to add interactive theme switching, here is a simple JavaScript snippet you can include at the bottom of your HTML file (before the closing </body> tag). This is completely optional and not required for the assignment.


      <!-- Add a theme toggle button in your navigation -->
      <button id="theme-toggle" class="btn">Toggle Theme</button>
      
      <!-- Add this script before closing body tag -->
      <script type="module">
          const toggleButton = document.getElementById('theme-toggle');
          const html = document.documentElement;
          
          toggleButton.addEventListener('click', () => {
              const currentTheme = html.getAttribute('data-theme');
              const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
              html.setAttribute('data-theme', newTheme);
          });
      </script>
  

This adds a button that toggles between light and dark themes by changing the data-theme attribute on the HTML element. Your CSS already handles the visual changes through custom properties.

The script uses modern ES modules (type="module") and arrow functions with explicit curly braces. The toggle logic reads the current theme, determines the new theme, and updates the attribute. Your custom properties handle everything else automatically.

What You Will Learn

This assignment reinforces your understanding of CSS custom properties and math functions through practical application. You will gain experience building maintainable design systems, creating fluid responsive layouts without media queries, implementing component variations with scoped properties, and building theme systems that adapt dynamically.

These skills are fundamental to modern CSS development. The patterns you practice here will apply to every project you build, from small landing pages to large applications. Custom properties and math functions are not advanced features you use occasionally but core tools you will use daily.