Learn Responsive Web Design with JavaScript on Day 7. Dive into mobile-first design, CSS media queries, and touch event handling for modern web development.
Day 7. Your layout looks sharp on your laptop, then someone opens it on a phone and the whole thing folds in on itself. Responsive design is how you stop that from happening. CSS does most of the styling, but JavaScript lets you react to the screen instead of only decorating it. Today we cover mobile-first thinking, media queries in both CSS and JS, and touch events.
Table of Contents
Mobile-First Design Approach
Mobile-first means you design for the small screen first, then add complexity as the screen grows. It feels backwards if you came up on desktop, but that constraint is the point. A phone has no room for filler, so you’re forced to decide what actually matters and layer the rest on top.
Start with a fluid grid. Use relative units like percentages and viewport units (vw, vh) so the layout stretches instead of snapping at fixed pixel widths:
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
}
.column {
width: 100%;
padding: 0 15px;
}
@media (min-width: 768px) {
.column {
width: 50%;
}
}Beyond the grid, three things carry most of the weight:
- Mobile navigation: Build a menu that collapses cleanly on small screens and stays intuitive as the screen widens. This is the thing people notice first when it’s wrong.
- Images and media: Let them scale to the screen. Use the
srcsetattribute so the browser picks a right-sized image, andobject-fitto keep aspect ratios from breaking. - Typography: Pick readable fonts and size them with relative units like
remoremso text scales with the layout instead of fighting it.
CSS Media Queries and JavaScript
Media queries apply styles based on what the device can do: width, height, resolution, orientation. Here’s the plain CSS version, nudging the font size up as the screen gets wider:
/* Mobile styles (default) */
body {
font-size: 14px;
}
/* Tablet styles */
@media (min-width: 768px) {
body {
font-size: 16px;
}
}
/* Desktop styles */
@media (min-width: 1024px) {
body {
font-size: 18px;
}
}CSS handles the styling. But sometimes you need JavaScript to do something when a breakpoint changes, not just repaint. That’s what window.matchMedia() is for. It returns a MediaQueryList object you can both read right now and subscribe to for changes.
Attach a change listener and it fires whenever the viewport crosses the breakpoint in either direction:
/**
* Checks for changes in screen width and logs whether the screen width matches a specific media query.
*
* @param {MediaQueryList} e - A MediaQueryList object that represents the result of the query.
*/
const mediaQuery = window.matchMedia("(min-width: 768px)");
/**
* Handles changes in the screen width by logging the current state of the screen width.
* This function is triggered when the media query result changes (screen size changes).
*
* @param {MediaQueryListEvent} e - Event object representing the change in media query state.
*/
function handleScreenChange(e) {
if (e.matches) {
console.log("Screen width is at least 768px");
} else {
console.log("Screen width is less than 768px");
}
}
// Adds an event listener to detect changes in the screen width.
mediaQuery.addEventListener("change", handleScreenChange);
// Call the function initially to log the current screen state
handleScreenChange(mediaQuery);Two details worth calling out. The listener only fires on a change, so we call the handler once up front to catch the current state on load. And addEventListener("change", ...) is the current way to do this. The older addListener() method still works but is deprecated, so reach for the event-listener form on new code.
Working with Touch Events
Phones and tablets don’t have a mouse. Touch events give you the raw interaction: where a finger lands, how it moves, when it lifts. Four events cover the whole lifecycle:
touchstart: fires when a finger first lands on the screen.touchmove: fires as the finger slides across the screen.touchend: fires when the finger lifts off.touchcancel: fires when the browser cuts the touch off, for example the screen rotates mid-gesture, the browser rejects an accidental palm touch, or the system takes over the input.
Here’s a small area wired up to log each event as it happens:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Touch Events Example</title>
</head>
<body>
<div id="touchArea" style="width: 100%; height: 300px; background-color: #f0f0f0;"></div>
<script>
/**
* Initializes touch event listeners on the touch area.
* Logs touch event details when triggered.
*/
// Select the touch area element
const touchArea = document.getElementById("touchArea");
/**
* Event listener for the 'touchstart' event.
* Triggered when a user starts touching the screen.
* @param {TouchEvent} e - The touch event object.
*/
touchArea.addEventListener("touchstart", (e) => {
e.preventDefault();
console.log("Touch started");
});
/**
* Event listener for the 'touchmove' event.
* Triggered when a user moves their finger across the screen.
* @param {TouchEvent} e - The touch event object.
*/
touchArea.addEventListener("touchmove", (e) => {
e.preventDefault();
console.log("Touch moved");
});
/**
* Event listener for the 'touchend' event.
* Triggered when a user lifts their finger from the screen.
* @param {TouchEvent} e - The touch event object.
*/
touchArea.addEventListener("touchend", (e) => {
e.preventDefault();
console.log("Touch ended");
});
/**
* Event listener for the 'touchcancel' event.
* Triggered when a touch event is interrupted, e.g., by an incoming call.
* @param {TouchEvent} e - The touch event object.
*/
touchArea.addEventListener("touchcancel", (e) => {
e.preventDefault();
console.log("Touch cancelled");
});
</script>
</body>
</html>Each listener calls preventDefault() to stop the browser’s built-in touch behavior, like scrolling or zooming, so your own handling takes over. Open the console on a phone or in device emulation and you’ll watch the events roll in as you drag a finger across the box.
Conclusion
That’s responsive design with JavaScript in one pass: build mobile-first so the essentials come first, let media queries handle the styling, reach for matchMedia() when you need logic tied to a breakpoint, and wire up touch events so the experience feels right under a thumb.
None of this is exotic. It’s the baseline for anything you ship now, because most of your traffic is already on a small screen. Test on a real phone early and often, not just by dragging your browser window narrow, and the surprises get a lot smaller.
What’s Next?
Day 8 puts these skills to work. We build a small ToDo app from scratch: adding tasks, marking them done, removing them, all through dynamic DOM updates. It’s the first point in this series where the pieces come together into a real, working thing you can actually use.


