DEV Community

Cover image for CSS Architecture
koushikmaya
koushikmaya

Posted on

CSS Architecture

Responsive CSS: From Mobile-First Design to Modern Styling

Responsive design is about creating websites that work well across mobile, tablet, and desktop screens. In this post, I learned some important techniques for building responsive and maintainable CSS.

1. Mobile-First Media Queries

Mobile-first means writing the base CSS for smaller screens first and then enhancing the layout for larger screens.

/* Mobile */
.card {
    width: 100%;
}

/* Tablet */
@media (min-width: 768px) {
    .card {
        width: 70%;
    }
}

/* Desktop */
@media (min-width: 1024px) {
    .card {
        width: 50%;
    }
}
Enter fullscreen mode Exit fullscreen mode

The main idea is:

Mobile → Tablet → Desktop

min-width is commonly used for mobile-first development because styles are progressively added as the screen gets larger.

min-width vs max-width

  • min-width: applies styles when the screen is at least the specified width.
  • max-width: applies styles when the screen is at most the specified width.

For example:

@media (max-width: 768px) {
    h1 {
        font-size: 20px;
    }
}
Enter fullscreen mode Exit fullscreen mode

One important lesson I learned: CSS media queries belong inside <style> or a CSS file, not inside <script>.

2. Fluid Typography

Fixed font sizes don't always work well across different screen sizes. Fluid typography allows text to adapt to the viewport.

rem

rem is relative to the root font size.

h1 {
    font-size: 2rem;
}
Enter fullscreen mode Exit fullscreen mode

If the root size is 16px, 2rem is 32px.

vw

vw is relative to the viewport width.

h1 {
    font-size: 5vw;
}
Enter fullscreen mode Exit fullscreen mode

However, using only vw can make text too small or too large.

clamp()

clamp() provides a minimum, flexible value, and maximum:

h1 {
    font-size: clamp(1.5rem, 4vw, 3rem);
}
Enter fullscreen mode Exit fullscreen mode

This allows the font size to grow smoothly while keeping it within limits.

3. Responsive Images

Images can consume a lot of bandwidth, so responsive images help browsers choose an appropriate image for the device.

srcset

<img
    src="small.jpg"
    srcset="
        small.jpg 400w,
        medium.jpg 800w,
        large.jpg 1200w"
    sizes="100vw"
    alt="Mountain">
Enter fullscreen mode Exit fullscreen mode

srcset provides multiple image sizes, allowing the browser to choose an appropriate resource.

<picture>

picture is useful when different images should be displayed at different screen sizes.

<picture>
    <source
        media="(min-width: 1000px)"
        srcset="desktop.jpg">
    <source
        media="(min-width: 600px)"
        srcset="tablet.jpg">
    <img src="mobile.jpg" alt="Nature">
</picture>
Enter fullscreen mode Exit fullscreen mode

4. BEM Naming Convention

BEM stands for:
Block → Element → Modifier
It helps keep CSS class names organized and reduces naming conflicts.

<div class="card card--dark">
    <img class="card__image">
    <h2 class="card__title">
        Product
    </h2>
    <p class="card__text">
        Description
    </p>
</div>
Enter fullscreen mode Exit fullscreen mode

The structure is:

Block
.card
Element
.card__title
Modifier
.card--dark
Enter fullscreen mode Exit fullscreen mode

BEM makes larger CSS projects easier to understand and maintain.

5. Utility-First Styling

Utility-first CSS uses small, reusable classes to build a component.
A popular example is Tailwind CSS:

<button class="bg-blue-500 text-white p-4 rounded">
    Submit
</button>
Enter fullscreen mode Exit fullscreen mode

Each utility generally performs a specific styling job.

Advantages

  • Fast development
  • Reusable utility classes
  • Consistent styling
  • Less custom CSS ### Disadvantage HTML can become crowded with many classes. --- ## 6. Component-Scoped Styling CSS Modules are an example of component-scoped styling.
/* Button.module.css */
.button {
    background: blue;
    color: white;
    padding: 10px;
}
Enter fullscreen mode Exit fullscreen mode

Then in a component:

import styles from "./Button.module.css";
function Button() {
    return (
        <button className={styles.button}>
            Submit
        </button>
    );
}
Enter fullscreen mode Exit fullscreen mode

The styles are scoped to the component, which helps prevent global CSS conflicts.

Utility-First vs CSS Modules

Feature Utility-First CSS Modules
Styling Utility classes Component CSS
HTML More classes Cleaner
Scope Utilities Component-scoped
Development Very fast Structured
Best for Rapid UI development Component-based applications

Neither approach is universally better. The choice depends on the project's requirements, team preferences, and architecture.

Key Takeaways

From this topic, I learned:

  • Start responsive designs with a mobile-first approach.
  • Use min-width to progressively enhance layouts.
  • Use rem, vw, and especially clamp() for flexible typography.
  • Use srcset for different image sizes.
  • Use <picture> when different image sources are needed.
  • Use BEM to create structured and predictable CSS class names.
  • Utility-first CSS focuses on composing designs from small utility classes.
  • CSS Modules provide component-scoped styling.
  • Media queries are CSS, so they belong in <style> or .css files, not <script>. Responsive CSS is not just about making a website "fit" on different screens. It's about building layouts that adapt, remain accessible, perform well, and are easy to maintain.

Top comments (2)

Collapse
 
merbayerp profile image
Mustafa ERBAY

clamp() was one of those CSS features that changed how I think about responsive design. Once you start using it for typography and spacing, you realize you don’t need a media query for every small transition between screen sizes.

Nice learning summary. I’d add min(), max() and container queries to the list as good next steps — they fit really well with what you’ve covered here.

Collapse
 
koushikmaya profile image
koushikmaya

Thank you! 🙌 I completely agree — clamp() makes responsive styling much cleaner. I’ll definitely explore min(), max(), and container queries next. Appreciate the suggestions! 🚀