A fixed navbar and sticky footer

It is nice to work with Bootstrap. CSS seems less intimidating and more approachable, and they also keep improving Bootstrap every year. However, there are developments in standard CSS which we tend to ignore because of the familiarity and convenience of Bootstrap. And some dev outfits might not want its developers to use Bootstrap, so it’s always a good practice to learn alternatives.

Let’s create a new project with a fixed navbar and a sticky footer using only CSS Grid.

On the command window, create a project named no_bs.

Stop the server if it is still running.

[00000000(----) INF] Received signal 2. Shutting down.
[main(----) INF] Stopped to listen for HTTP requests on ::1:8080
[main(----) INF] Stopped to listen for HTTP requests on 127.0.0.1^C:8080
Warning
: c:\vibeprojects\hello>3 socket handles leaked at driver shutdown.
Warning: 3 socket handles leaked at driver shutdown.
c:\vibeprojects\hello>cd ..
c:\vibeprojects>dub init no_bs -t vibe.d
Package recipe format (sdl/json) [json]:
Name [no_bs]:
Description [A simple vibe.d server application.]:
Author name [Owner]:
License [proprietary]:
Copyright string [Copyright © 2023, Owner]:
Add dependency (leave empty to skip) []:
     Success created empty project in c:\vibeprojects\no_bs
             Package successfully created in no_bs
c:\vibeprojects>cd no_bs
c:\vibeprojects\no_bs>

Open the no_bs folder in VS Code and edit source\app.d to make it look like this:

import vibe.vibe;
void main()
{
  auto settings = new HTTPServerSettings;
  settings.port = 8080;
  settings.bindAddresses = ["::1", "127.0.0.1"];
  auto router = new URLRouter;
  router.get("*", serveStaticFiles("public/"));
  router.get("/", staticTemplate!"index.dt");
  router.get("/about", staticTemplate!"about.dt");
  router.get("/contact", staticTemplate!"contact.dt");
  router.get("/login", staticTemplate!"login.dt");
  auto listener = listenHTTP(settings, router);
  scope (exit) listener.stopListening();
  runApplication();
}

Next, create views\layout.dt:

doctype 5
html
  head
    title Employee Timekeeping System
    include styles.dt
  body
    div.container
      div.menu
        include menu.dt
      div.content
        block maincontent
      div.footer
        include footer.dt

Then create views\styles.dt:

:css
  body
  {
    margin: 0;
    padding: 0;
  }
  .container
  {
    display: grid;
    grid-template-rows: 40px auto 30px;
    height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
  }
  .menu
  {
    position: fixed;
    top: 0;
    width: 100%;
    padding: 10px 0;
    background-color: whitesmoke;
  }
  .menu-item
  {
    display: inline;
  }
  .item-link
  {
    margin-left: 30px;
    font-family: Verdana, Geneva, Tahoma, sans-serif;
    font-size: 18px;
    color: teal;
    text-decoration: none;
  }
  .item-link-right
  {
    float: right;
    margin-right: 30px;
  }
  .modal-form
  {
    position: fixed;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background: rgba(0,0,0,0.5);
    z-index: 99999;
    opacity: 0;
    pointer-events: none;
  }
  #login:target, #find_employee:target
  {
    opacity: 1;
    pointer-events: auto;
  }
  .modal-form-grid
  {
    display: grid;
    grid-template: 30px 30px 30px / 1fr 1fr;
    grid-gap: 10px;
  }
  .text-control
  {
    grid-column: 1 / 3;
  }
  #but-reset
  {
    grid-column: 1 / 2;
  }
  #but-submit
  {
    grid-column: 2 / 3;
  }
  .modal-form-wrapper-login
  {
    width: 250px;
    position: absolute;
    right: 0;
    margin-top: 40px;
    padding: 25px 20px;
    border-radius: 10px;
    text-align: center;
    background-color: whitesmoke;
  }
  .modal-form-wrapper-find_employee
  {
    width: 250px;
    position: relative;
    left: 280px;
    margin-top: 40px;
    padding: 25px 20px;
    border-radius: 10px;
    text-align: center;
    background-color: whitesmoke;
  }
  .content
  {
    padding: 40px 30px;
  }
  .footer
  {
    position: fixed;
    bottom: 0;
    width: 100%;    
    background-color: whitesmoke;
    padding: 5px 0;
  }
  .copyright
  {
    font-family: Verdana, Geneva, Tahoma, sans-serif;
    font-size: 14px;
    text-align: center;
    color: teal;
  }
  .form-hidden
  {
    padding: 0;
    margin: 0;
    display: inline;
  }

Then create views\menu.dt:

div.menu-item
  a.item-link(href="/") Home
div.menu-item
  a.item-link(href="about") About us
div.menu-item
  a.item-link(href="contact") Contact us
div.menu-item
  a.item-link.item-link-right(href="login") Login

Then create views\index.dt:

extends layout
block maincontent
  h2 The Lorem Ipsum Company
  div.
    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Nam nec urna arcu. Quisque eleifend posuere vestibulum.
    In sed magna mauris. Phasellus bibendum ligula et placerat
    vulputate. In non suscipit lectus, a laoreet odio. Donec
    at sapien eu nisi porta condimentum. Morbi non varius ex,
    nec luctus nisl. Aenean varius dui quis arcu auctor luctus.
    Integer efficitur ornare massa, ac suscipit enim sagittis et.
    Proin vestibulum tellus in ipsum ultrices, sed imperdiet
    sapien euismod. Praesent vel facilisis mauris. Proin finibus
    congue tellus, non varius ante. Nullam tincidunt dolor felis.
    Pellentesque non luctus tellus. Curabitur et sapien at justo
    fringilla feugiat et a erat.
    <br /><br />

And make stub pages for views\about.dt:

extends layout
block maincontent
  h2 The About Us page
  div
    <h3>This is the About Us page.</h3>

and views\contact.dt:

extends layout
block maincontent
  h2 The Contact Us page
  div
    <h3>This is the Contact Us page.</h3>

and views\login.dt:

extends layout
block maincontent
  h2 The Login page
  div
    <h3>This is the Login page.</h3>

After you compile and run, you should be able to see these pages:

We just created a layout with a fixed navbar and a sticky footer without using Bootstrap. If you expand and contract the browser, you will see that the middle row expands and contracts to fit the page, making the pages responsive.

In the views\styles.dt file, we declared this:

  .container
  {
    display: grid;
    grid-template-rows: 40px auto 30px;
    height: 100%;
    width: 100%;
    margin: 0;
    padding: 0;
  }

We did not declare any columns, effectively making the whole page just one column with three rows. The menu bar is on the top row and the footer is on the bottom row, with the middle row expanding and contracting to fit the page height when the browser is resized, thus making it responsive.

With CSS Grid, you will notice that the layout terms are declared in the CSS file so the HTML file is cleaner compared to using Bootstrap.

Now let's add a modal dialogue to the menu without JavaScript.

Last updated