Responsive Design
Responsive Design Guidelines
Overview
Section titled “Overview”WEC Design System uses a mobile-first approach to ensure products work seamlessly across all device sizes. Our breakpoint system is based on common device widths used in the Indonesian market.
Breakpoints
Section titled “Breakpoints”Our standard breakpoint system follows Tailwind CSS defaults:
| Breakpoint | Min Width | Max Container | Target Devices |
|---|---|---|---|
xs | 0px | 100% | Small mobile (320px+) |
sm | 640px | 640px | Mobile landscape, large phones |
md | 768px | 768px | Tablet portrait (iPad) |
lg | 1024px | 1024px | Tablet landscape, small desktop |
xl | 1280px | 1280px | Desktop, laptops |
2xl | 1366px | 1440px | Large desktops |
Breakpoint Usage
Section titled “Breakpoint Usage”/* Mobile-first: Base styles apply to all screens */.card { padding: 16px; font-size: 14px;}
/* sm: 640px and up */@media (min-width: 640px) { .card { padding: 20px; }}
/* md: 768px and up */@media (min-width: 768px) { .card { padding: 24px; font-size: 16px; }}
/* lg: 1024px and up */@media (min-width: 1024px) { .card { padding: 32px; font-size: 18px; }}Mobile-First Approach
Section titled “Mobile-First Approach”Always design for mobile first, then enhance for larger screens.
/* Base styles for mobile */.component { flex-direction: column; padding: var(--spacing-4); font-size: var(--text-mobile-body2);}
/* Enhance for tablet */@media (min-width: 768px) { .component { flex-direction: row; padding: var(--spacing-6); font-size: var(--text-desktop-body2); }}
/* Enhance for desktop */@media (min-width: 1024px) { .component { padding: var(--spacing-10); }}Container Patterns
Section titled “Container Patterns”Content Wrapper
Section titled “Content Wrapper”.content-wrapper { width: 100%; margin: 0 auto; padding-left: 24px; /* Mobile */ padding-right: 24px;}
@media (min-width: 768px) { .content-wrapper { padding-left: 40px; /* Tablet */ padding-right: 40px; }}
@media (min-width: 1024px) { .content-wrapper { padding-left: 100px; /* Desktop */ padding-right: 100px; }}Max-Width Containers
Section titled “Max-Width Containers”| Container Type | Max Width | Usage |
|---|---|---|
.container-sm | 640px | Narrow content, forms |
.container-md | 768px | Medium content, articles |
.container-lg | 1024px | Wide content, dashboards |
.container-xl | 1440px | Maximum content width |
.container-sm { max-width: 640px; margin: 0 auto; }.container-md { max-width: 768px; margin: 0 auto; }.container-lg { max-width: 1024px; margin: 0 auto; }.container-xl { max-width: 1440px; margin: 0 auto; }Layout Patterns
Section titled “Layout Patterns”Single Column to Grid
Section titled “Single Column to Grid”// Mobile: Single column// Tablet: 2 columns// Desktop: 3-4 columns
<div className=" grid grid-cols-1 /* Mobile: 1 column */ md:grid-cols-2 /* Tablet: 2 columns */ lg:grid-cols-3 /* Desktop: 3 columns */ xl:grid-cols-4 /* Large: 4 columns */ gap-4 /* 16px gap */"> {items.map(item => ( <Card key={item.id}>{item.content}</Card> ))}</div>Collapsible Navigation
Section titled “Collapsible Navigation”// Mobile: Hamburger menu// Desktop: Always visible
<nav className="flex items-center justify-between p-4"> <Logo />
{/* Mobile menu button */} <button className="lg:hidden" onClick={toggleMenu}> <MenuIcon /> </button>
{/* Desktop navigation */} <ul className="hidden lg:flex gap-8"> <li><a href="/">Home</a></li> <li><a href="/packages">Packages</a></li> <li><a href="/help">Help</a></li> </ul></nav>
{/* Mobile menu drawer */}<MobileMenu isOpen={isMenuOpen} onClose={() => setIsMenuOpen(false)} />Horizontal Scrolling (Mobile)
Section titled “Horizontal Scrolling (Mobile)”// Mobile: Horizontal scroll// Desktop: Grid or flex
<div className=" flex overflow-x-auto gap-4 snap-x lg:grid lg:grid-cols-4 lg:overflow-visible"> {tabs.map(tab => ( <button key={tab.id} className="snap-start shrink-0 min-w-[120px]" > {tab.label} </button> ))}</div>Responsive Typography
Section titled “Responsive Typography”Type scale adjusts between mobile and desktop:
| Element | Mobile | Desktop | Scale |
|---|---|---|---|
| H1/Hero | 32px / 40px | 64px / 72px | 2.0x |
| H2/Title | 32px / 36px | 56px / 72px | 1.75x |
| H3/Section | 20px / 24px | 44px / 56px | 2.2x |
| H4/Subsection | 16px / 24px | 32px / 48px | 2.0x |
| H5/Card title | 18px / 24px | 24px / 32px | 1.33x |
| H6/Small heading | 18px / 24px | 18px / 24px | Same |
| Body | 14px / 24px | 18px / 32px | 1.28x |
| Secondary | 14px / 16px | 15px / 24px | 1.07x |
| Caption | 12px / 24px | 13px / 24px | 1.08x |
Responsive Typography Example
Section titled “Responsive Typography Example”.heading-primary { font-size: 32px; /* Mobile */ line-height: 40px; font-weight: 700;}
@media (min-width: 768px) { .heading-primary { font-size: 64px; /* Desktop */ line-height: 72px; }}Touch Targets
Section titled “Touch Targets”Ensure interactive elements are large enough for touch (minimum 44×44px):
| Element | Minimum Size | WEC Standard |
|---|---|---|
| Buttons | 44×44px | 48×48px recommended |
| Links | 44×44px | Add padding if text is small |
| Form inputs | 44px height | 48px height recommended |
| Checkboxes | 24×24px | With padding to 44px |
| Radio buttons | 24×24px | With padding to 44px |
Touch Target Examples
Section titled “Touch Target Examples”/* Icon button - full area touchable */.icon-button { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; padding: 12px; /* Creates space around icon */}
/* Text link - add padding for touch */.inline-link { display: inline-block; padding: 8px 12px; margin: -8px -12px; /* Negative margin prevents layout shift */}
/* Form input with adequate height */.form-input { height: 48px; padding: 12px 16px; font-size: 16px; /* Prevents iOS zoom */}Responsive Images
Section titled “Responsive Images”Use appropriate image sizes and formats:
// Responsive image with srcset<img src="package-card-mobile.jpg" srcSet=" package-card-mobile.jpg 640w, package-card-tablet.jpg 768w, package-card-desktop.jpg 1024w " sizes=" (max-width: 640px) 100vw, (max-width: 768px) 50vw, 33vw " alt="Combo Internet 50GB Package" loading="lazy"/>
// With Astro Image componentimport { Image } from 'astro:assets';
<Image src={packageImage} alt="Combo Internet Package" widths={[640, 768, 1024, 1440]} sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, 33vw" loading="lazy"/>Common Responsive Patterns
Section titled “Common Responsive Patterns”Navigation
Section titled “Navigation”// Mobile: Bottom tab bar or hamburger menu// Desktop: Top navigation bar
<nav className=" fixed bottom-0 left-0 right-0 /* Mobile: bottom bar */ lg:static lg:top-0 /* Desktop: top bar */ bg-white border-t lg:border-t-0 lg:border-b z-50"> <div className="flex justify-around lg:justify-between lg:gap-8"> {/* Nav items */} </div></nav>.package-card { /* Mobile: Full width */ width: 100%; padding: 16px; border-radius: 12px 12px 0 0;}
@media (min-width: 768px) { .package-card { /* Tablet: Fixed width with gap */ width: calc(50% - 12px); padding: 20px; border-radius: 16px 16px 0 0; }}
@media (min-width: 1024px) { .package-card { /* Desktop: Fixed width */ width: 320px; padding: 24px; border-radius: 20px 20px 0 0; }}Tables
Section titled “Tables”// Mobile: Card view or horizontal scroll// Desktop: Full table
<div className="overflow-x-auto lg:overflow-visible"> <table className="w-full min-w-[600px] lg:min-w-0"> <thead> <tr> <th>Package</th> <th>Quota</th> <th>Price</th> <th>Action</th> </tr> </thead> <tbody> {/* Table rows */} </tbody> </table></div>Modals
Section titled “Modals”.modal-content { /* Mobile: Full screen or bottom sheet */ position: fixed; bottom: 0; left: 0; right: 0; border-radius: 20px 20px 0 0; max-height: 90vh;}
@media (min-width: 768px) { .modal-content { /* Desktop: Centered modal */ bottom: auto; left: 50%; right: auto; transform: translateX(-50%); width: 100%; max-width: 500px; border-radius: 20px; }}.form { /* Mobile: Single column */ display: flex; flex-direction: column; gap: 16px;}
@media (min-width: 768px) { .form { /* Desktop: Two columns */ display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }}
.form-full-width { /* Span full width on all screens */ grid-column: 1 / -1;}Container Padding (WEC Standard)
Section titled “Container Padding (WEC Standard)”Responsive padding for main content containers:
| Breakpoint | Padding |
|---|---|
| Mobile (< 768px) | 24px |
| Tablet (768px - 1024px) | 40px |
| Desktop (1024px+) | 100px |
.content-wrapper { padding-left: 24px; padding-right: 24px;}
@media (min-width: 768px) { .content-wrapper { padding-left: 40px; padding-right: 40px; }}
@media (min-width: 1024px) { .content-wrapper { padding-left: 100px; padding-right: 100px; }}Responsive Utilities
Section titled “Responsive Utilities”Hide/Show by Breakpoint
Section titled “Hide/Show by Breakpoint”/* Mobile only */.hidden { display: none; }.block { display: block; }.flex { display: flex; }
/* Show on sm and up */@media (min-width: 640px) { .sm\:hidden { display: none; } .sm\:block { display: block; } .sm\:flex { display: flex; }}
/* Show on md and up */@media (min-width: 768px) { .md\:hidden { display: none; } .md\:block { display: block; } .md\:flex { display: flex; }}
/* Show on lg and up */@media (min-width: 1024px) { .lg\:hidden { display: none; } .lg\:block { display: block; } .lg\:flex { display: flex; }}Tailwind Responsive Classes
Section titled “Tailwind Responsive Classes”// Hide on mobile, show on desktop<div className="hidden lg:block"> Desktop content</div>
// Show on mobile, hide on desktop<div className="block lg:hidden"> Mobile content</div>
// Different layouts by screen size<div className="flex flex-col md:flex-row lg:flex-row"> <div>Content 1</div> <div>Content 2</div></div>Testing
Section titled “Testing”Test your designs on these devices:
| Device | Width | Type |
|---|---|---|
| iPhone SE | 375px | Small mobile |
| iPhone 12/13 | 390px | Standard mobile |
| iPhone 14 Pro Max | 430px | Large mobile |
| iPad | 768px | Tablet portrait |
| iPad Pro | 1024px | Tablet landscape |
| Laptop | 1366px | Desktop |
| Large desktop | 1920px | Large screen |
Browser DevTools
Section titled “Browser DevTools”- Open DevTools (F12)
- Click device toolbar button (Ctrl+Shift+M)
- Select device or enter custom dimensions
- Test touch simulation
Testing Checklist
Section titled “Testing Checklist”- Test on 375px (small mobile)
- Test on 768px (tablet)
- Test on 1024px (desktop)
- Test touch targets (44×44px minimum)
- Test horizontal scroll behavior
- Test font sizes (minimum 14px)
- Test form inputs (no zoom on focus)
- Test navigation (mobile menu vs desktop)
Performance Considerations
Section titled “Performance Considerations”Mobile Performance
Section titled “Mobile Performance”- Lazy load images below the fold
- Use WebP format with JPEG fallback
- Minify CSS and JavaScript
- Optimize font loading (preload critical fonts)
- Reduce CLS (Cumulative Layout Shift)
<!-- Preload critical fonts --><link rel="preload" href="/fonts/poppins-regular.woff2" as="font" type="font/woff2" crossorigin>
<!-- Lazy load images --><img src="placeholder.jpg" data-src="actual.jpg" loading="lazy" alt="...">
<!-- Responsive images --><picture> <source srcset="image.webp" type="image/webp"> <source srcset="image.jpg" type="image/jpeg"> <img src="image.jpg" alt="..." loading="lazy"></picture>Best Practices
Section titled “Best Practices”| ✅ Do | ❌ Don’t |
|---|---|
| Use mobile-first approach | Design desktop-first |
| Test on real devices | Only use browser emulation |
| Use relative units (rem, %) | Use fixed pixels everywhere |
| Ensure 44×44px touch targets | Make buttons smaller than 44px |
| Use responsive images | Use full-size images on mobile |
| Optimize for performance | Load everything upfront |
| Test text readability | Use tiny fonts on mobile |
| Consider landscape mode | Only test portrait |