What is Responsive Design?

Responsive design ensures that a website looks good and functions correctly on all devices — desktops, tablets, and mobile phones. It uses flexible layouts, scalable units, and media queries to adapt content to different screen sizes.

Quick Check

Desktop:
What should stay in a row?

Tablet:
What starts to feel cramped?

Mobile:
What should stack?
What should become one column?

Always:
content first → layout second
                    

Media Queries

Media queries apply CSS rules only when certain conditions are met, such as screen width. They are the foundation of responsive design.

A breakpoint is not:
"pick random widths"

A breakpoint is:
"the layout starts to feel wrong here"
                        
Two approaches:

Mobile-first  → write for small screens first, scale up with min-width
Desktop-first → write for large screens first, scale down with max-width

Mobile-first is recommended.
It forces you to start with what matters most.
                        
Approach Query Description
Mobile-first @media (min-width: 600px) Applies styles when screen is 600px or wider
Mobile-first @media (min-width: 768px) Applies styles at tablet width and above
Mobile-first @media (min-width: 1024px) Applies styles at desktop width and above
Desktop-first @media (max-width: 768px) Applies styles to tablets and smaller
Desktop-first @media (max-width: 480px) Applies styles to mobile only
Mobile-first example (min-width):

/* default — mobile */
.container {
    flex-direction: column;
}

/* tablet and up */
@media (min-width: 600px) {
    .container {
        flex-direction: row;
    }
}

Desktop-first example (max-width):

/* default — desktop */
.container {
    flex-direction: row;
}

@media (max-width: 600px) {
    .container {
        flex-direction: column;
    }
}
                        

Responsive Units

Responsive units scale with the screen size, making layouts more flexible and adaptive.

%   → based on parent
vw  → based on viewport width
vh  → based on viewport height
rem → based on root font size

Rule:
avoid relying on fixed px for everything
                        
Unit Description Example
% Percentage of the parent element. width: 50%;
vw Viewport width (1vw = 1% of screen width). font-size: 5vw;
vh Viewport height (1vh = 1% of screen height). height: 50vh;
rem Scales with root font size. padding: 2rem;
clamp() Sets a min, preferred, and max value. font-size: clamp(1rem, 2vw, 2rem);
Useful:
font-size: clamp(1rem, 2vw, 2rem);
                        

Flexbox for Responsive Layouts

Flexbox provides a flexible layout model that adapts naturally to different screen sizes. It is ideal for navigation bars, card layouts, and content alignment.

Main Axis vs Cross Axis

flex-direction: row;         flex-direction: column;

Main axis  → left ↔ right    Main axis  → top ↕ bottom
Cross axis → top  ↕ bottom   Cross axis → left ↔ right
                        
Desktop:
[ item ][ item ][ item ]

Mobile:
[ item ]
[ item ]
[ item ]
                        
Property Description Example
display: flex Enables flexbox layout. div { display: flex; }
flex-wrap Allows items to wrap onto new lines. flex-wrap: wrap;
justify-content Controls horizontal alignment. justify-content: space-between;
align-items Controls vertical alignment. align-items: center;
flex-direction Controls the direction of items. flex-direction: column;

Use justify-content to control alignment along the main axis in flexbox. justify-content

CSS Grid for Responsive Layouts

CSS Grid is a powerful layout system that allows you to create complex, responsive two-dimensional layouts with ease.

Important: display: grid; does not automatically create multiple columns.

Default = 1 column If I do not define columns, items stack vertically.

Grid item sizing:

Grid items stretch to fill their grid area by default.

2 columns = each item has less space
1 column = each item has more space

If a child gets wider on mobile, it is usually because the grid track became wider.

Grid alignment:

justify-items → parent controls all grid children
justify-self  → one child controls itself

Rule:
Use the parent for default behaviour.
Use the child only for exceptions.
Desktop:
[ 1 ][ 2 ][ 3 ]

Tablet:
[ 1 ][ 2 ]
[ 3 ]

Mobile:
[ 1 ]
[ 2 ]
[ 3 ]
                        
Property Description Example
display: grid Enables grid layout. div { display: grid; }
grid-template-columns Defines column structure. grid-template-columns: 1fr 1fr;
grid-template-rows Defines rows structure.
It's a space for the separator.
grid-template-rows: 1fr 1fr;
grid-area Shorthand to place an item by row and column in one line: row-start / col-start / row-end / col-end. Can also name an area defined in grid-template-areas. grid-area: 1 / 1 / 3 / 3;
gap Controls spacing between grid items. One value sets both. Two values set row then column — use a space not a comma: gap: 10px 5px not gap: 10px, 5px gap: 20px;
gap: 10px 5px;
repeat() Repeats column or row patterns. grid-template-columns: repeat(3, 1fr);
minmax() Sets a size range for grid tracks. minmax(200px, 1fr)
Useful pattern:
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
                        

Responsive layout decisions from real projects

One container = one job

A section container should handle overall structure. A wrapper inside it should handle the layout of repeated items. Each card or item should handle its own internal content.

When to use align-self

Use align-self when one flex child needs different cross-axis alignment from its siblings.

Example use cases:

  • A nav block aligned differently from a heading in the same flex container
  • One card or button positioned differently from the rest

Width, max-width, and percentages

  • max-width limits how large something can become
  • width: 100% makes an element fill its parent
  • Percentage widths on cards control how much of a row each item takes

If you want exactly 3 cards per row, a percentage-based width is often a better choice than max-width alone.

Breakpoints are discovered, not guessed

Test the layout and see where it actually breaks. The true breakpoint is the point where the design stops fitting comfortably.

Responsive image pattern

  • Use a wrapper to limit the image block width
  • Center the wrapper if needed
  • Make the image scale to the wrapper

Gallery card pattern

For galleries and repeated cards:

  • The wrapper usually controls row and wrap behavior
  • Each card controls its share of the row
  • The image fills the card width

Common Responsive Patterns

These layout patterns are frequently used to create responsive websites that adapt smoothly across devices.

Gallery / cards:
Desktop → 3 across
Tablet  → 2 across
Mobile  → 1 across

Text + image:
Desktop → side by side
Mobile  → stacked

Navigation:
Desktop → row
Mobile  → wrap / stack / simplify
                        
Pattern Description Example
Stacking Columns Columns become rows on smaller screens. @media (max-width: 768px) { flex-direction: column; }
Responsive Navigation Nav collapses or stacks on mobile. @media (max-width: 600px) { nav a { display: block; } }
Fluid Typography Text scales with viewport size. font-size: clamp(1rem, 2vw, 2rem);
Auto-Fit Grid Grid items fill available space. grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));

Responsive Images

Images are part of responsive layout too. If an image looks wrong, check the container first, then check how the image fits inside it.

Container first
Image second

If image looks too small:
→ maybe too many columns

If image looks awkward:
→ check crop area / fit / container width
                    
Idea Description Example
Fluid width Image scales with its container. width: 100%;
Keep ratio Avoid distortion when resizing. height: auto;
Crop intentionally Control how the image fills a box. object-fit: cover;
Choose visible area Keep the important part of the image in view. object-position: center;

Fast Reminders

Layout breaking?
→ what should stack?

Tablet awkward?
→ it may need its own layout decision

Gallery looks too tight?
→ reduce columns

Images look wrong?
→ check the container first

Responsive not working?
→ check breakpoint width

Desktop works but mobile doesn't?
→ reduce, stack, simplify