- Responsive Design
- When to use this skill
- New website/app
-
- Layout design for combined mobile-desktop use
- Legacy improvement
-
- Converting fixed layouts to responsive
- Performance optimization
-
- Image optimization per device
- Multiple screens
- Tablet, desktop, and large screen support Instructions Step 1: Mobile-First Approach Design from small screens and progressively expand. Example : / Default: Mobile (320px~) / .container { padding : 1 rem ; font-size : 14 px ; } .grid { display : grid ; grid-template-columns : 1 fr ; gap : 1 rem ; } / Tablet (768px~) / @media ( min-width : 768 px ) { .container { padding : 2 rem ; font-size : 16 px ; } .grid { grid-template-columns : repeat ( 2 , 1 fr ) ; gap : 1.5 rem ; } } / Desktop (1024px~) / @media ( min-width : 1024 px ) { .container { max-width : 1200 px ; margin : 0 auto ; padding : 3 rem ; } .grid { grid-template-columns : repeat ( 3 , 1 fr ) ; gap : 2 rem ; } } / Large screen (1440px~) / @media ( min-width : 1440 px ) { .grid { grid-template-columns : repeat ( 4 , 1 fr ) ; } } Step 2: Flexbox/Grid Layout Leverage modern CSS layout systems. Flexbox (1-dimensional layout): / Navigation bar / .navbar { display : flex ; justify-content : space-between ; align-items : center ; flex-wrap : wrap ; } / Card list / .card-list { display : flex ; flex-direction : column ; gap : 1 rem ; } @media ( min-width : 768 px ) { .card-list { flex-direction : row ; flex-wrap : wrap ; } .card { flex : 1 1 calc ( 50 % - 0.5 rem ) ; / 2 columns / } } @media ( min-width : 1024 px ) { .card { flex : 1 1 calc ( 33.333 % - 0.667 rem ) ; / 3 columns / } } CSS Grid (2-dimensional layout): / Dashboard layout / .dashboard { display : grid ; grid-template-areas : "header" "sidebar" "main" "footer" ; gap : 1 rem ; } @media ( min-width : 768 px ) { .dashboard { grid-template-areas : "header header" "sidebar main" "footer footer" ; grid-template-columns : 250 px 1 fr ; } } @media ( min-width : 1024 px ) { .dashboard { grid-template-columns : 300 px 1 fr ; } } .header { grid-area : header ; } .sidebar { grid-area : sidebar ; } .main { grid-area : main ; } .footer { grid-area : footer ; } Step 3: Responsive Images Provide images suited to the device. Using srcset : < img src = " image-800.jpg " srcset = " image-400.jpg 400w, image-800.jpg 800w, image-1200.jpg 1200w, image-1600.jpg 1600w " sizes = " (max-width: 600px) 100vw, (max-width: 900px) 50vw, 33vw " alt = " Responsive image " /> picture element (Art Direction): < picture
< source media = " (max-width: 767px) " srcset = " portrait.jpg "
< source media = " (max-width: 1023px) " srcset = " square.jpg "
- <
- img
- src
- =
- "
- landscape.jpg
- "
- alt
- =
- "
- Art direction example
- "
- >
- </
- picture
- >
- CSS background images
- :
- .hero
- {
- background-image
- :
- url
- (
- 'hero-mobile.jpg'
- )
- ;
- }
- @media
- (
- min-width
- :
- 768
- px
- )
- {
- .hero
- {
- background-image
- :
- url
- (
- 'hero-tablet.jpg'
- )
- ;
- }
- }
- @media
- (
- min-width
- :
- 1024
- px
- )
- {
- .hero
- {
- background-image
- :
- url
- (
- 'hero-desktop.jpg'
- )
- ;
- }
- }
- / Or use image-set() /
- .hero
- {
- background-image
- :
- image-set
- (
- url
- (
- 'hero-1x.jpg'
- )
- 1
- x
- ,
- url
- (
- 'hero-2x.jpg'
- )
- 2
- x
- )
- ;
- }
- Step 4: Responsive Typography
- Adjust text size based on screen size.
- clamp() function
- (fluid sizing):
- :root
- {
- / min, preferred, max /
- --font-size-body
- :
- clamp
- (
- 14
- px
- ,
- 2.5
- vw
- ,
- 18
- px
- )
- ;
- --font-size-h1
- :
- clamp
- (
- 24
- px
- ,
- 5
- vw
- ,
- 48
- px
- )
- ;
- --font-size-h2
- :
- clamp
- (
- 20
- px
- ,
- 4
- vw
- ,
- 36
- px
- )
- ;
- }
- body
- {
- font-size
- :
- var
- (
- --font-size-body
- )
- ;
- }
- h1
- {
- font-size
- :
- var
- (
- --font-size-h1
- )
- ;
- line-height
- :
- 1.2
- ;
- }
- h2
- {
- font-size
- :
- var
- (
- --font-size-h2
- )
- ;
- line-height
- :
- 1.3
- ;
- }
- Media query approach
- :
- body
- {
- font-size
- :
- 14
- px
- ;
- line-height
- :
- 1.6
- ;
- }
- @media
- (
- min-width
- :
- 768
- px
- )
- {
- body
- {
- font-size
- :
- 16
- px
- ;
- }
- }
- @media
- (
- min-width
- :
- 1024
- px
- )
- {
- body
- {
- font-size
- :
- 18
- px
- ;
- }
- }
- Step 5: Container Queries (New Feature)
- Apply styles based on parent container size.
- .card-container
- {
- container-type
- :
- inline-size
- ;
- container-name
- :
- card
- ;
- }
- .card
- {
- padding
- :
- 1
- rem
- ;
- }
- .card
- h2
- {
- font-size
- :
- 1.2
- rem
- ;
- }
- / When container is 400px or wider /
- @container
- card
- (
- min-width
- :
- 400
- px
- )
- {
- .card
- {
- display
- :
- grid
- ;
- grid-template-columns
- :
- 200
- px
- 1
- fr
- ;
- padding
- :
- 1.5
- rem
- ;
- }
- .card
- h2
- {
- font-size
- :
- 1.5
- rem
- ;
- }
- }
- / When container is 600px or wider /
- @container
- card
- (
- min-width
- :
- 600
- px
- )
- {
- .card
- {
- grid-template-columns
- :
- 300
- px
- 1
- fr
- ;
- padding
- :
- 2
- rem
- ;
- }
- }
- Output format
- Standard Breakpoints
- / Mobile (default): 320px ~ 767px /
- / Tablet: 768px ~ 1023px /
- / Desktop: 1024px ~ 1439px /
- / Large: 1440px+ /
- :root
- {
- --breakpoint-sm
- :
- 640
- px
- ;
- --breakpoint-md
- :
- 768
- px
- ;
- --breakpoint-lg
- :
- 1024
- px
- ;
- --breakpoint-xl
- :
- 1280
- px
- ;
- --breakpoint-2xl
- :
- 1536
- px
- ;
- }
- / Usage example /
- @media
- (
- min-width
- :
- 768
- px
- )
- {
- / Tablet /
- }
- @media
- (
- min-width
- :
- 1024
- px
- )
- {
- / Desktop /
- }
- Constraints
- Mandatory Rules (MUST)
- Viewport meta tag
-
- Must be included in HTML
- <
- meta
- name
- =
- "
- viewport
- "
- content
- =
- "
- width=device-width, initial-scale=1.0
- "
- >
- Mobile-First
-
- Mobile default, use min-width media queries
- ✅
- @media (min-width: 768px)
- ❌
- @media (max-width: 767px)
- (Desktop-first)
- Relative units
-
- Use rem, em, %, vw/vh instead of px
- font-size: rem
- padding/margin: rem or em
- width: % or vw
- Prohibited (MUST NOT)
- Fixed width prohibited
-
- Avoid
- width: 1200px
- Use
- max-width: 1200px
- Duplicate code
- Avoid repeating same styles across all breakpoints
Common styles as default, only differences in media queries
Examples
Example 1: Responsive Navigation
function
ResponsiveNav
(
)
{
const
[
isOpen
,
setIsOpen
]
=
useState
(
false
)
;
return
(
<
nav
className
=
"
navbar
"
{ / Logo / } < a href = " / " className = " logo "
MyApp </ a
{ / Hamburger button (mobile) / } < button className = " menu-toggle " onClick = { ( ) => setIsOpen ( ! isOpen ) } aria-label = " Toggle menu " aria-expanded = { isOpen }
< span
</ span
< span
</ span
< span
</ span
</ button
{ / Navigation links / } < ul className = {
nav-links ${ isOpen ? 'active' : '' }}< li
</ li
< li
</ li
< li
</ li
</ ul
</ nav
) ; } .navbar { display : flex ; justify-content : space-between ; align-items : center ; padding : 1 rem ; } / Hamburger button (mobile only) / .menu-toggle { display : flex ; flex-direction : column ; gap : 4 px ; } .nav-links { display : none ; position : absolute ; top : 60 px ; left : 0 ; right : 0 ; background : white ; flex-direction : column ; } .nav-links .active { display : flex ; } / Tablet and above: hide hamburger, always show / @media ( min-width : 768 px ) { .menu-toggle { display : none ; } .nav-links { display : flex ; position : static ; flex-direction : row ; gap : 2 rem ; } } Example 2: Responsive Grid Card function ProductGrid ( { products } ) { return ( < div className = " product-grid "
{ products . map ( product => ( < div key = { product . id } className = " product-card "
< img src = { product . image } alt = { product . name } /> < h3
{ product . name } </ h3
< p className = " price "
$ { product . price } </ p
< button
Add to Cart </ button
</ div
) ) } </ div
) ; } .product-grid { display : grid ; grid-template-columns : 1 fr ; / Mobile: 1 column / gap : 1 rem ; padding : 1 rem ; } @media ( min-width : 640 px ) { .product-grid { grid-template-columns : repeat ( 2 , 1 fr ) ; / 2 columns / } } @media ( min-width : 1024 px ) { .product-grid { grid-template-columns : repeat ( 3 , 1 fr ) ; / 3 columns / gap : 1.5 rem ; } } @media ( min-width : 1440 px ) { .product-grid { grid-template-columns : repeat ( 4 , 1 fr ) ; / 4 columns / gap : 2 rem ; } } .product-card { border : 1 px solid
ddd
- ;
- border-radius
- :
- 8
- px
- ;
- padding
- :
- 1
- rem
- ;
- }
- .product-card
- img
- {
- width
- :
- 100
- %
- ;
- height
- :
- auto
- ;
- aspect-ratio
- :
- 1
- /
- 1
- ;
- object-fit
- :
- cover
- ;
- }
- Best practices
- Container queries first
-
- Use container queries instead of media queries when possible
- Flexbox vs Grid
-
- Flexbox for 1-dimensional, Grid for 2-dimensional
- Performance
-
- Image lazy loading, use WebP format
- Testing
-
- Chrome DevTools Device Mode, BrowserStack
- References
- MDN Responsive Design
- CSS Grid Guide
- Flexbox Guide
- Container Queries
- Metadata
- Version
- Current Version
-
- 1.0.0
- Last Updated
-
- 2025-01-01
- Compatible Platforms
- Claude, ChatGPT, Gemini