Thursday, February 5, 2026

Struggles and Learning Lessons with Responsive Design (React + CSS)

 

CSS Struggles: Lessons Learned from Building a Large Responsive App

Through me traversing online, in forums and discussing with others, CSS has been known to be a real pain point for developers in general. For me, I have always had moments of frustration with bugs that never seem obvious, and I have wasted tens of hours in the past trying to simply align two containers or correct an overflow problem. There is a plethora of problems that can arise when CSS begins to get extensive and you simply haven’t done the homework for what all the different properties do within the cascading nature of containers and their children elements.

I wanted to write this blog to help myself identify the struggles I’ve had with responsive design specifically, but in general I could always use more conceptual understanding, as CSS tends to be more abstract than the systematic nature of other languages.


Setting up Backend First, Then Frontend

When making a web application, specifically with a backend using something such as a REST API, it is best to first do the business logic (backend) before doing any design. The order I’ve usually proceeded with my previous projects is first setting up my models, routes, and controllers, then using something like Postman to test HTTP requests, emulating client-side behavior so I can test responses from my REST API.

The bits of information requested and returned from the frontend are sent securely through HTTP headers, and some information is then dynamically displayed for users. So essentially, once I have my backend logic (controllers, routes, models) set up and tested, and I am getting the data I need, I can start worrying about the frontend and how I want to modularize my components.

React offers components which act like normal functions whose purpose is to serve individual blocks of JSX/HTML, where I can give each their own hooks and state variables, although you usually want to mount what you can to parent components. Components pair nicely with CSS Modules, but this is something that needs to be used with care and discipline. Even on my most recent project, I made the mistake of not creating enough CSS modules to keep code organized. The modules I did have still ended up being over a thousand lines, which caused trouble with disorganization and identifying bugs.


The Real Issue: Design Responsibility

Overall, the main issue I had while working on RetroGamingAtlas was design responsibility. The core idea is that I should’ve set up and relied more on :root token variables, separating layout-related tokens (spacing, padding, gap, typography) and design tokens (colors, borders, etc.) into their own files.

Instead of hard coding values for every component, using preset tokens would have made everything more cohesive for mobile responsiveness and easier to develop against. These tokens could also be tested early using Chrome DevTools after creating container shells, confirming mobile responsiveness sooner rather than later.

For parent containers, I should have focused on setting layout constraints such as max-width, padding, gap, alignment, and grid or flex rules, keeping in mind to rely on max-width so views don’t break and can instead adapt to different screen sizes. Child elements then take on the behavior of those constraints, such as shrinking or growing, maintaining aspect ratios, minimum sizes, and handling overflow.

Setting heights should generally be avoided and should instead be content driven, using padding and gap where possible. I realized that I was setting my dimensions in the wrong places at times, where both parent and child components had fixed sizes. This led me to add unnecessary media queries. I should have been thinking less in terms of nudging things into place and more in terms of constraining layouts properly.

Another realization I had was that many responsive issues were not actually caused by missing breakpoints, but by missing default layout behavior. Defaulting to fluid widths using width: 100% and max-width, letting content dictate height, and handling overflow early would have prevented a lot of issues I tried to solve later with media queries.

Properties like min-width: 0 are useful for containers that contain text, and using aspect-ratio for media elements works far better than hard coding heights. Clamp also proved useful, particularly for typography and spacing, where fluid scaling makes more sense.


What I’d Do Differently Next Time

What I want to remember next time before starting a large-scale project is to default to fluid widths using width:100% and max-width, rely on gap with flexbox or grid for internal spacing, and avoid setting heights unless absolutely necessary. Media elements should rely on aspect ratios, and text containers should account for overflow early on.

I would also define preset tokens earlier and potentially create React layout primitive components such as Shell for horizontal padding and width constraints, Stack for vertical spacing, Cluster for horizontal grouping like tags, and Grid or Card components. These primitives would allow me to insert components with more confidence, knowing they will respond correctly to parent containers, and they could be reused across projects if needed.


Closing Thoughts

CSS stopped feeling random once I started treating it as a system rather than a series of fixes. By separating tokens from layout behavior, defining clearer responsibility between parent and child elements, and relying more on intrinsic layouts instead of forced dimensions, responsive design became far more predictable, especially on mobile.

This project didn’t just improve my CSS skills, it changed how I think about UI architecture overall.

No comments:

Post a Comment