Media Queries in Responsive Web Design

Week 4: Wednesday Morning Session

What are Media Queries?

Media queries are the backbone of responsive web design, allowing CSS to apply different styles based on the characteristics of the device or browser viewport. Think of media queries as filters that examine the current state of the browsing environment and apply CSS rules only when specific conditions are met.

Just as a thermostat in your home triggers the heating system when the temperature drops below a certain threshold, media queries trigger specific CSS rules when the viewport meets particular conditions (like being narrower than 768 pixels).

Before media queries, creating websites that adapted to different screen sizes required separate versions of the site or complex JavaScript solutions. Media queries revolutionized web development by providing a pure CSS approach to responsive design.

Anatomy of a Media Query

Let's break down the structure of a media query to understand its components:

@media media-type and (media-feature-rule) {
    /* CSS rules to be applied when media query matches */
    selector {
        property: value;
    }
}

The key components are:

Real-world analogy: Think of media queries like a bouncer at a club. The media type is like checking if someone is on the guest list (are they using a screen, printer, etc.). Media features are like additional entry requirements (are they over 21, dressed appropriately, etc.). Only when all conditions are met does the person (or in our case, the CSS rules) get to enter.

Media Types

Media types define the broad category of device. While there are several media types in the specification, these are the most commonly used:

Print Media Example

/* Normal screen styles */
body {
    background-color: #f5f5f5;
    color: #333;
}

/* Print-specific styles */
@media print {
    body {
        background-color: white;
        color: black;
        font-size: 12pt;
    }
    
    /* Hide navigation and interactive elements when printing */
    nav, button, .ads, .comments {
        display: none;
    }
    
    /* Ensure links show their URLs */
    a[href]:after {
        content: " (" attr(href) ")";
    }
}

Practical application: Print media queries are incredibly useful for creating printer-friendly versions of your content. They allow you to strip away navigation, adjust typography for paper, and even add content (like URLs) that makes the printed page more useful without cluttering the screen version.

Media Features

Media features are the conditions we test for within media queries. They allow us to target specific characteristics of the user's device or browser.

Width-based Media Features

/* Base mobile styles */
.container {
    padding: 10px;
}

/* Tablets and larger */
@media screen and (min-width: 768px) {
    .container {
        padding: 20px;
    }
}

/* Desktops and larger */
@media screen and (min-width: 1024px) {
    .container {
        padding: 30px;
        max-width: 1200px;
        margin: 0 auto;
    }
}

Note: min-width and max-width are more commonly used than the exact width, as they allow for more flexible designs that work across a range of screen sizes.

Height-based Media Features

/* Adjust hero section for shorter screens */
@media screen and (max-height: 600px) {
    .hero {
        min-height: auto;
        padding: 20px 0;
    }
    
    .hero h1 {
        font-size: 1.5rem;
    }
}

Real-world use case: Height-based queries are particularly useful for adjusting full-height elements on shorter screens, such as when a mobile device is in landscape orientation or on netbooks with limited vertical space.

Device Pixel Ratio Media Features

/* Standard resolution */
.logo {
    background-image: url('logo.png');
}

/* High resolution screens (like Retina displays) */
@media (-webkit-min-device-pixel-ratio: 2), 
       (min-resolution: 192dpi) { 
    .logo {
        background-image: url('logo@2x.png');
    }
}

Real-world application: Device pixel ratio queries allow you to serve higher-resolution images to devices with high-density displays (like Apple's Retina displays), while still serving appropriately sized images to standard displays. This helps maintain visual quality without unnecessarily increasing load times for all users.

Orientation Media Features

/* Default layout */
.gallery {
    display: grid;
    grid-template-columns: 1fr;
    gap: 10px;
}

/* Landscape orientation - more horizontal space */
@media screen and (orientation: landscape) {
    .gallery {
        grid-template-columns: repeat(3, 1fr);
    }
}

Real-world use case: Orientation queries are excellent for creating interfaces that adapt to how a user is holding their device. For example, a photo gallery might display in a single column in portrait mode but expand to multiple columns in landscape mode to take advantage of the wider screen.

Other Useful Media Features

These additional features allow for even more tailored experiences based on user preferences and device capabilities.

Logical Operators in Media Queries

Media queries support logical operators that allow you to create more complex conditions:

The 'and' Operator

The 'and' operator combines multiple conditions that must all be true for the query to apply.

/* Apply only when both conditions are met */
@media screen and (min-width: 768px) and (max-width: 1023px) {
    /* Tablet-specific styles */
    body {
        font-size: 16px;
    }
}

Real-world use case: The 'and' operator is perfect for targeting specific ranges, like creating styles exclusively for tablets by targeting screen widths between 768px and 1023px.

The 'not' Operator

The 'not' operator negates the query, applying styles when the conditions are NOT met.

/* Apply to everything except screens */
@media not screen {
    /* Styles for print, speech, etc. */
    body {
        background: none;
    }
}

Note: The 'not' operator applies to the entire query, not just a part of it.

The 'only' Operator

The 'only' operator is primarily used to hide media queries from older browsers that don't support them.

@media only screen and (min-width: 768px) {
    /* These styles will be ignored by very old browsers */
    .container {
        width: 750px;
    }
}

Note: Modern browsers no longer need the 'only' operator, but it's sometimes still included for backwards compatibility.

Using Commas for 'OR' Logic

Commas function like the 'OR' operator, allowing you to apply styles when any of the comma-separated conditions are true.

/* Apply when either condition is met */
@media screen and (max-width: 767px), print {
    /* Styles for both mobile devices and print */
    .sidebar {
        display: none;
    }
}

Real-world use case: This approach is useful when you want to apply the same styles in multiple contexts - for example, hiding a sidebar both on small screens and when printing.

Mobile-First vs. Desktop-First with Media Queries

Desktop-First Approach (Traditional)

In a desktop-first approach, you design for the desktop experience first and then use media queries with max-width to adapt the design for smaller screens.

/* Desktop styles (default) */
.container {
    width: 1140px;
    margin: 0 auto;
}

/* Tablet styles */
@media screen and (max-width: 1023px) {
    .container {
        width: 90%;
    }
}

/* Mobile styles */
@media screen and (max-width: 767px) {
    .container {
        width: 100%;
        padding: 0 15px;
    }
}

Analogy: Desktop-first is like starting with a large, fully-furnished house and then figuring out what furniture to remove to fit into a smaller apartment. You begin with everything and then start taking away.

Mobile-First Approach (Recommended)

In a mobile-first approach, you design for the mobile experience first and then use media queries with min-width to enhance the design for larger screens.

/* Mobile styles (default) */
.container {
    width: 100%;
    padding: 0 15px;
}

/* Tablet styles */
@media screen and (min-width: 768px) {
    .container {
        width: 90%;
        margin: 0 auto;
    }
}

/* Desktop styles */
@media screen and (min-width: 1024px) {
    .container {
        width: 1140px;
    }
}

Analogy: Mobile-first is like starting with a backpack containing only essential items for a hike, and then adding more items as you get a bigger backpack. You begin with the essentials and progressively enhance.

Why Mobile-First is Often Better

Real-world impact: Many major websites and frameworks (like Bootstrap) have shifted to a mobile-first approach over the years, recognizing that starting with the constraints of mobile creates more focused, efficient designs that scale up well to larger screens.

Common Breakpoints for Media Queries

While you should ideally set breakpoints based on your content rather than specific devices, these standard breakpoints provide a good starting point:

Device Category Breakpoint Range Common Values
Small mobile devices 320px - 575px 320px, 480px
Large mobile devices 576px - 767px 576px
Tablets 768px - 991px 768px
Laptops/small desktops 992px - 1199px 992px
Large desktops 1200px and above 1200px, 1400px

Bootstrap 5 Breakpoints

For reference, these are the breakpoints used by the popular Bootstrap framework:

// Small devices (landscape phones, 576px and up)
@media (min-width: 576px) { ... }

// Medium devices (tablets, 768px and up)
@media (min-width: 768px) { ... }

// Large devices (desktops, 992px and up)
@media (min-width: 992px) { ... }

// X-Large devices (large desktops, 1200px and up)
@media (min-width: 1200px) { ... }

// XX-Large devices (larger desktops, 1400px and up)
@media (min-width: 1400px) { ... }

Important consideration: Rather than targeting specific devices, focus on where your content and layout naturally need to adjust. This approach, known as "content-first" breakpoints, results in designs that work well across a wider range of devices.

Practical Examples of Media Queries

Responsive Navigation

One of the most common uses for media queries is creating a responsive navigation menu:

/* Mobile-first navigation (hamburger menu) */
.nav-toggle {
    display: block; /* Show hamburger icon */
}

.nav-menu {
    display: none; /* Hide menu by default */
}

.nav-menu.active {
    display: block; /* Show when toggled */
    position: absolute;
    top: 60px;
    left: 0;
    width: 100%;
    background: #fff;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}

.nav-menu li {
    display: block;
    border-bottom: 1px solid #eee;
}

/* Desktop navigation */
@media screen and (min-width: 768px) {
    .nav-toggle {
        display: none; /* Hide hamburger icon */
    }
    
    .nav-menu {
        display: flex; /* Always show menu */
        position: static;
        box-shadow: none;
    }
    
    .nav-menu li {
        display: inline-block;
        border-bottom: none;
        margin-left: 20px;
    }
}

Real-world implementation: This pattern is used on countless websites to transform a horizontal navigation on desktop into a space-saving hamburger menu on mobile devices.

Responsive Grid Layout

Creating a grid layout that adjusts columns based on screen size:

/* Mobile: Single column */
.grid-container {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
}

/* Tablet: Two columns */
@media screen and (min-width: 768px) {
    .grid-container {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* Desktop: Four columns */
@media screen and (min-width: 1024px) {
    .grid-container {
        grid-template-columns: repeat(4, 1fr);
    }
}

Real-world application: This approach is ideal for product listings, image galleries, blog posts, and any content that benefits from a grid layout.

Font Size Adjustments

Adjusting typography for different screen sizes:

/* Base typography (mobile) */
body {
    font-size: 16px;
}

h1 {
    font-size: 1.75rem;
    line-height: 1.2;
}

h2 {
    font-size: 1.5rem;
    line-height: 1.2;
}

/* Tablet typography */
@media screen and (min-width: 768px) {
    body {
        font-size: 17px;
    }
    
    h1 {
        font-size: 2rem;
    }
    
    h2 {
        font-size: 1.75rem;
    }
}

/* Desktop typography */
@media screen and (min-width: 1024px) {
    body {
        font-size: 18px;
    }
    
    h1 {
        font-size: 2.5rem;
    }
    
    h2 {
        font-size: 2rem;
    }
}

Design principle: Typography should scale proportionally with screen size, but not in a strictly linear fashion. Reading comfort requires different sizing adjustments at different screen sizes.

Responsive Images

Using media queries with the picture element for art direction:

<picture>
    <source media="(min-width: 1024px)" srcset="image-large.jpg">
    <source media="(min-width: 768px)" srcset="image-medium.jpg">
    <img src="image-small.jpg" alt="Responsive Image">
</picture>

Use case: This approach allows you to not only serve differently sized images but also differently cropped or composed images based on screen size. For example, a landscape-oriented hero image on desktop might be replaced with a portrait-oriented version on mobile.

Advanced Media Query Techniques

Nested Media Queries in Sass/SCSS

CSS preprocessors like Sass allow you to nest media queries within selectors, making your code more organized:

// SCSS
.card {
    padding: 15px;
    
    @media screen and (min-width: 768px) {
        padding: 20px;
    }
    
    .card-title {
        font-size: 1.2rem;
        
        @media screen and (min-width: 768px) {
            font-size: 1.5rem;
        }
    }
}

This compiles to:

/* Compiled CSS */
.card {
    padding: 15px;
}

@media screen and (min-width: 768px) {
    .card {
        padding: 20px;
    }
}

.card .card-title {
    font-size: 1.2rem;
}

@media screen and (min-width: 768px) {
    .card .card-title {
        font-size: 1.5rem;
    }
}

Development benefit: Nesting media queries keeps related styles together in your source code, making maintenance easier and helping developers understand the relationship between base styles and their responsive variations.

Feature Queries with @supports

Combine media queries with feature queries for progressive enhancement:

/* Basic styling for all browsers */
.container {
    display: block;
}

/* Enhanced with Flexbox for browsers that support it */
@supports (display: flex) {
    .container {
        display: flex;
        flex-wrap: wrap;
    }
    
    /* Make flexbox responsive */
    @media screen and (max-width: 767px) {
        .container {
            flex-direction: column;
        }
    }
}

Progressive enhancement: This approach allows you to provide a baseline experience for all browsers while enhancing the experience for those that support modern features. The media query inside the @supports block creates responsive behavior only when the feature is supported.

Container Queries (Emerging Standard)

Container queries are an evolving feature that allows components to respond to their parent container's size rather than the viewport:

/* Define a containment context */
.card-container {
    container-type: inline-size;
}

/* Base card styles */
.card {
    padding: 15px;
}

/* When the container is at least 400px wide */
@container (min-width: 400px) {
    .card {
        padding: 20px;
        display: flex;
    }
}

The future of responsive design: Container queries represent a shift from viewport-centric to component-centric responsive design. They allow reusable components to adapt based on their immediate context rather than the overall page size, which is especially valuable for design systems and component libraries.

Preference Queries

Media queries that respond to user preferences:

/* Default light theme */
:root {
    --background-color: #fff;
    --text-color: #333;
}

/* Dark theme for users who prefer it */
@media (prefers-color-scheme: dark) {
    :root {
        --background-color: #222;
        --text-color: #f0f0f0;
    }
}

/* Reduce animations for users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
    * {
        animation: none !important;
        transition: none !important;
    }
}

Accessibility benefit: Preference queries allow your design to respect user needs and preferences at the operating system level, which is particularly important for accessibility and user experience. For example, users with vestibular disorders often enable reduced motion settings to prevent discomfort from animations.

Common Media Query Mistakes and Best Practices

Common Mistakes

Best Practices

Performance Considerations

Media queries can impact performance if not handled carefully:

<!-- Conditionally load CSS based on viewport size -->
<link rel="stylesheet" href="base.css">
<link rel="stylesheet" href="tablet.css" media="screen and (min-width: 768px)">
<link rel="stylesheet" href="desktop.css" media="screen and (min-width: 1024px)">

Performance benefit: With this approach, browsers will only download the CSS files relevant to the current viewport size, reducing initial load time, particularly for mobile users.

Practical Workshop: Building a Responsive Component

Let's apply what we've learned by building a responsive card component that adapts across different screen sizes:

HTML Structure

<div class="product-card">
    <div class="product-image">
        <img src="product.jpg" alt="Product Name">
    </div>
    <div class="product-info">
        <h3 class="product-title">Product Name</h3>
        <p class="product-description">This is a short description of the product and its features.</p>
        <div class="product-meta">
            <span class="product-price">$29.99</span>
            <button class="product-button">Add to Cart</button>
        </div>
    </div>
</div>

CSS with Media Queries

/* Base styles (mobile-first) */
.product-card {
    border: 1px solid #eee;
    border-radius: 8px;
    overflow: hidden;
    background: white;
    box-shadow: 0 2px 5px rgba(0,0,0,0.1);
    margin-bottom: 20px;
}

.product-image img {
    width: 100%;
    height: auto;
    display: block;
}

.product-info {
    padding: 15px;
}

.product-title {
    margin-top: 0;
    margin-bottom: 10px;
    font-size: 1.2rem;
}

.product-description {
    margin-bottom: 15px;
    font-size: 0.9rem;
    color: #666;
}

.product-meta {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.product-price {
    font-weight: bold;
    font-size: 1.1rem;
}

.product-button {
    background: #0066cc;
    color: white;
    border: none;
    padding: 8px 15px;
    border-radius: 4px;
    cursor: pointer;
    font-weight: bold;
}

/* Tablet styles */
@media screen and (min-width: 768px) {
    .product-card {
        display: flex;
        max-height: 200px;
    }
    
    .product-image {
        flex: 0 0 200px;
    }
    
    .product-image img {
        height: 100%;
        object-fit: cover;
    }
    
    .product-info {
        flex: 1;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
    }
    
    .product-title {
        font-size: 1.3rem;
    }
}

/* Desktop styles */
@media screen and (min-width: 1024px) {
    .product-card {
        transition: transform 0.3s ease, box-shadow 0.3s ease;
    }
    
    .product-card:hover {
        transform: translateY(-5px);
        box-shadow: 0 5px 15px rgba(0,0,0,0.1);
    }
    
    .product-button {
        opacity: 0.9;
        transition: opacity 0.3s ease, background-color 0.3s ease;
    }
    
    .product-button:hover {
        opacity: 1;
        background-color: #0055aa;
    }
}

/* Large desktop styles */
@media screen and (min-width: 1400px) {
    .product-info {
        padding: 20px;
    }
    
    .product-title {
        font-size: 1.5rem;
    }
    
    .product-description {
        font-size: 1rem;
    }
}

This responsive component demonstrates:

Real-world application: This card pattern is commonly used for product listings in e-commerce, article previews in blogs, and content cards in dashboards and apps.

Testing Media Queries

Browser Developer Tools

Most modern browsers include responsive design mode in their developer tools:

Browser Extensions

Extensions can enhance your media query testing workflow:

Online Testing Tools

Testing Checklist

When testing your media queries, check the following:

Conclusion: The Power of Media Queries

Media queries are the foundation that makes responsive web design possible. They allow us to create websites that provide optimal experiences across an ever-expanding range of devices and screen sizes.

Remember that effective responsive design isn't just about making things fit on different screens—it's about delivering the right experience for each context. Media queries give us the tool to create these contextual experiences, adapting not just layout but typography, interaction, and even content to meet users where they are.

As web technology continues to evolve, the role of media queries is expanding beyond just screen sizes to include user preferences, device capabilities, and environmental conditions. By mastering media queries, you're equipping yourself with a fundamental skill that will remain relevant even as the specifics of web design continue to evolve.

In our next session, we'll explore how to combine media queries with modern layout techniques like Flexbox and CSS Grid to create even more powerful responsive designs with less code.

Daily Assignment: Media Query Mastery

Apply today's concepts by creating a responsive webpage that demonstrates effective use of media queries:

  1. Create a webpage with a header, main content area with cards, sidebar, and footer
  2. Implement a mobile-first approach with at least 3 breakpoints
  3. The layout should stack vertically on mobile, with the sidebar below the main content
  4. On tablets, implement a 2-column card layout and keep the sidebar below
  5. On desktop, create a 3-column layout for cards and move the sidebar to the right
  6. Include at least one print media query that optimizes the page for printing
  7. Implement at least one preference query (dark mode or reduced motion)

Requirements:

Create this in a file called 04week/media_queries_assignment.html and submit it to the course repository by the end of day.

Additional Resources