Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

100% height body is taller than 100vh, caused by Angular's router-outlet

Tags:

css

angular

I have an angular page, home, which is comprised of 2 components and a router-outlet

<div class="home-container">
  <header></header>
  <sub-header></sub-header>
  <router-outlet></router-outlet>
</div>

I want the home-container above to always be, at a minimum, full screen height. The header should show, then the sub-header, then the contents of the router-outlet should always fill up at least the rest of the screen (or more if there's more content of course).

Normally this is easy but it seems the router-outlet is messing it up. Example can be seen http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas , hit run and then click the "Heroes" link to route. In this example I don't want the Heroes div to be taller than the screen, and don't understand why it is.

My styles to accomplish this are. (assume router-outlet is on 'my-page')

html, body {
  height: 100%;
}

.home-container {
   height: 100%;
}

.my-page {
  height: 100%;
}

My expectation here obviously is that home-container is full screen, shows header, shows sub-header, and that my-page then fills in at a minimum the rest of the vertical height.

What is actually happening though, is that there's a scroll bar with available height that appears equal to my header and sub-header.

This plnkr http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas illustrates exactly my meaning. If you click Run and then the link for "Heroes" you will see the router-outlet contents, in this case heroes-list.component, with a green background. I do not understand why the green here is bleeding below the screen when everything is set to 100%

Update I have tried using all manner of different CSS attributes to different levels in this nesting. Including 100vh vs 100%, min-height vs height, and every combination of body/html/home-container/my-page. I have also tried the same with Angular's CSS :host, to the same result of no different

Update2 If I move it out of the element then everything behaves as you'd expect and there's no vertical scroll bar. Something about the router-outlet wrapper adds vertical space somewhere but I cannot figure out where or what is causing it.

Final Update The below answers might be useful for some applications but I ended up just solving it by giving the .my-page a specified height, just doing height: calc(100vh - $headerheight - $subheaderheight) which gets the job done

like image 728
Joshua Ohana Avatar asked Oct 19 '17 02:10

Joshua Ohana


3 Answers

As far as I understand, 100% on a child will be equal to the size of the parents natural height. If you want to fill the space available, you really should be using flex unless you have a requirement to support IE9 and below.

I would update your Anchors to be contained in a div (or another wrapper)

<h1 class="title">Component Router</h1>
<div>
    <a [routerLink]="['CrisisCenter']">Crisis Center</a>
    <a [routerLink]="['Heroes']">Heroes</a>
</div>
<router-outlet></router-outlet>

I would then utilize flexbox to allow the content to expand as required

.hero-list {
  background-color: green;
  height: 100%;
  overflow:auto
}

undefined {
  flex: 1;
}

body, html, my-app {
  height: 100%;
}

my-app{
  display: flex;
  flex-flow: column;
}

Plunker to test: http://plnkr.co/edit/yE1KOZMr1pd5jQKlVYIN?p=preview

On chrome i still have scroll bars due to an 8px margin on body - this can easily be removed with CSS for a scroll free full height experience.

like image 129
damanptyltd Avatar answered Nov 17 '22 20:11

damanptyltd


There are two causes that make your <body> element taller than 100% of the viewport:

  1. Default margins of the <body> element that come from the browser's built-in styles and usually are 8px. This means that the <body> element will be as tall as the <html> element, but also will have 8px space above it and below it, causing the <html> element to overflow.
  2. The top margin of the <h1> element "falls out" from the container due to margin collapsing. This makes the space above the <body> element equal to the default top margin of <h1> (about 21px instead of 8px).

Setting zero margin to <body> (part of ToTaTaRi's answer) helps you to solve the 1st issue. To solve the second one, you should make the <body> element or (probably better) the .my-app container establish the new Block Formatting Context. The easiest and most cross-browser way for this is setting the container overflow:hidden (other options are display:flow-root, which works for modern Chrome/Firefox, or column-count:1, which works in IE10+ and all modern browsers, you can compare nearly all the options in this live example).

like image 38
Ilya Streltsyn Avatar answered Nov 17 '22 21:11

Ilya Streltsyn


First of all you should reset browser default styles at least somehow like this:

* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}

Then you could achive what you want without a flex layout if prefered through splitting the page into a header section and main content section with a preset division... So lets say the heading and the links go together into a container div with i.e. a height of 20% and the main content which is at the moment hold in a tag "undefined" gets a height of 80%, if you now set the height of the app container to 100% or 100vh it should work as expected!

EDIT (because the topic is still open...):

Have you tried this css code like explained above, works like charm!?

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html, body, my-app {
  height: 100%;
  height: 100vh;
}

h1 , h1 + div {
  height: 10%;
  height: 10vh;
}

undefined {
  display: block;
  background-color: green;
  min-height: 80%;
  min-height: 80vh;
}
like image 1
ToTaTaRi Avatar answered Nov 17 '22 22:11

ToTaTaRi