CSS Viewport Units
Master viewport-relative units for creating truly responsive designs that adapt to any screen size
What are CSS Viewport Units?
CSS viewport units are length units that are relative to the size of the viewport—the visible area of a web page. Unlike fixed units like pixels, viewport units scale dynamically with the browser window size, making them perfect for responsive design.
These units enable you to create layouts that truly adapt to any screen size, from mobile phones to ultra-wide desktop monitors, without relying solely on media queries.
The Four Viewport Units:
- vw (Viewport Width): 1vw = 1% of viewport width
- vh (Viewport Height): 1vh = 1% of viewport height
- vmin (Viewport Minimum): 1vmin = 1% of the smaller viewport dimension
- vmax (Viewport Maximum): 1vmax = 1% of the larger viewport dimension
Why Use Viewport Units?
- Create truly fluid, scalable designs
- Reduce dependency on media queries
- Build full-height sections easily
- Scale typography smoothly across devices
- Maintain consistent proportions on any screen
Understanding Each Viewport Unit
vw - Viewport Width
This element is 50vw wide (50% of viewport width). It scales proportionally as you resize your browser horizontally.
vh - Viewport Height
This element has a height of 30vh (shown as 120px here for demo). Perfect for full-screen sections and vertical spacing.
vmin - Viewport Minimum
Always 20% of the smaller viewport dimension. Great for maintaining square aspect ratios on any screen orientation.
vmax - Viewport Maximum
Always 15% of the larger viewport dimension. Useful for elements that should never become too dominant.
Practical Applications
1. Responsive Typography
Create text that scales smoothly without media queries:
2. Full-Height Sections
Create sections that always fill the viewport height:
3. Responsive Spacing
Use viewport units for padding and margins that scale with screen size:
Best Practices & Common Pitfalls
Best Practices
- Use clamp() to set minimum and maximum bounds
- Test on multiple screen sizes and orientations
- Combine viewport units with other units for flexibility
- Use vmin/vmax for maintaining aspect ratios
- Consider accessibility and user zoom preferences
- Set reasonable minimum sizes for text
- Use rem units for minimum values in clamp()
Common Pitfalls
- Text becoming too small on mobile devices
- Elements becoming too large on wide screens
- Ignoring browser zoom functionality
- Using viewport units for all measurements
- Not testing on actual devices
- Forgetting about landscape orientation on mobile
- Mobile browser address bar affecting 100vh
Modern Approach: clamp() Function
The best practice is to combine viewport units with the clamp() function for controlled responsiveness:
Browser Support & Compatibility
Excellent Browser Support
Viewport units have excellent support across all modern browsers since 2013. They're safe to use in production!
Desktop Browsers
- Chrome 20+ ✓
- Firefox 19+ ✓
- Safari 6+ ✓
- Edge (all versions) ✓
- IE 9+ (partial support) ⚠️
Mobile Browsers
- iOS Safari 6+ ✓
- Android Browser 4.4+ ✓
- Chrome Mobile ✓
- Samsung Internet ✓
- Firefox Mobile ✓
Mobile Considerations
On mobile devices, the browser UI (address bar, etc.) can show/hide, affecting 100vh calculations. Consider using min-height instead of height for full-screen sections, or use the new dynamic viewport units (dvh) when supported.
Complete Viewport Units Example
Interactive Viewport Demo
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>CSS Viewport Units Tutorial</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } :root { --primary-color: #667eea; --secondary-color: #764ba2; --accent-color: #f093fb; --success-color: #4facfe; --warning-color: #43e97b; --danger-color: #fa709a; --dark-color: #2d3748; --light-color: #f7fafc; --text-color: #2d3748; --text-light: #fff; --border-color: #e2e8f0; --spacing-xs: 0.25rem; --spacing-sm: 0.5rem; --spacing-md: 1rem; --spacing-lg: 1.5rem; --spacing-xl: 2rem; --spacing-xxl: 3rem; --border-radius: 0.5rem; --shadow: 0 4px 6px rgba(0, 0, 0, 0.1); --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.15); --transition: all 0.3s ease; --font-main: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; --font-mono: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, monospace; } body { font-family: var(--font-main); line-height: 1.6; color: var(--text-color); background: linear-gradient(135deg, var(--light-color) 0%, #ffffff 100%); overflow-x: hidden; } /* Header with viewport height */ .hero-section { height: 100vh; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); color: var(--text-light); text-align: center; position: relative; } .hero-content h1 { font-size: clamp(2rem, 8vw, 5rem); margin-bottom: 1rem; font-weight: bold; } .hero-content p { font-size: clamp(1rem, 3vw, 1.5rem); margin-bottom: 2rem; opacity: 0.9; } .scroll-indicator { position: absolute; bottom: 2rem; left: 50%; transform: translateX(-50%); animation: bounce 2s infinite; } @keyframes bounce { 0%, 20%, 50%, 80%, 100% { transform: translateX(-50%) translateY(0); } 40% { transform: translateX(-50%) translateY(-10px); } 60% { transform: translateX(-50%) translateY(-5px); } } .container { max-width: 1200px; margin: 0 auto; padding: 0 var(--spacing-md); } /* Section Styles */ .section { background: white; border-radius: var(--border-radius); padding: var(--spacing-xl); margin: var(--spacing-xl) 0; box-shadow: var(--shadow); } h2 { font-size: clamp(1.5rem, 4vw, 2.5rem); color: var(--dark-color); margin-bottom: var(--spacing-lg); padding-bottom: var(--spacing-sm); border-bottom: 3px solid var(--primary-color); } h3 { font-size: clamp(1.2rem, 3vw, 1.75rem); color: var(--dark-color); margin: var(--spacing-lg) 0 var(--spacing-md); } p { margin-bottom: var(--spacing-md); line-height: 1.7; } /* Demo Containers */ .demo-container { background: var(--light-color); border-radius: var(--border-radius); padding: var(--spacing-lg); margin: var(--spacing-lg) 0; border: 2px solid var(--border-color); position: relative; } .demo-label { position: absolute; top: -10px; left: var(--spacing-md); background: var(--primary-color); color: var(--text-light); padding: var(--spacing-xs) var(--spacing-sm); border-radius: var(--border-radius); font-size: 0.875rem; font-weight: bold; } /* Viewport Width Demos */ .vw-demo { width: 50vw; height: 100px; background: linear-gradient(45deg, var(--success-color), var(--warning-color)); display: flex; align-items: center; justify-content: center; color: var(--text-light); font-weight: bold; border-radius: var(--border-radius); margin: var(--spacing-md) 0; } .vh-demo { width: 100%; height: 50vh; background: linear-gradient(45deg, var(--danger-color), var(--accent-color)); display: flex; align-items: center; justify-content: center; color: var(--text-light); font-weight: bold; border-radius: var(--border-radius); margin: var(--spacing-md) 0; flex-direction: column; } .vmin-demo { width: 30vmin; height: 30vmin; background: linear-gradient(45deg, var(--primary-color), var(--secondary-color)); display: flex; align-items: center; justify-content: center; color: var(--text-light); font-weight: bold; border-radius: var(--border-radius); margin: var(--spacing-md) auto; } .vmax-demo { width: 20vmax; height: 10vmax; background: linear-gradient(45deg, var(--accent-color), var(--success-color)); display: flex; align-items: center; justify-content: center; color: var(--text-light); font-weight: bold; border-radius: var(--border-radius); margin: var(--spacing-md) auto; } /* Typography demos */ .viewport-text-demo { margin: var(--spacing-lg) 0; } .vw-text { font-size: 4vw; text-align: center; background: linear-gradient(45deg, var(--primary-color), var(--accent-color)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-weight: bold; margin: var(--spacing-md) 0; } .vh-text { font-size: 3vh; text-align: center; color: var(--secondary-color); font-weight: bold; margin: var(--spacing-md) 0; } .vmin-text { font-size: 5vmin; text-align: center; color: var(--success-color); font-weight: bold; margin: var(--spacing-md) 0; } .vmax-text { font-size: 3vmax; text-align: center; color: var(--danger-color); font-weight: bold; margin: var(--spacing-md) 0; } /* Comparison Grid */ .comparison-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--spacing-lg); margin: var(--spacing-lg) 0; } .comparison-item { background: white; border-radius: var(--border-radius); overflow: hidden; box-shadow: var(--shadow); transition: var(--transition); } .comparison-item:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); } .comparison-header { background: var(--primary-color); color: var(--text-light); padding: var(--spacing-md); text-align: center; font-weight: bold; } .comparison-body { padding: var(--spacing-md); } .comparison-demo { height: 100px; display: flex; align-items: center; justify-content: center; color: var(--text-light); font-weight: bold; border-radius: var(--border-radius); margin: var(--spacing-sm) 0; } .px-demo { width: 200px; background: #95a5a6; } .percent-demo { width: 80%; background: #3498db; } .vw-demo-small { width: 25vw; background: #e74c3c; } /* Practical Examples */ .sidebar-layout { display: flex; gap: var(--spacing-md); min-height: 60vh; margin: var(--spacing-lg) 0; } .sidebar { width: 25vw; min-width: 200px; background: var(--secondary-color); color: var(--text-light); padding: var(--spacing-lg); border-radius: var(--border-radius); } .main-content { flex: 1; background: var(--light-color); padding: var(--spacing-lg); border-radius: var(--border-radius); border: 2px solid var(--border-color); } /* Full-screen section */ .fullscreen-section { height: 100vh; background: linear-gradient(45deg, var(--accent-color), var(--success-color)); display: flex; align-items: center; justify-content: center; margin: var(--spacing-xl) 0; border-radius: var(--border-radius); color: var(--text-light); text-align: center; } .fullscreen-content h3 { font-size: 6vw; margin-bottom: var(--spacing-md); } .fullscreen-content p { font-size: 2vw; opacity: 0.9; } /* Code Block */ .code-block { background: #2d3748; color: #e2e8f0; padding: var(--spacing-lg); border-radius: var(--border-radius); overflow-x: auto; margin: var(--spacing-lg) 0; font-family: var(--font-mono); font-size: 0.875rem; line-height: 1.5; position: relative; } .code-comment { color: #68d391; font-style: italic; } .code-property { color: #63b3ed; } .code-value { color: #f6ad55; } /* Responsive adjustments */ @media (max-width: 768px) { .sidebar-layout { flex-direction: column; } .sidebar { width: 100%; min-width: unset; } .comparison-grid { grid-template-columns: 1fr; } .vw-text { font-size: 6vw; } .vh-text { font-size: 4vh; } } /* Viewport size indicator */ .viewport-indicator { position: fixed; top: var(--spacing-md); right: var(--spacing-md); background: var(--dark-color); color: var(--text-light); padding: var(--spacing-sm) var(--spacing-md); border-radius: var(--border-radius); font-family: var(--font-mono); font-size: 0.75rem; z-index: 1000; box-shadow: var(--shadow); } /* Dynamic content based on viewport */ .dynamic-content { padding: 5vw; text-align: center; background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1)); border-radius: var(--border-radius); margin: var(--spacing-lg) 0; } .dynamic-content h3 { font-size: clamp(1.5rem, 4vw, 3rem); margin-bottom: 2vw; } .dynamic-content p { font-size: clamp(1rem, 2vw, 1.25rem); line-height: 1.6; } /* Animation using viewport units */ .animated-box { width: 15vw; height: 15vw; min-width: 100px; min-height: 100px; background: linear-gradient(45deg, var(--primary-color), var(--accent-color)); border-radius: 50%; margin: 5vh auto; animation: float 6s ease-in-out infinite; } @keyframes float { 0%, 100% { transform: translateY(0px); } 50% { transform: translateY(-3vh); } } /* Button styles */ .btn { display: inline-block; padding: var(--spacing-sm) var(--spacing-lg); background: var(--primary-color); color: var(--text-light); border: none; border-radius: var(--border-radius); cursor: pointer; font-size: 0.875rem; font-weight: 600; margin-right: var(--spacing-sm); transition: var(--transition); text-decoration: none; } .btn:hover { background: var(--secondary-color); transform: translateY(-2px); box-shadow: var(--shadow); } .btn-copy { background: var(--success-color); } .btn-copy:hover { background: var(--warning-color); } </style> </head> <body> <!-- Viewport Size Indicator --> <div class="viewport-indicator"> <div id="viewport-size">Viewport: <span id="dimensions"></span></div> </div> <!-- Hero Section --> <section class="hero-section"> <div class="hero-content"> <h1>CSS Viewport Units</h1> <p>Master responsive design with viewport-relative units</p> <div class="scroll-indicator"> <svg width="30" height="30" viewBox="0 0 24 24" fill="currentColor"> <path d="M12 14l4-4h-3V2h-2v8H8l4 4zm0 3v5l-7-7h3V7h2v8h3l-7 7z"/> </svg> </div> </div> </section> <div class="container"> <!-- Introduction --> <section class="section"> <h2>Understanding Viewport Units</h2> <p> Viewport units are CSS length units that are relative to the size of the viewport—the visible area of a web page. Unlike fixed units like pixels, viewport units scale dynamically with the browser window size. </p> <p> These units are essential for creating truly responsive designs that adapt fluidly to any screen size, from mobile phones to large desktop monitors. </p> <div class="dynamic-content"> <h3>This content scales with your viewport!</h3> <p> The padding, font sizes, and spacing on this element all use viewport units. Try resizing your browser window to see how everything adjusts proportionally. </p> </div> </section> <!-- Viewport Unit Types --> <section class="section"> <h2>Types of Viewport Units</h2> <div class="comparison-grid"> <div class="comparison-item"> <div class="comparison-header">vw (Viewport Width)</div> <div class="comparison-body"> <p><strong>1vw = 1% of viewport width</strong></p> <div class="demo-container"> <div class="demo-label">50vw wide</div> <div class="vw-demo">50vw width</div> </div> <p>Perfect for elements that should scale with screen width.</p> </div> </div> <div class="comparison-item"> <div class="comparison-header">vh (Viewport Height)</div> <div class="comparison-body"> <p><strong>1vh = 1% of viewport height</strong></p> <div class="demo-container"> <div class="demo-label">50vh tall</div> <div class="vh-demo"> <span>50vh height</span> <small>Resize vertically to see changes</small> </div> </div> <p>Ideal for full-screen sections and vertical layouts.</p> </div> </div> <div class="comparison-item"> <div class="comparison-header">vmin (Viewport Minimum)</div> <div class="comparison-body"> <p><strong>1vmin = 1% of smaller dimension</strong></p> <div class="demo-container"> <div class="demo-label">30vmin square</div> <div class="vmin-demo">30vmin</div> </div> <p>Great for maintaining aspect ratios on any screen.</p> </div> </div> <div class="comparison-item"> <div class="comparison-header">vmax (Viewport Maximum)</div> <div class="comparison-body"> <p><strong>1vmax = 1% of larger dimension</strong></p> <div class="demo-container"> <div class="demo-label">20vmax × 10vmax</div> <div class="vmax-demo">20vmax × 10vmax</div> </div> <p>Useful for elements that should never get too large.</p> </div> </div> </div> </section> <!-- Typography with Viewport Units --> <section class="section"> <h2>Responsive Typography</h2> <p> Viewport units excel at creating typography that scales smoothly across devices without media queries. </p> <div class="viewport-text-demo"> <div class="vw-text">4vw Text (scales with width)</div> <div class="vh-text">3vh Text (scales with height)</div> <div class="vmin-text">5vmin Text (scales with smaller dimension)</div> <div class="vmax-text">3vmax Text (scales with larger dimension)</div> </div> <div class="code-block"> <span class="code-comment">/* Responsive typography without media queries */</span><br> .responsive-heading {<br> <span class="code-property">font-size</span>: <span class="code-value">4vw</span>; <span class="code-comment">/* Scales with viewport width */</span><br> }<br><br> .responsive-text {<br> <span class="code-property">font-size</span>: <span class="code-value">2vmin</span>; <span class="code-comment">/* Always readable on any orientation */</span><br> }<br><br> <span class="code-comment">/* Modern approach: combine with clamp() for better control */</span><br> .modern-responsive {<br> <span class="code-property">font-size</span>: <span class="code-value">clamp(1rem, 4vw, 3rem)</span>;<br> <span class="code-comment">/* min: 1rem, preferred: 4vw, max: 3rem */</span><br> } </div> </section> <!-- Practical Examples --> <section class="section"> <h2>Practical Applications</h2> <h3>1. Full-Height Sections</h3> <p>Create sections that always fill the viewport height:</p> <div class="code-block"> .hero-section {<br> <span class="code-property">height</span>: <span class="code-value">100vh</span>; <span class="code-comment">/* Full viewport height */</span><br> <span class="code-property">display</span>: <span class="code-value">flex</span>;<br> <span class="code-property">align-items</span>: <span class="code-value">center</span>;<br> <span class="code-property">justify-content</span>: <span class="code-value">center</span>;<br> } </div> <h3>2. Responsive Sidebars</h3> <p>Sidebars that maintain proportional width:</p> <div class="sidebar-layout"> <aside class="sidebar"> <h4>Sidebar (25vw)</h4> <p>This sidebar maintains 25% of viewport width with a minimum width of 200px.</p> </aside> <main class="main-content"> <h4>Main Content (flex: 1)</h4> <p>This main content area takes up the remaining space. The sidebar will always be 25% of the viewport width (with a minimum of 200px for usability).</p> </main> </div> <div class="code-block"> .sidebar {<br> <span class="code-property">width</span>: <span class="code-value">25vw</span>;<br> <span class="code-property">min-width</span>: <span class="code-value">200px</span>; <span class="code-comment">/* Prevent it from getting too small */</span><br> }<br><br> .main-content {<br> <span class="code-property">flex</span>: <span class="code-value">1</span>; <span class="code-comment">/* Takes remaining space */</span><br> } </div> <h3>3. Animated Elements</h3> <p>Animations that scale with viewport size:</p> <div class="animated-box"></div> <div class="code-block"> .animated-element {<br> <span class="code-property">width</span>: <span class="code-value">15vw</span>;<br> <span class="code-property">height</span>: <span class="code-value">15vw</span>;<br> <span class="code-property">animation</span>: <span class="code-value">float 6s ease-in-out infinite</span>;<br> }<br><br> @keyframes float {<br> 0%, 100% { <span class="code-property">transform</span>: <span class="code-value">translateY(0px)</span>; }<br> 50% { <span class="code-property">transform</span>: <span class="code-value">translateY(-3vh)</span>; }<br> } </div> </section> <!-- Comparison with Other Units --> <section class="section"> <h2>Viewport Units vs Other CSS Units</h2> <div class="comparison-grid"> <div class="comparison-item"> <div class="comparison-header">Pixels (px)</div> <div class="comparison-body"> <div class="comparison-demo px-demo">200px</div> <p><strong>Fixed size</strong> - Always 200 pixels regardless of screen size. Not responsive.</p> </div> </div> <div class="comparison-item"> <div class="comparison-header">Percentage (%)</div> <div class="comparison-body"> <div class="comparison-demo percent-demo">80%</div> <p><strong>Relative to parent</strong> - 80% of the parent container's width. Responsive to parent, not viewport.</p> </div> </div> <div class="comparison-item"> <div class="comparison-header">Viewport Width (vw)</div> <div class="comparison-body"> <div class="comparison-demo vw-demo-small">25vw</div> <p><strong>Relative to viewport</strong> - Always 25% of viewport width. Truly responsive to screen size.</p> </div> </div> </div> <div class="code-block"> <span class="code-comment">/* Comparison of different units */</span><br> .fixed-width { <span class="code-property">width</span>: <span class="code-value">300px</span>; } <span class="code-comment">/* Always 300px */</span><br> .percentage-width { <span class="code-property">width</span>: <span class="code-value">50%</span>; } <span class="code-comment">/* 50% of parent */</span><br> .viewport-width { <span class="code-property">width</span>: <span class="code-value">50vw</span>; } <span class="code-comment">/* 50% of viewport */</span><br> .relative-width { <span class="code-property">width</span>: <span class="code-value">20em</span>; } <span class="code-comment">/* 20 times font-size */</span> </div> </section> <!-- Best Practices --> <section class="section"> <h2>Best Practices and Common Pitfalls</h2> <div class="comparison-grid"> <div class="comparison-item" style="border: 2px solid var(--success-color);"> <div class="comparison-header" style="background: var(--success-color);">✅ Best Practices</div> <div class="comparison-body"> <ul style="list-style-type: disc; padding-left: 1.5rem; line-height: 1.8;"> <li>Use clamp() to set min/max bounds</li> <li>Test on multiple screen sizes</li> <li>Combine with other units for flexibility</li> <li>Use vmin/vmax for consistent aspect ratios</li> <li>Set reasonable minimum sizes</li> <li>Consider accessibility (Don't make text too small)</li> </ul> </div> </div> <div class="comparison-item" style="border: 2px solid var(--danger-color);"> <div class="comparison-header" style="background: var(--danger-color);">❌ Common Pitfalls</div> <div class="comparison-body"> <ul style="list-style-type: disc; padding-left: 1.5rem; line-height: 1.8;"> <li>Text becoming too small on mobile</li> <li>Elements becoming too large on big screens</li> <li>Ignoring browser zoom functionality</li> <li>Using viewport units for all measurements</li> <li>Not testing on actual devices</li> <li>Forgetting about landscape orientation</li> </ul> </div> </div> </div> <h3>Modern Approach: Combining with clamp()</h3> <p>The best practice is to combine viewport units with the clamp() function for controlled responsiveness:</p> <div class="code-block"> <span class="code-comment">/* ✅ Recommended: Controlled scaling */</span><br> .heading {<br> <span class="code-property">font-size</span>: <span class="code-value">clamp(1.5rem, 4vw, 3rem)</span>;<br> <span class="code-comment">/* Never smaller than 1.5rem, never larger than 3rem */</span><br> }<br><br> .container {<br> <span class="code-property">width</span>: <span class="code-value">clamp(300px, 90vw, 1200px)</span>;<br> <span class="code-comment">/* Responsive width with sensible bounds */</span><br> }<br><br> <span class="code-comment">/* ❌ Avoid: Uncontrolled scaling */</span><br> .bad-example {<br> <span class="code-property">font-size</span>: <span class="code-value">5vw</span>; <span class="code-comment">/* Could be tiny on mobile, huge on desktop */</span><br> } </div> </section> <!-- Browser Support and Compatibility --> <section class="section"> <h2>Browser Support & Compatibility</h2> <div style="background: var(--success-color); color: var(--text-light); padding: var(--spacing-lg); border-radius: var(--border-radius); margin-bottom: var(--spacing-lg);"> <h3 style="color: var(--text-light); margin-top: 0;">✅ Excellent Browser Support</h3> <p style="margin-bottom: 0;">Viewport units have excellent support across all modern browsers since 2013. Safe to use in production!</p> </div> <div class="comparison-grid"> <div class="comparison-item"> <div class="comparison-header">Desktop Browsers</div> <div class="comparison-body"> <ul style="list-style-type: none; padding: 0;"> <li>✅ Chrome 20+</li> <li>✅ Firefox 19+</li> <li>✅ Safari 6+</li> <li>✅ Edge (all versions)</li> <li>⚠️ IE 9+ (partial support)</li> </ul> </div> </div> <div class="comparison-item"> <div class="comparison-header">Mobile Browsers</div> <div class="comparison-body"> <ul style="list-style-type: none; padding: 0;"> <li>✅ iOS Safari 6+</li> <li>✅ Android Browser 4.4+</li> <li>✅ Chrome Mobile (all)</li> <li>✅ Samsung Internet (all)</li> <li>✅ Firefox Mobile (all)</li> </ul> </div> </div> </div> <h3>Mobile Viewport Considerations</h3> <p>Mobile browsers have some unique behaviors with viewport units:</p> <div style="background: var(--warning-color); color: var(--dark-color); padding: var(--spacing-lg); border-radius: var(--border-radius); margin: var(--spacing-lg) 0;"> <h4>Mobile Browser UI Changes</h4> <p>On mobile devices, the browser UI (address bar, etc.) can show/hide, affecting 100vh calculations. Consider using min-height instead of height for full-screen sections.</p> </div> <div class="code-block"> <span class="code-comment">/* Better approach for mobile full-screen sections */</span><br> .mobile-friendly-hero {<br> <span class="code-property">min-height</span>: <span class="code-value">100vh</span>; <span class="code-comment">/* Instead of height: 100vh */</span><br> <span class="code-property">height</span>: <span class="code-value">100svh</span>; <span class="code-comment">/* Small viewport height (future) */</span><br> } </div> </section> <!-- Advanced Viewport Units --> <section class="section"> <h2>New Viewport Units (CSS Values 4)</h2> <p>CSS Values and Units Level 4 introduces new viewport units to address mobile browser issues:</p> <div class="comparison-grid"> <div class="comparison-item"> <div class="comparison-header">Small Viewport Units</div> <div class="comparison-body"> <ul style="list-style-type: disc; padding-left: 1.5rem;"> <li><strong>svh, svw:</strong> Small viewport height/width</li> <li><strong>svmin, svmax:</strong> Small viewport min/max</li> <li>Assumes UI is visible (smallest possible)</li> </ul> </div> </div> <div class="comparison-item"> <div class="comparison-header">Large Viewport Units</div> <div class="comparison-body"> <ul style="list-style-type: disc; padding-left: 1.5rem;"> <li><strong>lvh, lvw:</strong> Large viewport height/width</li> <li><strong>lvmin, lvmax:</strong> Large viewport min/max</li> <li>Assumes UI is hidden (largest possible)</li> </ul> </div> </div> <div class="comparison-item"> <div class="comparison-header">Dynamic Viewport Units</div> <div class="comparison-body"> <ul style="list-style-type: disc; padding-left: 1.5rem;"> <li><strong>dvh, dvw:</strong> Dynamic viewport height/width</li> <li><strong>dvmin, dvmax:</strong> Dynamic viewport min/max</li> <li>Adjusts as UI shows/hides</li> </ul> </div> </div> </div> <div class="code-block"> <span class="code-comment">/* Future-proof mobile-friendly approach */</span><br> .hero-section {<br> <span class="code-property">height</span>: <span class="code-value">100vh</span>; <span class="code-comment">/* Fallback for older browsers */</span><br> <span class="code-property">height</span>: <span class="code-value">100svh</span>; <span class="code-comment">/* Small viewport (UI visible) */</span><br> <span class="code-property">height</span>: <span class="code-value">100dvh</span>; <span class="code-comment">/* Dynamic viewport (adjusts) */</span><br> } </div> </section> <!-- Performance Considerations --> <section class="section"> <h2>Performance Considerations</h2> <div style="background: var(--light-color); padding: var(--spacing-lg); border-radius: var(--border-radius); border: 1px solid var(--border-color);"> <h3>Viewport Units Performance</h3> <p>Viewport units are generally performant, but consider these factors:</p> <div class="comparison-grid" style="margin-top: var(--spacing-lg);"> <div> <h4 style="color: var(--success-color); margin-bottom: var(--spacing-sm);">✅ Good Performance</h4> <ul style="list-style-type: disc; padding-left: 1.5rem; font-size: 0.9rem;"> <li>Static viewport unit values</li> <li>Layout properties (width, height, padding)</li> <li>Typography sizing</li> <li>Transform values</li> </ul> </div> <div> <h4 style="color: var(--warning-color); margin-bottom: var(--spacing-sm);">⚠️ Use Carefully</h4> <ul style="list-style-type: disc; padding-left: 1.5rem; font-size: 0.9rem;"> <li>Frequent viewport unit animations</li> <li>Complex calc() expressions</li> <li>Many elements with viewport units</li> <li>Viewport units in CSS custom properties</li> </ul> </div> </div> </div> <div class="code-block"> <span class="code-comment">/* ✅ Performant: Static viewport units */</span><br> .header { <span class="code-property">height</span>: <span class="code-value">10vh</span>; }<br> .sidebar { <span class="code-property">width</span>: <span class="code-value">25vw</span>; }<br><br> <span class="code-comment">/* ⚠️ Less performant: Complex calculations */</span><br> .complex { <span class="code-property">width</span>: <span class="code-value">calc(50vw - 2rem + 10px)</span>; }<br><br> <span class="code-comment">/* ❌ Avoid: Animating viewport-dependent properties */</span><br> .avoid {<br> <span class="code-property">animation</span>: <span class="code-value">resize 1s linear infinite</span>;<br> }<br> @keyframes resize {<br> 0% { <span class="code-property">width</span>: <span class="code-value">10vw</span>; }<br> 100% { <span class="code-property">width</span>: <span class="code-value">90vw</span>; }<br> } </div> </section> <!-- Real-world Examples --> <section class="section"> <h2>Real-World Use Cases</h2> <h3>1. Landing Page Hero</h3> <div class="code-block"> .hero {<br> <span class="code-property">height</span>: <span class="code-value">100vh</span>;<br> <span class="code-property">background</span>: <span class="code-value">url('hero-bg.jpg') center/cover</span>;<br> <span class="code-property">display</span>: <span class="code-value">flex</span>;<br> <span class="code-property">align-items</span>: <span class="code-value">center</span>;<br> <span class="code-property">justify-content</span>: <span class="code-value">center</span>;<br> }<br><br> .hero h1 {<br> <span class="code-property">font-size</span>: <span class="code-value">clamp(2rem, 8vw, 6rem)</span>;<br> <span class="code-property">text-align</span>: <span class="code-value">center</span>;<br> } </div> <h3>2. Card Grid Layout</h3> <div class="code-block"> .card-grid {<br> <span class="code-property">display</span>: <span class="code-value">grid</span>;<br> <span class="code-property">grid-template-columns</span>: <span class="code-value">repeat(auto-fit, minmax(min(300px, 40vw), 1fr))</span>;<br> <span class="code-property">gap</span>: <span class="code-value">2vw</span>;<br> <span class="code-property">padding</span>: <span class="code-value">5vw</span>;<br> } </div> <h3>3. Modal Dialog</h3> <div class="code-block"> .modal {<br> <span class="code-property">position</span>: <span class="code-value">fixed</span>;<br> <span class="code-property">top</span>: <span class="code-value">50vh</span>;<br> <span class="code-property">left</span>: <span class="code-value">50vw</span>;<br> <span class="code-property">transform</span>: <span class="code-value">translate(-50%, -50%)</span>;<br> <span class="code-property">max-width</span>: <span class="code-value">90vw</span>;<br> <span class="code-property">max-height</span>: <span class="code-value">90vh</span>;<br> } </div> <h3>4. Responsive Spacing</h3> <div class="code-block"> .section {<br> <span class="code-property">padding</span>: <span class="code-value">clamp(2rem, 5vw, 8rem) clamp(1rem, 5vw, 4rem)</span>;<br> <span class="code-comment">/* Responsive vertical and horizontal padding */</span><br> }<br><br> .container {<br> <span class="code-property">margin</span>: <span class="code-value">0 auto</span>;<br> <span class="code-property">padding</span>: <span class="code-value">0 5vw</span>;<br> <span class="code-property">max-width</span>: <span class="code-value">1200px</span>;<br> } </div> </section> </div> <!-- Full Screen Example --> <section class="fullscreen-section"> <div class="fullscreen-content"> <h3>100vh Full-Screen Section</h3> <p>This section always fills the entire viewport height</p> </div> </section> <div class="container"> <!-- Accessibility Considerations --> <section class="section"> <h2>Accessibility & User Experience</h2> <div style="background: var(--danger-color); color: var(--text-light); padding: var(--spacing-lg); border-radius: var(--border-radius); margin-bottom: var(--spacing-lg);"> <h3 style="color: var(--text-light); margin-top: 0;">⚠️ Important Accessibility Considerations</h3> <ul style="margin: 0; padding-left: 1.5rem;"> <li>Viewport units can interfere with user zoom preferences</li> <li>Very small text (below 16px) can be difficult to read</li> <li>Consider users with visual impairments</li> <li>Test with browser zoom at 200%</li> </ul> </div> <h3>Zoom-Friendly Approach</h3> <div class="code-block"> <span class="code-comment">/* ✅ Zoom-friendly: Use rem for minimum size */</span><br> .accessible-text {<br> <span class="code-property">font-size</span>: <span class="code-value">clamp(1rem, 3vw, 2rem)</span>;<br> <span class="code-comment">/* 1rem minimum respects user's base font size */</span><br> }<br><br> <span class="code-comment">/* ❌ Not zoom-friendly: Pure viewport units */</span><br> .problematic-text {<br> <span class="code-property">font-size</span>: <span class="code-value">3vw</span>; <span class="code-comment">/* Could be too small when zoomed */</span><br> } </div> <h3>Reduced Motion Preferences</h3> <div class="code-block"> <span class="code-comment">/* Respect user's motion preferences */</span><br> .animated-viewport-element {<br> <span class="code-property">animation</span>: <span class="code-value">float 6s ease-in-out infinite</span>;<br> }<br><br> @media (prefers-reduced-motion: reduce) {<br> .animated-viewport-element {<br> <span class="code-property">animation</span>: <span class="code-value">none</span>;<br> }<br> } </div> </section> <!-- Summary --> <section class="section"> <h2>Summary</h2> <p> Viewport units are powerful tools for creating truly responsive designs that adapt fluidly to any screen size. When used thoughtfully with modern CSS functions like clamp(), they enable designs that work beautifully across all devices. </p> <div style="background: linear-gradient(135deg, var(--primary-color), var(--secondary-color)); color: var(--text-light); padding: var(--spacing-xl); border-radius: var(--border-radius); margin: var(--spacing-lg) 0;"> <h3 style="color: var(--text-light); margin-top: 0;">Key Takeaways</h3> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--spacing-lg); margin-top: var(--spacing-lg);"> <div> <h4 style="color: var(--accent-color); margin-bottom: var(--spacing-sm);">Units to Remember</h4> <ul style="margin: 0; padding-left: 1.5rem; font-size: 0.9rem;"> <li>vw: 1% of viewport width</li> <li>vh: 1% of viewport height</li> <li>vmin: 1% of smaller dimension</li> <li>vmax: 1% of larger dimension</li> </ul> </div> <div> <h4 style="color: var(--accent-color); margin-bottom: var(--spacing-sm);">Best Practices</h4> <ul style="margin: 0; padding-left: 1.5rem; font-size: 0.9rem;"> <li>Combine with clamp() for control</li> <li>Set minimum and maximum bounds</li> <li>Test across different screen sizes</li> <li>Consider accessibility and zoom</li> </ul> </div> </div> </div> </section> </div> <script> // Update viewport size indicator function updateViewportSize() { const width = window.innerWidth; const height = window.innerHeight; const dimensions = document.getElementById('dimensions'); if (dimensions) { dimensions.textContent = `${width} × ${height}px`; } } // Update on load and resize updateViewportSize(); window.addEventListener('resize', updateViewportSize); // Smooth scrolling for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth' }); } }); }); </script> </body> </html>
Advanced Viewport Techniques
New Viewport Units (CSS Values 4)
Modern browsers are introducing new viewport units to address mobile browser UI issues:
Small Viewport
- svh, svw
- svmin, svmax
- UI visible (smallest)
Large Viewport
- lvh, lvw
- lvmin, lvmax
- UI hidden (largest)
Dynamic Viewport
- dvh, dvw
- dvmin, dvmax
- Adjusts as UI changes
Performance Considerations
While viewport units are generally performant, consider these optimization tips:
Good for Performance
- Static viewport unit values
- Layout properties (width, height)
- Typography sizing
- Transform values
Use Carefully
- Animating viewport properties
- Complex calc() expressions
- Many elements with viewport units
- Viewport units in CSS variables
Ready to Master Viewport Units?
Experiment with our interactive example that demonstrates all viewport units in action. Resize your browser window and see how different elements respond to viewport changes in real-time!