htmlcsstwitter-bootstrapdjango-templatesbootstrap-5

How an I set height relative to viewport for values other than 100 with Bootstrap 5?


This is an an attempt to create a type of div I created in the past but with a custom stylesheet with minimal non-bootstrap css. It's not quite there yet, but I'm trying to covert each style rule I wrote into my django static files CSS into a bootstrap class. I'm stuck on viewport-based sizing.

The state prior to me discovering these docs is this, with the height fitting content as you would expect:

Height fits content

I discover this wonderful little bit in Bootstrap 5

I set my class to "vh-100" which very cool, sets the div to take up the full vertical height of the view port.

But wait, it matches the height the ENTIRE viewport, not the remainder after the navbar and padding is figured out. Makes sense though.

nice n long

Awesome! just need to shave a little off that so it actually fits in the actual viewport and we have the desired end state.

Looking in bootstrap documentation you can usually specify 25%, 50%,75%, or 100% like we did here. Well, it doesn't talk about that for viewport-based sizing, but it does in a lot of bootstrap stuff, so I'd guess it'd be the same here. So I give that a go. 75% Viewport should be just right to give it a little bottom area.

So now "vh-50" or "vh-75"

Nope

Okay, weird- Viewport must be 100 or it falls back to sizing based on content. No other examples of any other values for viewport based sizing are visible in docs, and I couldn't locate any in the wild.

Just in case, here's the html for that div (part of a jinja content block in a django app)

{% block content %}
  <div class="body-area bg-dark text-light my-5 vh-75">
    <div class="container">
      <div class="row">
        Hi
      </div>
    </div>
  </div>
{% endblock %}
Here is my CSS. I did already try removing ALL instances of height from my css with no effect. The html and body are being applied via a base template, which you can see works since the background gradient displays correctly (it tiles otherwise without that body/html style).

.body-area {
  margin-left: auto;
  margin-right: auto;
  width: 75%;
  border: 10px solid #000000;
  border-radius: 15px;
}

html {
  height: 100%;
}
body {
  height: 100%;
  margin: 0;
  background-repeat: no-repeat;
  background-attachment: fixed;
}

While I'm starting to think I probably shouldn't even bother, and probably won't in this particular app, I think it'd be really useful to be able to size things based on percentages of the viewport, especially for a mobile app.

So am I going about this all wrong? Should I not be ever sizing anything other than 100 of viewport? How should I approach this, either with the bootstrap tool I'm attempting to or the best practice that is currently unknown to me?

I'm hoping any CSS/bootstrap wizards out there will know a trick that I hope will be helpful to both me and whoever else stumbles on this in the future.


Solution

  • You shouldn't be setting heights manually. You should be using the flexbox grid to do it automatically with the appropriate alignment classes.

    1. Put a flex column around the navbar and content elements with class vh-100. This can simply be the body element.
    2. Put class flex-fill on the content element so it stretches to fill the remaining space.

    <head>
      <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    </head>
    
    <body class="d-flex flex-column vh-100">
      <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <div class="container-fluid">
          <a class="navbar-brand" href="#">Navbar</a>
          
          <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
          </button>
          
          <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <!-- ... -->
          </div>
        </div>
      </nav>
    
      <div class="body-area container-fluid bg-dark text-light flex-fill">
        <div class="row">
          <div class="col">
            Hi
          </div>
        </div>
      </div>
    </body>