Mobile traffic now accounts for over 50% of web traffic, making responsive design mandatory for modern web applications. At ZIRA Software, we use Bootstrap with Laravel to create responsive, mobile-friendly applications that work beautifully on all devices.
Why Bootstrap with Laravel?
Bootstrap advantages:
- Mobile-first responsive grid system
- Pre-built UI components
- Cross-browser compatibility
- Extensive documentation
- Active community
- Rapid development
Laravel integration benefits:
- Blade templates work perfectly with Bootstrap
- Asset pipeline for compiling Bootstrap Sass
- Easy customization through variables
- Clean separation of concerns
Installing Bootstrap in Laravel
Method 1: CDN (Quick Start)
In your master layout (app/views/layouts/master.blade.php):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>@yield('title') - My App</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
</head>
<body>
@include('partials.navbar')
<div class="container">
@yield('content')
</div>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
@yield('scripts')
</body>
</html>
Method 2: Local Assets (Production)
- Download Bootstrap:
bower install bootstrap --save
# Or download from getbootstrap.com
- Copy files:
cp bower_components/bootstrap/dist/css/bootstrap.min.css public/css/
cp bower_components/bootstrap/dist/js/bootstrap.min.js public/js/
- Reference in layout:
<link rel="stylesheet" href="{{ asset('css/bootstrap.min.css') }}">
<script src="{{ asset('js/bootstrap.min.js') }}"></script>
Responsive Grid System
Bootstrap's grid divides the page into 12 columns:
<div class="container">
<div class="row">
<div class="col-md-8">
<!-- Main content: 8 columns on desktop -->
@yield('content')
</div>
<div class="col-md-4">
<!-- Sidebar: 4 columns on desktop -->
@include('partials.sidebar')
</div>
</div>
</div>
Responsive breakpoints:
col-xs-*: Extra small devices (phones, <768px)col-sm-*: Small devices (tablets, ≥768px)col-md-*: Medium devices (desktops, ≥992px)col-lg-*: Large devices (large desktops, ≥1200px)
Complex responsive layout:
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-4">
<!-- Full width on phone -->
<!-- Half width on tablet -->
<!-- One-third on desktop -->
Product 1
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
Product 2
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
Product 3
</div>
</div>
Navigation Bar
Create a responsive navbar partial (app/views/partials/navbar.blade.php):
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<!-- Mobile toggle button -->
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{ route('home') }}">
{{ Config::get('app.name') }}
</a>
</div>
<div class="collapse navbar-collapse" id="navbar-collapse">
<ul class="nav navbar-nav">
<li class="{{ Request::is('/') ? 'active' : '' }}">
<a href="{{ route('home') }}">Home</a>
</li>
<li class="{{ Request::is('products*') ? 'active' : '' }}">
<a href="{{ route('products.index') }}">Products</a>
</li>
<li class="{{ Request::is('about') ? 'active' : '' }}">
<a href="{{ route('about') }}">About</a>
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
@if (Auth::check())
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
{{ Auth::user()->name }} <span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li><a href="{{ route('profile') }}">Profile</a></li>
<li><a href="{{ route('orders') }}">My Orders</a></li>
<li class="divider"></li>
<li><a href="{{ route('logout') }}">Logout</a></li>
</ul>
</li>
@else
<li><a href="{{ route('login') }}">Login</a></li>
<li><a href="{{ route('register') }}">Register</a></li>
@endif
</ul>
</div>
</div>
</nav>
Forms
Bootstrap form styling with Laravel Form Builder:
<form method="POST" action="{{ route('products.store') }}" class="form-horizontal">
{{ csrf_field() }}
<div class="form-group {{ $errors->has('name') ? 'has-error' : '' }}">
<label for="name" class="col-sm-2 control-label">Product Name</label>
<div class="col-sm-10">
<input type="text" name="name" id="name" class="form-control"
value="{{ old('name') }}" required>
@if ($errors->has('name'))
<span class="help-block">{{ $errors->first('name') }}</span>
@endif
</div>
</div>
<div class="form-group {{ $errors->has('price') ? 'has-error' : '' }}">
<label for="price" class="col-sm-2 control-label">Price</label>
<div class="col-sm-10">
<div class="input-group">
<span class="input-group-addon">$</span>
<input type="number" name="price" id="price" class="form-control"
value="{{ old('price') }}" step="0.01" required>
</div>
@if ($errors->has('price'))
<span class="help-block">{{ $errors->first('price') }}</span>
@endif
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-primary">Create Product</button>
<a href="{{ route('products.index') }}" class="btn btn-default">Cancel</a>
</div>
</div>
</form>
Data Tables
Responsive product listing:
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th class="hidden-xs">Category</th>
<th>Price</th>
<th class="hidden-xs">Stock</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach ($products as $product)
<tr>
<td>{{ $product->id }}</td>
<td>
<strong>{{ $product->name }}</strong>
<br class="visible-xs">
<small class="visible-xs text-muted">
{{ $product->category->name }}
</small>
</td>
<td class="hidden-xs">{{ $product->category->name }}</td>
<td>${{ number_format($product->price, 2) }}</td>
<td class="hidden-xs">
<span class="label label-{{ $product->in_stock ? 'success' : 'danger' }}">
{{ $product->stock }}
</span>
</td>
<td>
<a href="{{ route('products.edit', $product) }}" class="btn btn-sm btn-primary">
<span class="glyphicon glyphicon-edit"></span>
<span class="hidden-xs">Edit</span>
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
{{ $products->links() }}
Cards/Panels
Product grid with Bootstrap panels:
<div class="row">
@foreach ($products as $product)
<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
<div class="panel panel-default">
<div class="panel-body">
<img src="{{ $product->image_url }}" alt="{{ $product->name }}"
class="img-responsive center-block" style="max-height: 200px;">
</div>
<div class="panel-footer">
<h4 class="text-center">{{ $product->name }}</h4>
<p class="text-center">
<strong class="text-primary">${{ number_format($product->price, 2) }}</strong>
</p>
<a href="{{ route('products.show', $product) }}" class="btn btn-primary btn-block">
View Details
</a>
</div>
</div>
</div>
@endforeach
</div>
Alerts and Messages
Display Laravel session messages:
@if (Session::has('success'))
<div class="alert alert-success alert-dismissible">
<button type="button" class="close" data-dismiss="alert">
<span>×</span>
</button>
{{ Session::get('success') }}
</div>
@endif
@if (Session::has('error'))
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert">
<span>×</span>
</button>
{{ Session::get('error') }}
</div>
@endif
@if ($errors->any())
<div class="alert alert-danger">
<strong>Please correct the following errors:</strong>
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
Pagination
Bootstrap-styled pagination (Laravel includes this by default):
{{ $products->links() }}
Customize pagination view if needed:
php artisan view:publish
Edit app/views/pagination/default.php to match your Bootstrap version.
Modals
Confirm delete with Bootstrap modal:
<!-- Delete button -->
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteModal{{ $product->id }}">
Delete
</button>
<!-- Modal -->
<div class="modal fade" id="deleteModal{{ $product->id }}">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span>×</span></button>
<h4 class="modal-title">Confirm Delete</h4>
</div>
<div class="modal-body">
<p>Are you sure you want to delete <strong>{{ $product->name }}</strong>?</p>
</div>
<div class="modal-footer">
<form method="POST" action="{{ route('products.destroy', $product) }}">
{{ csrf_field() }}
{{ method_field('DELETE') }}
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-danger">Delete</button>
</form>
</div>
</div>
</div>
</div>
Custom Styling
Override Bootstrap defaults with custom CSS:
/* public/css/app.css */
/* Brand colors */
.navbar-default {
background-color: #2c3e50;
border-color: #1a252f;
}
.navbar-default .navbar-brand,
.navbar-default .navbar-nav > li > a {
color: #ecf0f1;
}
.btn-primary {
background-color: #3498db;
border-color: #2980b9;
}
.btn-primary:hover {
background-color: #2980b9;
}
/* Spacing utilities */
.mt-20 { margin-top: 20px; }
.mb-20 { margin-bottom: 20px; }
.p-20 { padding: 20px; }
Mobile-First Best Practices
- Use viewport meta tag:
<meta name="viewport" content="width=device-width, initial-scale=1">
- Hide content on mobile when necessary:
<span class="hidden-xs">This text is hidden on phones</span>
<span class="visible-xs">This text only shows on phones</span>
- Stack elements vertically on mobile:
<div class="col-xs-12 col-md-6">
<!-- Full width on phone, half width on desktop -->
</div>
- Use responsive images:
<img src="image.jpg" class="img-responsive" alt="Description">
- Make buttons full-width on mobile:
<button class="btn btn-primary btn-block visible-xs">Mobile Full Width</button>
<button class="btn btn-primary hidden-xs">Desktop Normal</button>
Testing Responsive Design
Browser DevTools:
- Chrome: F12 → Toggle Device Toolbar
- Firefox: F12 → Responsive Design Mode
Test on real devices:
- iPhone, iPad
- Android phones/tablets
- Various browsers
Use BrowserStack or similar services for comprehensive testing
Conclusion
Bootstrap with Laravel provides a solid foundation for building responsive web applications quickly. The combination of Laravel's powerful backend and Bootstrap's responsive frontend creates professional, mobile-friendly applications that work beautifully across all devices.
Need a responsive Laravel application? Contact ZIRA Software to discuss your project. We specialize in building mobile-friendly web applications with Bootstrap and modern frontend frameworks.