Bootstrap 5 Tutorial
v5.3.0Bootstrap 5 Tutorial
Blog Layout Project
Project Goal: Create a modern, responsive blog layout with article listings, individual posts, categories, tags, and comments.
Project Overview
This project demonstrates how to build a complete blog website using Bootstrap 5. The blog includes article listings, individual post pages, categories, tags, author bios, comments, and related posts.
Blog Features
- Blog post listings with excerpts
- Individual article pages
- Categories and tags system
- Author information and bios
- Comments section
- Related posts
- Search functionality
- Social sharing
Content Features
- Featured posts slider
- Popular posts sidebar
- Newsletter subscription
- Reading time estimates
- Table of contents
- Syntax highlighting for code
- Image galleries
- Print-friendly articles
Complete Blog Structure
HTML Layout
<!-- Blog Website -->
<!-- Top Bar -->
<div class="top-bar bg-primary text-white py-2 d-none d-md-block">
<div class="container">
<div class="d-flex justify-content-between align-items-center">
<div>
<span class="small">
<i class="fas fa-newspaper me-1"></i> Latest: Bootstrap 5.3 Released
</span>
</div>
<div class="d-flex gap-3">
<a href="#" class="text-white-50 text-decoration-none small">
<i class="fas fa-rss me-1"></i> RSS
</a>
<a href="#" class="text-white-50 text-decoration-none small">
<i class="fas fa-envelope me-1"></i> Newsletter
</a>
</div>
</div>
</div>
</div>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm sticky-top">
<div class="container">
<!-- Logo -->
<a class="navbar-brand fw-bold fs-3" href="#">
<i class="fas fa-blog text-primary me-2"></i>TechBlog
</a>
<!-- Main Navigation -->
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto">
<li class="nav-item"><a class="nav-link active" href="#">Home</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">
Categories
</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="#">Web Development</a>
<a class="dropdown-item" href="#">Mobile Apps</a>
<a class="dropdown-item" href="#">UI/UX Design</a>
<a class="dropdown-item" href="#">DevOps</a>
<a class="dropdown-item" href="#">Data Science</a>
</div>
</li>
<li class="nav-item"><a class="nav-link" href="#">Tutorials</a></li>
<li class="nav-item"><a class="nav-link" href="#">Resources</a></li>
<li class="nav-item"><a class="nav-link" href="#">About</a></li>
</ul>
<!-- Search -->
<form class="d-flex">
<div class="input-group">
<input type="search" class="form-control" placeholder="Search articles...">
<button class="btn btn-primary" type="submit">
<i class="fas fa-search"></i>
</button>
</div>
</form>
</div>
<!-- Mobile Toggle -->
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<!-- Hero Section -->
<section class="hero-section bg-light py-5">
<div class="container">
<div class="row align-items-center">
<div class="col-lg-8">
<span class="badge bg-primary mb-3">Featured</span>
<h1 class="display-4 fw-bold mb-3">The Future of Web Development with Bootstrap 5</h1>
<p class="lead mb-4">Learn how Bootstrap 5 is revolutionizing front-end development with new features, improved performance, and better accessibility.</p>
<div class="d-flex align-items-center">
<img src="https://via.placeholder.com/40" class="rounded-circle me-2" alt="Author">
<div>
<span class="fw-bold">John Doe</span>
<div class="text-muted small">
<span class="me-3"><i class="far fa-calendar me-1"></i> Jan 15, 2024</span>
<span class="me-3"><i class="far fa-clock me-1"></i> 5 min read</span>
<span><i class="far fa-comment me-1"></i> 12 comments</span>
</div>
</div>
</div>
</div>
<div class="col-lg-4">
<img src="https://via.placeholder.com/400x300" class="img-fluid rounded shadow" alt="Featured Post">
</div>
</div>
</div>
</section>
<!-- Main Content -->
<section class="py-5">
<div class="container">
<div class="row">
<!-- Blog Posts -->
<div class="col-lg-8">
<!-- Featured Posts Carousel -->
<div class="mb-5">
<h2 class="h4 mb-3">Featured Posts</h2>
<div id="featuredCarousel" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<div class="card border-0 shadow-sm">
<div class="row g-0">
<div class="col-md-5">
<img src="https://via.placeholder.com/400x250" class="img-fluid rounded-start h-100" alt="Post 1">
</div>
<div class="col-md-7">
<div class="card-body">
<span class="badge bg-success mb-2">New</span>
<h5 class="card-title">Responsive Design Best Practices 2024</h5>
<p class="card-text text-muted">Learn the latest techniques for creating responsive websites that work perfectly on all devices.</p>
<div class="d-flex align-items-center">
<img src="https://via.placeholder.com/30" class="rounded-circle me-2" alt="Author">
<span class="small">Sarah Johnson</span>
<span class="small text-muted ms-3"><i class="far fa-clock me-1"></i> 8 min read</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- More carousel items -->
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#featuredCarousel" data-bs-slide="prev">
<span class="carousel-control-prev-icon"></span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#featuredCarousel" data-bs-slide="next">
<span class="carousel-control-next-icon"></span>
</button>
</div>
</div>
<!-- Recent Posts -->
<h2 class="h4 mb-4">Recent Articles</h2>
<!-- Blog Post Card -->
<div class="card border-0 shadow-sm mb-4">
<div class="row g-0">
<div class="col-md-4">
<img src="https://via.placeholder.com/300x200" class="img-fluid rounded-start h-100" alt="Post Image">
</div>
<div class="col-md-8">
<div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-2">
<div>
<span class="badge bg-primary me-2">Web Dev</span>
<span class="badge bg-secondary">JavaScript</span>
</div>
<span class="text-muted small"><i class="far fa-clock me-1"></i> 6 min read</span>
</div>
<h3 class="card-title h5">
<a href="#" class="text-decoration-none text-dark">Mastering JavaScript ES6+ Features</a>
</h3>
<p class="card-text text-muted">A comprehensive guide to modern JavaScript features including arrow functions, promises, async/await, and more.</p>
<div class="d-flex justify-content-between align-items-center mt-3">
<div class="d-flex align-items-center">
<img src="https://via.placeholder.com/30" class="rounded-circle me-2" alt="Author">
<div>
<span class="fw-bold small">Mike Chen</span>
<div class="text-muted small">Jan 12, 2024</div>
</div>
</div>
<div>
<a href="#" class="text-muted small me-3">
<i class="far fa-comment me-1"></i> 24
</a>
<a href="#" class="text-muted small">
<i class="far fa-heart me-1"></i> 42
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- More blog post cards -->
<!-- Pagination -->
<nav aria-label="Page navigation" class="mt-5">
<ul class="pagination justify-content-center">
<li class="page-item disabled">
<a class="page-link" href="#" tabindex="-1">Previous</a>
</li>
<li class="page-item active"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">3</a></li>
<li class="page-item">
<a class="page-link" href="#">Next</a>
</li>
</ul>
</nav>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Newsletter -->
<div class="card border-0 shadow-sm mb-4">
<div class="card-body">
<h5 class="card-title">
<i class="fas fa-newspaper text-primary me-2"></i>Subscribe to Newsletter
</h5>
<p class="card-text text-muted small">Get the latest articles and tutorials delivered to your inbox.</p>
<form>
<div class="mb-3">
<input type="email" class="form-control" placeholder="Your email address">
</div>
<button type="submit" class="btn btn-primary w-100">Subscribe</button>
</form>
</div>
</div>
<!-- Categories -->
<div class="card border-0 shadow-sm mb-4">
<div class="card-body">
<h5 class="card-title">
<i class="fas fa-folder text-primary me-2"></i>Categories
</h5>
<ul class="list-unstyled mb-0">
<li class="mb-2">
<a href="#" class="text-decoration-none d-flex justify-content-between">
<span>Web Development</span>
<span class="badge bg-primary rounded-pill">24</span>
</a>
</li>
<li class="mb-2">
<a href="#" class="text-decoration-none d-flex justify-content-between">
<span>Mobile Apps</span>
<span class="badge bg-primary rounded-pill">18</span>
</a>
</li>
<li class="mb-2">
<a href="#" class="text-decoration-none d-flex justify-content-between">
<span>UI/UX Design</span>
<span class="badge bg-primary rounded-pill">15</span>
</a>
</li>
<li class="mb-2">
<a href="#" class="text-decoration-none d-flex justify-content-between">
<span>DevOps</span>
<span class="badge bg-primary rounded-pill">9</span>
</a>
</li>
<li>
<a href="#" class="text-decoration-none d-flex justify-content-between">
<span>Data Science</span>
<span class="badge bg-primary rounded-pill">7</span>
</a>
</li>
</ul>
</div>
</div>
<!-- Popular Tags -->
<div class="card border-0 shadow-sm mb-4">
<div class="card-body">
<h5 class="card-title">
<i class="fas fa-tags text-primary me-2"></i>Popular Tags
</h5>
<div class="d-flex flex-wrap gap-2">
<a href="#" class="badge bg-light text-dark text-decoration-none p-2">Bootstrap</a>
<a href="#" class="badge bg-light text-dark text-decoration-none p-2">JavaScript</a>
<a href="#" class="badge bg-light text-dark text-decoration-none p-2">React</a>
<a href="#" class="badge bg-light text-dark text-decoration-none p-2">CSS</a>
<a href="#" class="badge bg-light text-dark text-decoration-none p-2">HTML5</a>
<a href="#" class="badge bg-light text-dark text-decoration-none p-2">Node.js</a>
<a href="#" class="badge bg-light text-dark text-decoration-none p-2">API</a>
<a href="#" class="badge bg-light text-dark text-decoration-none p-2">Mobile</a>
</div>
</div>
</div>
<!-- Popular Posts -->
<div class="card border-0 shadow-sm">
<div class="card-body">
<h5 class="card-title">
<i class="fas fa-fire text-primary me-2"></i>Popular Posts
</h5>
<div class="list-group list-group-flush">
<a href="#" class="list-group-item list-group-item-action border-0 px-0 py-3">
<div class="d-flex">
<img src="https://via.placeholder.com/60" class="rounded me-3" style="width: 60px; height: 60px; object-fit: cover;">
<div>
<h6 class="mb-1">10 CSS Tricks You Should Know</h6>
<small class="text-muted">Jan 10, 2024</small>
</div>
</div>
</a>
<a href="#" class="list-group-item list-group-item-action border-0 px-0 py-3">
<div class="d-flex">
<img src="https://via.placeholder.com/60" class="rounded me-3" style="width: 60px; height: 60px; object-fit: cover;">
<div>
<h6 class="mb-1">Building REST APIs with Express</h6>
<small class="text-muted">Jan 8, 2024</small>
</div>
</div>
</a>
<!-- More popular posts -->
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Single Blog Post Page Example -->
<section class="py-5 bg-light d-none" id="singlePostExample">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8">
<!-- Breadcrumb -->
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item"><a href="#">Web Development</a></li>
<li class="breadcrumb-item active" aria-current="page">Bootstrap 5 Tutorial</li>
</ol>
</nav>
<!-- Article Header -->
<article>
<header class="mb-5">
<span class="badge bg-primary mb-3">Tutorial</span>
<h1 class="display-5 fw-bold mb-3">Complete Bootstrap 5 Tutorial for Beginners</h1>
<div class="d-flex align-items-center mb-4">
<img src="https://via.placeholder.com/50" class="rounded-circle me-3" alt="Author">
<div>
<div class="fw-bold">Alex Johnson</div>
<div class="text-muted small">
<span class="me-3"><i class="far fa-calendar me-1"></i> Jan 15, 2024</span>
<span class="me-3"><i class="far fa-clock me-1"></i> 8 min read</span>
<span><i class="far fa-eye me-1"></i> 1,245 views</span>
</div>
</div>
</div>
<!-- Social Sharing -->
<div class="d-flex gap-3 mb-4">
<a href="#" class="text-muted"><i class="fab fa-twitter fa-lg"></i></a>
<a href="#" class="text-muted"><i class="fab fa-facebook fa-lg"></i></a>
<a href="#" class="text-muted"><i class="fab fa-linkedin fa-lg"></i></a>
<a href="#" class="text-muted"><i class="fab fa-whatsapp fa-lg"></i></a>
</div>
<!-- Featured Image -->
<img src="https://via.placeholder.com/800x400" class="img-fluid rounded mb-4" alt="Featured Image">
</header>
<!-- Article Content -->
<div class="article-content">
<p class="lead mb-4">Bootstrap 5 brings significant improvements over previous versions, with new components, better customization options, and enhanced performance.</p>
<!-- Table of Contents -->
<div class="card mb-4">
<div class="card-header bg-light">
<h5 class="mb-0"><i class="fas fa-list me-2"></i>Table of Contents</h5>
</div>
<div class="card-body">
<nav class="table-of-contents">
<ul class="list-unstyled mb-0">
<li class="mb-2"><a href="#introduction" class="text-decoration-none">Introduction to Bootstrap 5</a></li>
<li class="mb-2"><a href="#installation" class="text-decoration-none">Installation Methods</a></li>
<li class="mb-2"><a href="#grid" class="text-decoration-none">Grid System Overview</a></li>
<li class="mb-2"><a href="#components" class="text-decoration-none">Key Components</a></li>
<li><a href="#conclusion" class="text-decoration-none">Conclusion</a></li>
</ul>
</nav>
</div>
</div>
<!-- Article Sections -->
<h2 id="introduction" class="h3 mt-5 mb-3">Introduction to Bootstrap 5</h2>
<p>Bootstrap 5 is the latest version of the world's most popular front-end framework. It comes with several major changes and improvements.</p>
<!-- Code Block -->
<div class="card mb-4">
<div class="card-header bg-dark text-white">
<div class="d-flex justify-content-between align-items-center">
<span>HTML Example</span>
<button class="btn btn-sm btn-outline-light" onclick="copyCode(this)">
<i class="fas fa-copy me-1"></i> Copy
</button>
</div>
</div>
<div class="card-body bg-light">
<pre class="mb-0"><code><!-- Bootstrap 5 Basic Template -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bootstrap 5 Template</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<h1>Hello, Bootstrap 5!</h1>
<!-- Bootstrap JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html></code></pre>
</div>
</div>
<!-- More article content -->
<!-- Tags -->
<div class="mt-5">
<h6 class="mb-3"><i class="fas fa-tags me-2"></i>Tags</h6>
<div class="d-flex flex-wrap gap-2">
<a href="#" class="badge bg-primary text-decoration-none p-2">Bootstrap</a>
<a href="#" class="badge bg-primary text-decoration-none p-2">Web Development</a>
<a href="#" class="badge bg-primary text-decoration-none p-2">Frontend</a>
<a href="#" class="badge bg-primary text-decoration-none p-2">CSS Framework</a>
</div>
</div>
<!-- Author Bio -->
<div class="card mt-5">
<div class="card-body">
<div class="row">
<div class="col-md-3 text-center mb-3 mb-md-0">
<img src="https://via.placeholder.com/100" class="rounded-circle" alt="Author">
</div>
<div class="col-md-9">
<h5 class="card-title">About the Author</h5>
<p class="card-text">Alex Johnson is a senior front-end developer with 10+ years of experience. He specializes in responsive design and modern CSS frameworks.</p>
<div class="d-flex gap-3">
<a href="#" class="text-muted"><i class="fab fa-twitter"></i></a>
<a href="#" class="text-muted"><i class="fab fa-github"></i></a>
<a href="#" class="text-muted"><i class="fab fa-linkedin"></i></a>
</div>
</div>
</div>
</div>
</div>
<!-- Comments Section -->
<div class="mt-5">
<h3 class="mb-4">
<i class="far fa-comments me-2"></i>Comments (12)
</h3>
<!-- Comment Form -->
<div class="card mb-4">
<div class="card-body">
<h5 class="card-title mb-3">Leave a Comment</h5>
<form>
<div class="mb-3">
<textarea class="form-control" rows="4" placeholder="Write your comment..."></textarea>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<input type="text" class="form-control" placeholder="Your name">
</div>
<div class="col-md-6 mb-3">
<input type="email" class="form-control" placeholder="Your email">
</div>
</div>
<button type="submit" class="btn btn-primary">Post Comment</button>
</form>
</div>
</div>
<!-- Comments List -->
<div class="comments-list">
<!-- Comment -->
<div class="d-flex mb-4">
<img src="https://via.placeholder.com/40" class="rounded-circle me-3" alt="User">
<div class="flex-grow-1">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0">Sarah Miller</h6>
<small class="text-muted">2 hours ago</small>
</div>
<p class="mb-2">Great tutorial! The code examples were very helpful.</p>
<div>
<button class="btn btn-sm btn-outline-primary">Reply</button>
<button class="btn btn-sm btn-outline-secondary ms-2">Like</button>
</div>
<!-- Reply -->
<div class="d-flex mt-4">
<img src="https://via.placeholder.com/30" class="rounded-circle me-3" alt="User">
<div class="flex-grow-1">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0">Author</h6>
<small class="text-muted">1 hour ago</small>
</div>
<p class="mb-2">Thank you Sarah! I'm glad you found it helpful.</p>
</div>
</div>
</div>
</div>
<!-- More comments -->
</div>
</div>
</div>
</article>
<!-- Related Posts -->
<div class="mt-5">
<h3 class="mb-4">Related Articles</h3>
<div class="row">
<div class="col-md-6 mb-4">
<div class="card border-0 shadow-sm h-100">
<img src="https://via.placeholder.com/400x200" class="card-img-top" alt="Related">
<div class="card-body">
<h5 class="card-title">Advanced Bootstrap Customization</h5>
<p class="card-text text-muted small">Learn how to customize Bootstrap 5 with SASS and CSS variables.</p>
</div>
</div>
</div>
<div class="col-md-6 mb-4">
<div class="card border-0 shadow-sm h-100">
<img src="https://via.placeholder.com/400x200" class="card-img-top" alt="Related">
<div class="card-body">
<h5 class="card-title">Bootstrap vs Tailwind CSS</h5>
<p class="card-text text-muted small">Comparison between two popular CSS frameworks.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer class="bg-dark text-white py-5">
<div class="container">
<div class="row">
<div class="col-lg-4 mb-4">
<h5 class="mb-3">
<i class="fas fa-blog text-primary me-2"></i>TechBlog
</h5>
<p class="text-white-50">A blog about web development, programming, and technology trends.</p>
<div class="d-flex gap-3 mt-4">
<a href="#" class="text-white-50"><i class="fab fa-twitter fa-lg"></i></a>
<a href="#" class="text-white-50"><i class="fab fa-facebook fa-lg"></i></a>
<a href="#" class="text-white-50"><i class="fab fa-github fa-lg"></i></a>
<a href="#" class="text-white-50"><i class="fab fa-linkedin fa-lg"></i></a>
</div>
</div>
<div class="col-lg-2 col-md-6 mb-4">
<h5 class="mb-3">Quick Links</h5>
<ul class="list-unstyled">
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Home</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Categories</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Tutorials</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">About</a></li>
</ul>
</div>
<div class="col-lg-3 col-md-6 mb-4">
<h5 class="mb-3">Categories</h5>
<ul class="list-unstyled">
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Web Development</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">Mobile Apps</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">UI/UX Design</a></li>
<li class="mb-2"><a href="#" class="text-white-50 text-decoration-none">DevOps</a></li>
</ul>
</div>
<div class="col-lg-3 mb-4">
<h5 class="mb-3">Stay Updated</h5>
<p class="text-white-50">Subscribe to our newsletter for the latest articles.</p>
<div class="input-group mb-3">
<input type="email" class="form-control" placeholder="Your email">
<button class="btn btn-primary" type="button">Subscribe</button>
</div>
</div>
</div>
<hr class="my-4 text-white-50">
<div class="row">
<div class="col-md-6">
<p class="mb-0">© 2024 TechBlog. All rights reserved.</p>
</div>
<div class="col-md-6 text-md-end">
<a href="#" class="text-white-50 text-decoration-none me-3">Privacy Policy</a>
<a href="#" class="text-white-50 text-decoration-none">Terms of Service</a>
</div>
</div>
</div>
</footer>Blog Styling CSS
Custom Blog Styles
/* Blog Custom Styles */
:root {
--primary-color: #0d6efd;
--secondary-color: #6c757d;
--success-color: #198754;
--light-color: #f8f9fa;
--dark-color: #212529;
}
/* Typography for Blog */
.blog-post h1, .blog-post h2, .blog-post h3, .blog-post h4 {
margin-top: 2rem;
margin-bottom: 1rem;
font-weight: 600;
}
.blog-post h1 {
font-size: 2.5rem;
border-bottom: 2px solid var(--primary-color);
padding-bottom: 0.5rem;
}
.blog-post h2 {
font-size: 2rem;
color: var(--dark-color);
}
.blog-post h3 {
font-size: 1.5rem;
color: var(--dark-color);
}
.blog-post p {
line-height: 1.8;
margin-bottom: 1.5rem;
font-size: 1.1rem;
}
.blog-post ul, .blog-post ol {
margin-bottom: 1.5rem;
padding-left: 2rem;
}
.blog-post li {
margin-bottom: 0.5rem;
line-height: 1.6;
}
/* Code Blocks */
.blog-post pre {
background-color: #1e1e1e;
color: #d4d4d4;
padding: 1rem;
border-radius: 0.5rem;
overflow-x: auto;
margin: 1.5rem 0;
}
.blog-post code {
background-color: #f8f9fa;
padding: 0.2rem 0.4rem;
border-radius: 0.25rem;
font-family: 'Courier New', monospace;
font-size: 0.9em;
}
.blog-post pre code {
background-color: transparent;
padding: 0;
color: inherit;
}
/* Blockquotes */
.blog-post blockquote {
border-left: 4px solid var(--primary-color);
padding-left: 1.5rem;
margin: 1.5rem 0;
font-style: italic;
color: var(--secondary-color);
}
.blog-post blockquote p:last-child {
margin-bottom: 0;
}
/* Images in Blog Posts */
.blog-post img {
max-width: 100%;
height: auto;
border-radius: 0.5rem;
margin: 1.5rem 0;
}
.blog-post .img-caption {
text-align: center;
font-style: italic;
color: var(--secondary-color);
margin-top: -1rem;
margin-bottom: 1.5rem;
}
/* Tables */
.blog-post table {
width: 100%;
margin: 1.5rem 0;
border-collapse: collapse;
}
.blog-post table th,
.blog-post table td {
padding: 0.75rem;
border: 1px solid #dee2e6;
text-align: left;
}
.blog-post table th {
background-color: var(--light-color);
font-weight: 600;
}
.blog-post table tr:nth-child(even) {
background-color: rgba(0, 0, 0, 0.02);
}
/* Hero Section */
.hero-section {
background: linear-gradient(135deg, var(--light-color) 0%, #e9ecef 100%);
}
/* Blog Cards */
.blog-card {
transition: all 0.3s ease;
border-radius: 10px;
overflow: hidden;
}
.blog-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1) !important;
}
.blog-card .card-img-top {
height: 200px;
object-fit: cover;
transition: transform 0.3s ease;
}
.blog-card:hover .card-img-top {
transform: scale(1.05);
}
/* Author Bio */
.author-bio {
background-color: var(--light-color);
border-radius: 10px;
padding: 1.5rem;
}
.author-bio img {
width: 100px;
height: 100px;
object-fit: cover;
}
/* Comments */
.comment {
border-bottom: 1px solid #dee2e6;
padding-bottom: 1.5rem;
margin-bottom: 1.5rem;
}
.comment:last-child {
border-bottom: none;
margin-bottom: 0;
}
.comment-reply {
margin-left: 3rem;
margin-top: 1rem;
padding-left: 1.5rem;
border-left: 2px solid var(--light-color);
}
/* Newsletter Form */
.newsletter-form .form-control {
border-radius: 0.5rem;
border: 2px solid #dee2e6;
padding: 0.75rem 1rem;
}
.newsletter-form .btn {
border-radius: 0.5rem;
}
/* Tags */
.tag-cloud {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag-cloud a {
text-decoration: none;
transition: all 0.3s ease;
}
.tag-cloud a:hover {
transform: translateY(-2px);
text-decoration: underline;
}
/* Table of Contents */
.table-of-contents {
position: sticky;
top: 20px;
}
.table-of-contents a {
color: var(--dark-color);
text-decoration: none;
transition: all 0.3s ease;
display: block;
padding: 0.5rem 0;
border-left: 3px solid transparent;
padding-left: 1rem;
}
.table-of-contents a:hover {
color: var(--primary-color);
border-left-color: var(--primary-color);
padding-left: 1.5rem;
}
.table-of-contents li.active a {
color: var(--primary-color);
border-left-color: var(--primary-color);
font-weight: 600;
}
/* Social Sharing */
.social-sharing {
display: flex;
gap: 0.5rem;
margin: 1.5rem 0;
}
.social-sharing a {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--light-color);
color: var(--dark-color);
transition: all 0.3s ease;
}
.social-sharing a:hover {
background-color: var(--primary-color);
color: white;
transform: translateY(-2px);
text-decoration: none;
}
/* Reading Progress Bar */
.reading-progress {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 3px;
background-color: #e9ecef;
z-index: 9999;
}
.reading-progress-bar {
height: 100%;
background-color: var(--primary-color);
width: 0%;
transition: width 0.3s ease;
}
/* Print Styles */
@media print {
.navbar,
.sidebar,
.comments-section,
.social-sharing,
.newsletter-form,
footer {
display: none !important;
}
.blog-post {
font-size: 12pt;
line-height: 1.6;
}
.blog-post h1 {
font-size: 18pt;
}
.blog-post h2 {
font-size: 16pt;
}
.blog-post img {
max-width: 100% !important;
}
a {
color: black !important;
text-decoration: none !important;
}
a:after {
content: " (" attr(href) ")";
font-size: 0.9em;
font-weight: normal;
}
}
/* Dark Theme for Blog */
.dark-theme .blog-post {
color: #f8f9fa;
}
.dark-theme .blog-post h1,
.dark-theme .blog-post h2,
.dark-theme .blog-post h3 {
color: #f8f9fa;
}
.dark-theme .blog-post code:not(pre code) {
background-color: #2d3748;
color: #e2e8f0;
}
.dark-theme .card {
background-color: #2d3748;
border-color: #4a5568;
}
.dark-theme .table-of-contents a {
color: #e2e8f0;
}
.dark-theme .social-sharing a {
background-color: #2d3748;
color: #e2e8f0;
}
/* Responsive Adjustments */
@media (max-width: 768px) {
.blog-post h1 {
font-size: 2rem;
}
.blog-post h2 {
font-size: 1.75rem;
}
.blog-post h3 {
font-size: 1.5rem;
}
.comment-reply {
margin-left: 1.5rem;
}
.table-of-contents {
position: static;
margin-bottom: 2rem;
}
}
/* Animations */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.fade-in-up {
animation: fadeInUp 0.5s ease-out;
}
/* Code Copy Button */
.code-copy-btn {
position: absolute;
top: 0.5rem;
right: 0.5rem;
opacity: 0;
transition: opacity 0.3s ease;
}
pre:hover .code-copy-btn {
opacity: 1;
}
.code-copy-btn.copied {
background-color: var(--success-color);
border-color: var(--success-color);
}
/* Lazy Loading Images */
.blog-img {
opacity: 0;
transition: opacity 0.3s ease;
}
.blog-img.loaded {
opacity: 1;
}Blog JavaScript Functionality
Interactive Features
// Blog JavaScript Functionality
class BlogSystem {
constructor() {
this.comments = JSON.parse(localStorage.getItem('comments')) || [];
this.likedPosts = JSON.parse(localStorage.getItem('likedPosts')) || [];
this.bookmarkedPosts = JSON.parse(localStorage.getItem('bookmarkedPosts')) || [];
this.init();
}
init() {
this.bindEvents();
this.setupReadingProgress();
this.setupTableOfContents();
this.setupCodeCopy();
this.setupLazyLoading();
this.setupCommentSystem();
this.loadComments();
}
bindEvents() {
// Like buttons
document.querySelectorAll('.btn-like').forEach(button => {
button.addEventListener('click', (e) => {
const postId = e.target.closest('[data-post-id]').dataset.postId;
this.toggleLike(postId, e.target);
});
});
// Bookmark buttons
document.querySelectorAll('.btn-bookmark').forEach(button => {
button.addEventListener('click', (e) => {
const postId = e.target.closest('[data-post-id]').dataset.postId;
this.toggleBookmark(postId, e.target);
});
});
// Comment form submission
const commentForm = document.getElementById('commentForm');
if (commentForm) {
commentForm.addEventListener('submit', (e) => {
e.preventDefault();
this.submitComment(commentForm);
});
}
// Reply buttons
document.querySelectorAll('.btn-reply').forEach(button => {
button.addEventListener('click', (e) => {
this.showReplyForm(e.target.dataset.commentId);
});
});
// Newsletter subscription
const newsletterForm = document.querySelector('.newsletter-form');
if (newsletterForm) {
newsletterForm.addEventListener('submit', (e) => {
e.preventDefault();
this.subscribeNewsletter(newsletterForm);
});
}
// Search functionality
const searchForm = document.querySelector('.search-form');
if (searchForm) {
searchForm.addEventListener('submit', (e) => {
e.preventDefault();
this.searchArticles(searchForm.querySelector('input').value);
});
}
// Theme toggle
const themeToggle = document.getElementById('themeToggle');
if (themeToggle) {
themeToggle.addEventListener('click', () => {
this.toggleTheme();
});
}
}
toggleLike(postId, button) {
const index = this.likedPosts.indexOf(postId);
const icon = button.querySelector('i');
const countElement = button.querySelector('.like-count');
if (index > -1) {
// Unlike
this.likedPosts.splice(index, 1);
icon.classList.remove('fas', 'text-danger');
icon.classList.add('far');
button.classList.remove('active');
} else {
// Like
this.likedPosts.push(postId);
icon.classList.remove('far');
icon.classList.add('fas', 'text-danger');
button.classList.add('active');
}
// Update count
if (countElement) {
let count = parseInt(countElement.textContent);
count = index > -1 ? count - 1 : count + 1;
countElement.textContent = count;
}
localStorage.setItem('likedPosts', JSON.stringify(this.likedPosts));
}
toggleBookmark(postId, button) {
const index = this.bookmarkedPosts.indexOf(postId);
const icon = button.querySelector('i');
if (index > -1) {
// Remove bookmark
this.bookmarkedPosts.splice(index, 1);
icon.classList.remove('fas', 'text-warning');
icon.classList.add('far');
button.classList.remove('active');
} else {
// Add bookmark
this.bookmarkedPosts.push(postId);
icon.classList.remove('far');
icon.classList.add('fas', 'text-warning');
button.classList.add('active');
}
localStorage.setItem('bookmarkedPosts', JSON.stringify(this.bookmarkedPosts));
}
setupReadingProgress() {
const progressBar = document.createElement('div');
progressBar.className = 'reading-progress';
progressBar.innerHTML = '<div class="reading-progress-bar"></div>';
document.body.appendChild(progressBar);
window.addEventListener('scroll', () => {
const winScroll = document.body.scrollTop || document.documentElement.scrollTop;
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
const scrolled = (winScroll / height) * 100;
progressBar.querySelector('.reading-progress-bar').style.width = scrolled + '%';
});
}
setupTableOfContents() {
const toc = document.querySelector('.table-of-contents');
if (!toc) return;
const headings = document.querySelectorAll('h2, h3');
const tocItems = Array.from(toc.querySelectorAll('a'));
// Highlight current section in TOC
window.addEventListener('scroll', () => {
let current = '';
headings.forEach(heading => {
const headingTop = heading.offsetTop;
if (window.scrollY >= headingTop - 100) {
current = heading.id;
}
});
tocItems.forEach(item => {
item.parentElement.classList.remove('active');
if (item.getAttribute('href') === `#${current}`) {
item.parentElement.classList.add('active');
}
});
});
// Smooth scroll for TOC links
tocItems.forEach(item => {
item.addEventListener('click', (e) => {
e.preventDefault();
const targetId = item.getAttribute('href');
const targetElement = document.querySelector(targetId);
if (targetElement) {
window.scrollTo({
top: targetElement.offsetTop - 80,
behavior: 'smooth'
});
}
});
});
}
setupCodeCopy() {
document.querySelectorAll('pre').forEach(pre => {
const button = document.createElement('button');
button.className = 'btn btn-sm btn-outline-secondary code-copy-btn';
button.innerHTML = '<i class="fas fa-copy me-1"></i> Copy';
button.addEventListener('click', () => {
const code = pre.querySelector('code').textContent;
navigator.clipboard.writeText(code).then(() => {
const originalHTML = button.innerHTML;
button.innerHTML = '<i class="fas fa-check me-1"></i> Copied!';
button.classList.add('copied');
setTimeout(() => {
button.innerHTML = originalHTML;
button.classList.remove('copied');
}, 2000);
});
});
pre.appendChild(button);
});
}
setupLazyLoading() {
const images = document.querySelectorAll('.blog-img');
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.add('loaded');
observer.unobserve(img);
}
});
});
images.forEach(img => imageObserver.observe(img));
}
setupCommentSystem() {
const commentForm = document.getElementById('commentForm');
if (commentForm) {
// Load existing comments
this.loadComments();
}
}
submitComment(form) {
const formData = new FormData(form);
const comment = {
id: Date.now().toString(),
author: formData.get('author'),
email: formData.get('email'),
content: formData.get('content'),
date: new Date().toISOString(),
postId: form.dataset.postId,
parentId: form.dataset.parentId || null,
replies: []
};
if (form.dataset.parentId) {
// Add as reply
const parentComment = this.findComment(this.comments, form.dataset.parentId);
if (parentComment) {
parentComment.replies.push(comment);
}
} else {
// Add as top-level comment
this.comments.push(comment);
}
localStorage.setItem('comments', JSON.stringify(this.comments));
this.loadComments();
form.reset();
this.showNotification('Comment submitted successfully!', 'success');
}
findComment(comments, id) {
for (const comment of comments) {
if (comment.id === id) {
return comment;
}
if (comment.replies && comment.replies.length > 0) {
const found = this.findComment(comment.replies, id);
if (found) return found;
}
}
return null;
}
loadComments() {
const container = document.querySelector('.comments-list');
if (!container) return;
const postId = container.dataset.postId;
const postComments = this.comments.filter(comment =>
comment.postId === postId && !comment.parentId
);
container.innerHTML = this.renderComments(postComments);
}
renderComments(comments) {
return comments.map(comment => `
<div class="comment" data-comment-id="${comment.id}">
<div class="d-flex">
<img src="https://via.placeholder.com/40" class="rounded-circle me-3" alt="${comment.author}">
<div class="flex-grow-1">
<div class="d-flex justify-content-between align-items-center mb-2">
<h6 class="mb-0">${comment.author}</h6>
<small class="text-muted">${this.formatDate(comment.date)}</small>
</div>
<p class="mb-2">${comment.content}</p>
<div>
<button class="btn btn-sm btn-outline-primary btn-reply" data-comment-id="${comment.id}">
Reply
</button>
</div>
${comment.replies && comment.replies.length > 0 ? `
<div class="comment-replies mt-3">
${this.renderComments(comment.replies)}
</div>
` : ''}
</div>
</div>
</div>
`).join('');
}
showReplyForm(commentId) {
const commentElement = document.querySelector(`[data-comment-id="${commentId}"]`);
const existingForm = commentElement.querySelector('.reply-form');
if (existingForm) {
existingForm.remove();
return;
}
const formHTML = `
<div class="reply-form mt-3">
<form class="comment-form" data-parent-id="${commentId}">
<div class="mb-3">
<textarea class="form-control" rows="2" placeholder="Write your reply..." required></textarea>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<input type="text" class="form-control" placeholder="Your name" required>
</div>
<div class="col-md-6 mb-3">
<input type="email" class="form-control" placeholder="Your email" required>
</div>
</div>
<div class="d-flex gap-2">
<button type="submit" class="btn btn-primary btn-sm">Post Reply</button>
<button type="button" class="btn btn-secondary btn-sm cancel-reply">Cancel</button>
</div>
</form>
</div>
`;
commentElement.insertAdjacentHTML('beforeend', formHTML);
// Bind form submission
const form = commentElement.querySelector('.comment-form');
form.addEventListener('submit', (e) => {
e.preventDefault();
this.submitComment(form);
});
// Bind cancel button
const cancelBtn = commentElement.querySelector('.cancel-reply');
cancelBtn.addEventListener('click', () => {
commentElement.querySelector('.reply-form').remove();
});
}
subscribeNewsletter(form) {
const email = form.querySelector('input[type="email"]').value;
// In a real app, you would send this to your server
console.log('Newsletter subscription:', email);
this.showNotification('Successfully subscribed to newsletter!', 'success');
form.reset();
}
searchArticles(query) {
// In a real app, you would make an API call
console.log('Searching for:', query);
// For demo purposes, show a message
this.showNotification(`Search results for: "${query}"`, 'info');
}
toggleTheme() {
document.body.classList.toggle('dark-theme');
const theme = document.body.classList.contains('dark-theme') ? 'dark' : 'light';
localStorage.setItem('blog-theme', theme);
}
formatDate(dateString) {
const date = new Date(dateString);
const now = new Date();
const diffMs = now - date;
const diffMins = Math.floor(diffMs / 60000);
const diffHours = Math.floor(diffMs / 3600000);
const diffDays = Math.floor(diffMs / 86400000);
if (diffMins < 60) {
return `${diffMins} minute${diffMins !== 1 ? 's' : ''} ago`;
} else if (diffHours < 24) {
return `${diffHours} hour${diffHours !== 1 ? 's' : ''} ago`;
} else if (diffDays < 7) {
return `${diffDays} day${diffDays !== 1 ? 's' : ''} ago`;
} else {
return date.toLocaleDateString();
}
}
showNotification(message, type = 'info') {
const notification = document.createElement('div');
notification.className = `alert alert-${type} alert-dismissible fade show position-fixed`;
notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999;';
notification.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
}
}
// Initialize blog system when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
window.blog = new BlogSystem();
// Load saved theme
const savedTheme = localStorage.getItem('blog-theme');
if (savedTheme === 'dark') {
document.body.classList.add('dark-theme');
}
// Initialize Bootstrap components
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
tooltipTriggerList.map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
// Initialize carousel if exists
const carousel = document.querySelector('.carousel');
if (carousel) {
new bootstrap.Carousel(carousel);
}
});
// Utility function to estimate reading time
function estimateReadingTime(text) {
const wordsPerMinute = 200;
const wordCount = text.split(/s+/).length;
const readingTime = Math.ceil(wordCount / wordsPerMinute);
return readingTime;
}
// Update reading time on page load
document.addEventListener('DOMContentLoaded', () => {
const articleContent = document.querySelector('.article-content');
if (articleContent) {
const text = articleContent.textContent;
const readingTime = estimateReadingTime(text);
const readingTimeElement = document.querySelector('.reading-time');
if (readingTimeElement) {
readingTimeElement.textContent = `${readingTime} min read`;
}
}
});
// Social sharing functionality
function shareOnSocial(platform) {
const url = encodeURIComponent(window.location.href);
const title = encodeURIComponent(document.title);
const text = encodeURIComponent('Check out this article!');
const shareUrls = {
twitter: `https://twitter.com/intent/tweet?url=${url}&text=${title}`,
facebook: `https://www.facebook.com/sharer/sharer.php?u=${url}`,
linkedin: `https://www.linkedin.com/shareArticle?mini=true&url=${url}&title=${title}`,
whatsapp: `https://wa.me/?text=${title} ${url}`
};
if (shareUrls[platform]) {
window.open(shareUrls[platform], '_blank', 'width=600,height=400');
}
}Blog Features Overview
| Feature | Description | Components Used |
|---|---|---|
| Blog Listing | Display articles with excerpts, metadata, and images | Cards, Grid System, Badges, Buttons |
| Single Post | Detailed article view with formatting and code blocks | Typography, Code Blocks, Images, Tables |
| Comments System | User comments with reply functionality | Forms, LocalStorage, Nested Comments |
| Categories & Tags | Organize content by topics | Badges, Links, Filtering |
| Author System | Author profiles and bios | Cards, Images, Social Links |
| Search Functionality | Search articles by keywords | Search Forms, JavaScript Filtering |
| Social Sharing | Share articles on social media | Social Icons, Share URLs |
| Newsletter | Email subscription for updates | Forms, Validation, LocalStorage |
SEO Optimization for Blogs
Blog SEO Best Practices
- Structured Data: Implement Article schema markup
- Meta Tags: Title, description, keywords, Open Graph
- URL Structure: Clean, readable URLs with keywords
- Internal Linking: Link to related articles
- Image Optimization: Alt text, proper file names, compression
- Mobile-Friendly: Responsive design, fast loading
- Content Quality: Comprehensive, valuable content
- Social Media: Shareable content, social meta tags
Performance Optimization
Blog Performance Tips
- Lazy load images and videos
- Optimize and compress images
- Minify CSS and JavaScript
- Implement proper caching
- Use CDN for static assets
- Reduce third-party scripts
- Implement code splitting
- Optimize web fonts