Foundation Off-Canvas
Off-Canvas is a slide-in navigation pattern, commonly used in mobile interfaces. When triggered, the navigation panel slides in from the edge of the screen. This chapter will introduce various uses of Off-Canvas.
Basic Off-Canvas
html
<div class="off-canvas-wrapper">
<!-- Off-Canvas Panel -->
<div class="off-canvas position-left" id="offCanvas" data-off-canvas>
<ul class="vertical menu">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div>
<!-- Main Content Area -->
<div class="off-canvas-content" data-off-canvas-content>
<!-- Trigger Button -->
<button type="button" data-toggle="offCanvas">Open Menu</button>
<!-- Page Content -->
<div class="grid-container">
<h1>Main Page Content</h1>
<p>Click the button to open the sidebar navigation.</p>
</div>
</div>
</div>Position Options
Off-Canvas can slide in from different directions:
html
<!-- Slide in from left -->
<div class="off-canvas position-left" id="offCanvasLeft" data-off-canvas>
Content
</div>
<!-- Slide in from right -->
<div class="off-canvas position-right" id="offCanvasRight" data-off-canvas>
Content
</div>
<!-- Slide in from top -->
<div class="off-canvas position-top" id="offCanvasTop" data-off-canvas>
Content
</div>
<!-- Slide in from bottom -->
<div class="off-canvas position-bottom" id="offCanvasBottom" data-off-canvas>
Content
</div>Overlay
Use data-reveal to control overlay behavior:
html
<!-- Show overlay (default) -->
<div class="off-canvas position-left" id="offCanvas1" data-off-canvas data-reveal="push">
Content
</div>
<!-- Overlap mode -->
<div class="off-canvas position-left" id="offCanvas2" data-off-canvas data-transition="overlap">
Content
</div>Responsive Off-Canvas
Display only on specific screen sizes:
html
<div class="off-canvas-wrapper">
<!-- Show only on small screens -->
<div class="off-canvas position-left reveal-for-medium" id="offCanvasResponsive" data-off-canvas>
<ul class="vertical menu">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
</ul>
</div>
<div class="off-canvas-content" data-off-canvas-content>
<!-- Trigger button shown only on small screens -->
<button type="button" class="hide-for-medium" data-toggle="offCanvasResponsive">
Menu
</button>
<main>Content</main>
</div>
</div>Off-Canvas with Header
html
<div class="off-canvas position-left" id="offCanvasWithHeader" data-off-canvas>
<div style="background: #1779ba; color: white; padding: 15px;">
<div class="grid-x align-middle">
<div class="cell auto">
<strong>Navigation Menu</strong>
</div>
<div class="cell shrink">
<button class="close-button" aria-label="Close menu" type="button" data-close>
<span aria-hidden="true">×</span>
</button>
</div>
</div>
</div>
<ul class="vertical menu">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Contact</a></li>
</ul>
</div>Nested Menu
html
<div class="off-canvas position-left" id="offCanvasNested" data-off-canvas>
<ul class="vertical menu" data-drilldown>
<li>
<a href="#">Products</a>
<ul class="menu vertical nested">
<li><a href="#">Product A</a></li>
<li><a href="#">Product B</a></li>
<li>
<a href="#">Product C</a>
<ul class="menu vertical nested">
<li><a href="#">C-1</a></li>
<li><a href="#">C-2</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#">Services</a></li>
<li><a href="#">About</a></li>
</ul>
</div>Dual Off-Canvas
html
<div class="off-canvas-wrapper">
<!-- Left Panel -->
<div class="off-canvas position-left" id="leftPanel" data-off-canvas>
<h4>Navigation Menu</h4>
<ul class="vertical menu">
<li><a href="#">Home</a></li>
<li><a href="#">About</a></li>
</ul>
</div>
<!-- Right Panel -->
<div class="off-canvas position-right" id="rightPanel" data-off-canvas>
<h4>Shopping Cart</h4>
<ul class="no-bullet">
<li>Product 1 - $99</li>
<li>Product 2 - $199</li>
</ul>
<hr>
<p><strong>Total: $298</strong></p>
<a class="button expanded" href="#">Checkout</a>
</div>
<!-- Main Content -->
<div class="off-canvas-content" data-off-canvas-content>
<div class="top-bar">
<div class="top-bar-left">
<button type="button" data-toggle="leftPanel">Menu</button>
</div>
<div class="top-bar-right">
<button type="button" data-toggle="rightPanel">Cart</button>
</div>
</div>
<main>Content</main>
</div>
</div>Configuration Options
html
<div class="off-canvas position-left" id="configOffCanvas" data-off-canvas
data-transition="overlap"
data-close-on-click="true"
data-content-overlay="true"
data-force-top="true">
Content
</div>| Option | Description | Default |
|---|---|---|
data-transition | Transition effect (push/overlap) | push |
data-close-on-click | Close on overlay click | true |
data-content-overlay | Show content overlay | true |
data-force-top | Force scroll to top | true |
JavaScript API
javascript
// Open
$('#offCanvas').foundation('open');
// Close
$('#offCanvas').foundation('close');
// Toggle
$('#offCanvas').foundation('toggle');
// Events
$('#offCanvas').on('opened.zf.offCanvas', function() {
console.log('Off-Canvas opened');
});
$('#offCanvas').on('closed.zf.offCanvas', function() {
console.log('Off-Canvas closed');
});Complete Example
html
<!DOCTYPE html>
<html class="no-js" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Foundation Off-Canvas Example</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/foundation-sites@6.7.5/dist/css/foundation.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/foundation-icons.min.css">
<style>
.off-canvas {
background: #2c3e50;
}
.off-canvas .menu a {
color: #ecf0f1;
padding: 15px 20px;
}
.off-canvas .menu a:hover {
background: rgba(255,255,255,0.1);
}
.off-canvas .menu a i {
margin-right: 10px;
}
.off-canvas-header {
background: #1779ba;
color: white;
padding: 15px 20px;
}
.off-canvas-header h4 {
margin: 0;
color: white;
}
.user-profile {
padding: 20px;
text-align: center;
border-bottom: 1px solid rgba(255,255,255,0.1);
}
.user-profile img {
width: 80px;
height: 80px;
border-radius: 50%;
margin-bottom: 10px;
}
.user-profile h5 {
color: white;
margin: 0;
}
.user-profile p {
color: #bdc3c7;
margin: 0;
font-size: 14px;
}
.main-content {
min-height: 100vh;
padding: 20px;
}
</style>
</head>
<body>
<div class="off-canvas-wrapper">
<!-- Left Off-Canvas -->
<div class="off-canvas position-left" id="leftOffCanvas" data-off-canvas>
<div class="off-canvas-header">
<div class="grid-x align-middle">
<div class="cell auto">
<h4>Navigation Menu</h4>
</div>
<div class="cell shrink">
<button class="close-button" aria-label="Close" type="button" data-close style="color: white;">
<span aria-hidden="true">×</span>
</button>
</div>
</div>
</div>
<div class="user-profile">
<img src="https://via.placeholder.com/80" alt="User Avatar">
<h5>John Doe</h5>
<p>Frontend Developer</p>
</div>
<ul class="vertical menu">
<li><a href="#"><i class="fi-home"></i> Home</a></li>
<li><a href="#"><i class="fi-torso"></i> Profile</a></li>
<li><a href="#"><i class="fi-mail"></i> Messages</a></li>
<li><a href="#"><i class="fi-widget"></i> Settings</a></li>
<li><a href="#"><i class="fi-info"></i> Help</a></li>
<li><a href="#"><i class="fi-power"></i> Logout</a></li>
</ul>
</div>
<!-- Right Off-Canvas (Shopping Cart) -->
<div class="off-canvas position-right" id="rightOffCanvas" data-off-canvas style="background: white; width: 300px;">
<div style="background: #3adb76; color: white; padding: 15px 20px;">
<div class="grid-x align-middle">
<div class="cell auto">
<h4 style="margin: 0; color: white;">Shopping Cart</h4>
</div>
<div class="cell shrink">
<button class="close-button" aria-label="Close" type="button" data-close>
<span aria-hidden="true">×</span>
</button>
</div>
</div>
</div>
<div style="padding: 20px;">
<div class="grid-x" style="margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid #eee;">
<div class="cell shrink">
<img src="https://via.placeholder.com/60" alt="Product Image" style="border-radius: 4px;">
</div>
<div class="cell auto" style="padding-left: 10px;">
<strong>Product Name 1</strong>
<p style="margin: 0; color: #666; font-size: 14px;">Qty: 1</p>
<p style="margin: 0; color: #cc4b37; font-weight: bold;">$99.00</p>
</div>
</div>
<div class="grid-x" style="margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid #eee;">
<div class="cell shrink">
<img src="https://via.placeholder.com/60" alt="Product Image" style="border-radius: 4px;">
</div>
<div class="cell auto" style="padding-left: 10px;">
<strong>Product Name 2</strong>
<p style="margin: 0; color: #666; font-size: 14px;">Qty: 2</p>
<p style="margin: 0; color: #cc4b37; font-weight: bold;">$199.00</p>
</div>
</div>
<div style="background: #f4f4f4; padding: 15px; border-radius: 4px; margin-bottom: 15px;">
<div class="grid-x">
<div class="cell auto">Subtotal</div>
<div class="cell shrink"><strong>$298.00</strong></div>
</div>
</div>
<a class="button expanded success" href="#">Checkout</a>
<a class="button hollow expanded" href="#">Continue Shopping</a>
</div>
</div>
<!-- Main Content Area -->
<div class="off-canvas-content" data-off-canvas-content>
<!-- Top Navigation -->
<div class="top-bar" style="background: #2c3e50;">
<div class="top-bar-left">
<ul class="menu">
<li>
<button class="button clear" type="button" data-toggle="leftOffCanvas" style="color: white;">
<i class="fi-list"></i>
</button>
</li>
<li class="menu-text" style="color: white;">Website Name</li>
</ul>
</div>
<div class="top-bar-right">
<ul class="menu">
<li>
<button class="button clear" type="button" data-toggle="rightOffCanvas" style="color: white; position: relative;">
<i class="fi-shopping-cart"></i>
<span class="badge alert" style="position: absolute; top: 0; right: 0; font-size: 10px;">2</span>
</button>
</li>
</ul>
</div>
</div>
<!-- Main Content -->
<div class="main-content">
<div class="grid-container">
<h1>Off-Canvas Navigation Example</h1>
<p>Click the menu icon in the top left to open the navigation menu, click the cart icon in the top right to view the shopping cart.</p>
<div class="callout">
<h4>Off-Canvas Features</h4>
<ul>
<li>Slide in from screen edge</li>
<li>Support multiple directions (left, right, top, bottom)</li>
<li>Perfect for mobile navigation</li>
<li>Can contain any content</li>
</ul>
</div>
<div class="grid-x grid-margin-x small-up-1 medium-up-3">
<div class="cell">
<div class="card">
<img src="https://via.placeholder.com/300x200" alt="Product">
<div class="card-section">
<h4>Product 1</h4>
<p>Product description...</p>
<a class="button" href="#">View Details</a>
</div>
</div>
</div>
<div class="cell">
<div class="card">
<img src="https://via.placeholder.com/300x200" alt="Product">
<div class="card-section">
<h4>Product 2</h4>
<p>Product description...</p>
<a class="button" href="#">View Details</a>
</div>
</div>
</div>
<div class="cell">
<div class="card">
<img src="https://via.placeholder.com/300x200" alt="Product">
<div class="card-section">
<h4>Product 3</h4>
<p>Product description...</p>
<a class="button" href="#">View Details</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/foundation-sites@6.7.5/dist/js/foundation.min.js"></script>
<script>$(document).foundation();</script>
</body>
</html>Off-Canvas Best Practices
- Mobile-First: Off-Canvas is best suited for mobile navigation
- Clear Triggers: Use recognizable icons or buttons
- Close Button: Provide obvious ways to close
- Appropriate Width: Don't take up too much screen space
- Content Organization: Organize panel content reasonably
Summary
In this chapter, we learned:
- Creating basic Off-Canvas
- Different positions (left, right, top, bottom)
- Responsive Off-Canvas
- Off-Canvas with headers and nested menus
- Dual Off-Canvas
- JavaScript API
Next chapter, we will learn Foundation Magellan.