Fixed-left Sidebar utilizing Bootstrap5 examples

Viewed 4670

I'm trying to create a fixed-left sidebar following the Bootstrap 5 Sidebar examples and I almost have everything setup correctly. My requirements are:

  • Sidebar needs to be fixed
  • Main content needs to be vertically and horizontally-centered
  • footer-info needs to be fixed at the bottom

Two problems I have are

  1. the main content jumps below the Sidebar when the screen gets too small. I would like to force the Sidebar and Main content remain side-by-side and have an x-axis scroll appear if need be while maintaining the Main content to be centered.
  2. I'm having a hard time centering my main content.

Included is my work in progress

<!doctype html>
<html lang="en">

<head>
  <!-- Required meta tags -->
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,
    initial-scale=1, shrink-to-fit=no">

  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" />
  <title>
    {% block title %} BRAND NAME {% endblock title %}
  </title>
</head>
<style>
  body {
    min-height: 100vh;
    min-height: -webkit-fill-available;
  }
  
  html {
    height: -webkit-fill-available;
  }
  
  main {
    display: flex;
    flex-wrap: nowrap;
    height: 100vh;
    height: -webkit-fill-available;
    max-height: 100vh;
    overflow-x: auto;
    overflow-y: hidden;
  }
  
  .sidebar {
    background-color: #adb5bd;
  }
  
  .sidebar .nav a:hover,
  .sidebar .nav a:focus {
    background-color: #dc3545;
  }
  
  .btn-toggle {
    display: inline-flex;
    align-items: center;
    padding: .25rem .5rem;
    font-weight: 600;
    color: rgba(0, 0, 0, .65);
    background-color: transparent;
    border: 0;
  }
  
  .btn-toggle::before {
    width: 1.25em;
    line-height: 0;
    transition: transform .35s ease;
    transform-origin: .5em 50%;
    content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e");
  }
  
  .btn-toggle[aria-expanded="true"]::before {
    transform: rotate(90deg);
  }
  
  .btn-toggle-nav a {
    display: inline-flex;
    padding: .1875rem .5rem;
    margin-top: .125rem;
    margin-left: 2rem;
    text-decoration: none;
    color: white;
  }
  
  .btn-toggle-nav a:hover,
  .btn-toggle-nav a:focus {
    background-color: #dc3545;
    color: white;
  }
  
  .login-menu {
    padding: 2rem 1rem;
    width: 250px;
  }
</style>

<body>
  <div class="container-fluid overflow-hidden">
    <div class="row vh-100 overflow-auto">
      <div class="sidebar d-flex flex-column flex-shrink-0 p-3" style="width: 240px;">
        <a href="#" class="navbar-brand d-flex align-items-center mb-3">
          BRAND NAME
        </a>
        <ul class="nav nav-pills flex-column mb-auto">
          <li class="mb-1">
            <a class="btn btn-toggle d-flex align-items-center rounded collapsed text-white" data-bs-toggle="collapse" data-bs-target="#csd-menu">
              <span class="mif-books mif-3x ms-1 me-2"></span> Create New...
            </a>
            <div class="collapse" id="csd-menu">
              <ul class="btn-toggle-nav list-unstyled fw-normal pb-1 small">
                <li><a href="#" class="link-dark rounded">Site</a></li>
                <li><a href="#" class="link-dark rounded">System</a></li>
                <li><a href="#" class="link-dark rounded">CSD</a></li>
                <li><a href="#" class="link-dark rounded">Circuit</a></li>
              </ul>
            </div>
          </li>
          <li class="mb-1">
            <a class="btn d-flex align-items-center rounded text-white">
              <svg xmlns="http://www.w3.org/2000/svg" width="30" fill="currentColor" class="bi bi-diagram-3 me-2" viewBox="0 0 16 16">
                <path fill-rule="evenodd" d="M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H14a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 2 7h5.5V6A1.5 1.5 0 0 1 6 4.5v-1zM8.5 5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1zM0 11.5A1.5 1.5 0 0 1 1.5 10h1A1.5 1.5 0 0 1 4 11.5v1A1.5 1.5 0 0 1 2.5 14h-1A1.5 1.5 0 0 1 0 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5A1.5 1.5 0 0 1 7.5 10h1a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 8.5 14h-1A1.5 1.5 0 0 1 6 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1z"/>
              </svg> Systems
            </a>
          </li>
        </ul>
        <hr>
        <div class="nav-link dropdown">
          <a href="#" class="d-flex align-items-center text-danger text-decoration-none dropdown-toggle" data-bs-toggle="dropdown">
            <h3>
              <strong>
                              Login
                          </strong>
            </h3>
          </a>
          <div class="dropdown-menu login-menu bg-secondary text-white shadow">
            <form action='/users/login_user/' method='POST' id="form-login-user">
              <div class="mb-1">
                <input type="username" class="form-control" id="username" placeholder="username">
              </div>
              <div class="mb-3">
                <input type="password" class="form-control" id="password" placeholder="password">
              </div>
              <button type="submit" class="btn btn-primary">Submit</button>
            </form>
          </div>
        </div>
        <ul class="nav nav-pills flex-column">
          <li class="mb-1">
            <a class="btn d-flex align-items-center rounded text-white">
                      Documentation
                  </a>
          </li>
          <li class="mb-1">
            <a class="btn d-flex align-items-center rounded text-white">
                      Help
                  </a>
          </li>
        </ul>
      </div>
      <div class="col d-flex flex-column h-sm-100">
        <main class="row overflow-auto">
          <div class="col">
            <h1 class="display-3 text-center">
              Circuits
            </h1>
            <div class="d-flex justify-content-center">
              <form class="loading" action="/search/" method="get">
                <input type="search" class="form-control" placeholder="Search..." aria-label="Search">
              </form>
            </div>
          </div>
        </main>
        <footer class="footer row mt-auto align-items-end justify-content-end text-muted">
          <div class="col"></div>
          <div class="col-auto text-center">
            Powered by
            <img src="{% static 'images/gloo_logo.png' %}" class="rounded my-2" alt="GLOO">
          </div>
          <div class="col text-end me-4">
            <div>
              version: [version_number]
            </div>
          </div>
        </footer>
        <br>
      </div>
    </div>
  </div>
  {% csrf_token %}
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>

</html>

2 Answers

Ok, seems I was able to resolve issue 1 where the main content would want to stack below the sidebar if the window became too small. Looking at the Bootstrap Flex Utilities I was able to utilize a .flex-row and .flex-column.flex-grow-1 combination. The Sidebar remains fixed even when I add a bunch of content to the right-side.

I am still having difficulty centering my search form while making my footer rest at the bottom. I have tried two different setups and each resolves part of my problem creating another problem:

  1. I can add a .justify-content-center to my flex-column to make my form vertically-centered but my footer will want to be placed centered as well. Here is this example.
  2. I can add a .mt-auto to my footer but then my search form want to be placed at the top of the page. Here is this example.

Try this as "Bootstrap 5 sidebar Example"

document.addEventListener("DOMContentLoaded", function(event) {

  const showNavbar = (toggleId, navId, bodyId, headerId) => {
    const toggle = document.getElementById(toggleId),
      nav = document.getElementById(navId),
      bodypd = document.getElementById(bodyId),
      headerpd = document.getElementById(headerId)

    // Validate that all variables exist
    if (toggle && nav && bodypd && headerpd) {
      toggle.addEventListener('click', () => {
        // show navbar
        nav.classList.toggle('show')
        // change icon
        toggle.classList.toggle('bx-x')
        // add padding to body
        bodypd.classList.toggle('body-pd')
        // add padding to header
        headerpd.classList.toggle('body-pd')
      })
    }
  }

  showNavbar('header-toggle', 'nav-bar', 'body-pd', 'header')

  /*===== LINK ACTIVE =====*/
  const linkColor = document.querySelectorAll('.nav_link')

  function colorLink() {
    if (linkColor) {
      linkColor.forEach(l => l.classList.remove('active'))
      this.classList.add('active')
    }
  }
  linkColor.forEach(l => l.addEventListener('click', colorLink))

  // Your code to run since DOM is loaded and ready
});
@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap");
:root {
  --header-height: 3rem;
  --nav-width: 68px;
  --first-color: #4723D9;
  --first-color-light: #AFA5D9;
  --white-color: #F7F6FB;
  --body-font: 'Nunito', sans-serif;
  --normal-font-size: 1rem;
  --z-fixed: 100
}

*,
::before,
::after {
  box-sizing: border-box
}

body {
  position: relative;
  margin: var(--header-height) 0 0 0;
  padding: 0 1rem;
  font-family: var(--body-font);
  font-size: var(--normal-font-size);
  transition: .5s
}

a {
  text-decoration: none
}

.header {
  width: 100%;
  height: var(--header-height);
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 1rem;
  background-color: var(--white-color);
  z-index: var(--z-fixed);
  transition: .5s
}

.header_toggle {
  color: var(--first-color);
  font-size: 1.5rem;
  cursor: pointer
}

.header_img {
  width: 35px;
  height: 35px;
  display: flex;
  justify-content: center;
  border-radius: 50%;
  overflow: hidden
}

.header_img img {
  width: 40px
}

.l-navbar {
  position: fixed;
  top: 0;
  left: -30%;
  width: var(--nav-width);
  height: 100vh;
  background-color: var(--first-color);
  padding: .5rem 1rem 0 0;
  transition: .5s;
  z-index: var(--z-fixed)
}

.nav {
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  overflow: hidden
}

.nav_logo,
.nav_link {
  display: grid;
  grid-template-columns: max-content max-content;
  align-items: center;
  column-gap: 1rem;
  padding: .5rem 0 .5rem 1.5rem
}

.nav_logo {
  margin-bottom: 2rem
}

.nav_logo-icon {
  font-size: 1.25rem;
  color: var(--white-color)
}

.nav_logo-name {
  color: var(--white-color);
  font-weight: 700
}

.nav_link {
  position: relative;
  color: var(--first-color-light);
  margin-bottom: 1.5rem;
  transition: .3s
}

.nav_link:hover {
  color: var(--white-color)
}

.nav_icon {
  font-size: 1.25rem
}

.show {
  left: 0
}

.body-pd {
  padding-left: calc(var(--nav-width) + 1rem)
}

.active {
  color: var(--white-color)
}

.active::before {
  content: '';
  position: absolute;
  left: 0;
  width: 2px;
  height: 32px;
  background-color: var(--white-color)
}

.height-100 {
  height: 100vh
}

@media screen and (min-width: 768px) {
  body {
    margin: calc(var(--header-height) + 1rem) 0 0 0;
    padding-left: calc(var(--nav-width) + 2rem)
  }
  .header {
    height: calc(var(--header-height) + 1rem);
    padding: 0 2rem 0 calc(var(--nav-width) + 2rem)
  }
  .header_img {
    width: 40px;
    height: 40px
  }
  .header_img img {
    width: 45px
  }
  .l-navbar {
    left: 0;
    padding: 1rem 1rem 0 0
  }
  .show {
    width: calc(var(--nav-width) + 156px)
  }
  .body-pd {
    padding-left: calc(var(--nav-width) + 188px)
  }
}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" />

<body id="body-pd">
  <header class="header" id="header">
    <div class="header_toggle"> <i class='bx bx-menu' id="header-toggle"></i> </div>
    <div class="header_img"> <img src="https://i.imgur.com/hczKIze.jpg" alt=""> </div>
  </header>
  <div class="l-navbar" id="nav-bar">
    <nav class="nav">
      <div>
        <a href="#" class="nav_logo"> <i class='bx bx-layer nav_logo-icon'></i> <span class="nav_logo-name">BBBootstrap</span> </a>
        <div class="nav_list">
          <a href="#" class="nav_link active"> <i class='bx bx-grid-alt nav_icon'></i> <span class="nav_name">Dashboard</span> </a>
          <a href="#" class="nav_link"> <i class='bx bx-user nav_icon'></i> <span class="nav_name">Users</span> </a>
          <a href="#" class="nav_link"> <i class='bx bx-message-square-detail nav_icon'></i> <span class="nav_name">Messages</span> </a>
          <a href="#" class="nav_link"> <i class='bx bx-bookmark nav_icon'></i> <span class="nav_name">Bookmark</span> </a>
          <a href="#" class="nav_link"> <i class='bx bx-folder nav_icon'></i> <span class="nav_name">Files</span> </a>
          <a href="#" class="nav_link"> <i class='bx bx-bar-chart-alt-2 nav_icon'></i> <span class="nav_name">Stats</span> </a>
        </div>
      </div>
      <a href="#" class="nav_link"> <i class='bx bx-log-out nav_icon'></i> <span class="nav_name">SignOut</span> </a>
    </nav>
  </div>
  <!--Container Main start-->
  <div class="height-100 bg-light">
    <h4>Main Components</h4>
  </div>
  <!--Container Main end-->

Its running code is here https://bbbootstrap.com/snippets/bootstrap-5-sidebar-menu-toggle-button-34132202#

Related