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

13,335

Solution 1

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.

Solution 2

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;
}

Solution 3

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).

Share:
13,335

Related videos on Youtube

Joshua Ohana
Author by

Joshua Ohana

Updated on September 15, 2022

Comments

  • Joshua Ohana
    Joshua Ohana over 1 year

    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

    • tobie
      tobie over 6 years
      try using 100vh !important instead of 100% for your height
  • Ilya Streltsyn
    Ilya Streltsyn over 6 years
    "100% on a child will be equal to the size of the parents natural height" — this is true only for absolutely positioned children. For statically positioned elements, 100% height always means 100% of the specified height of the parent element.
  • damanptyltd
    damanptyltd over 6 years
    I think you may have misunderstood the question. Those 2 issues you specify are not the core issues - it is the fact that the poster wants the child to fill the remaining vertical space of the parent element, but it is instead becoming the same height as the parent. This is extending the child passed the bottom of the parent, creating scroll bars. IF you put in both your margin and overflow fixes, this still occurs.
  • ToTaTaRi
    ToTaTaRi over 6 years
    Yeah, but thats what i ment, we have a sourrounding div (my-app or body) with 100% or 100vh, then we put in a header with the heading and links, lets say with a height round about 20vh and a main content box which again should be 100% or 100vh as it's parent, but that will make 120vh, so it must be just 80vh, so that all elements together will cover just 100vh!
  • ToTaTaRi
    ToTaTaRi over 6 years
    I've edited my answer above, just try the code... I can't see no problem there!?
  • damanptyltd
    damanptyltd over 6 years
    @ToTaTaRi my comment was not directed at you, please check which answer this comment tread is on.
  • Joshua Ohana
    Joshua Ohana over 6 years
    I don't like this answer and ended up not using it. We shouldn't have to be targeting an element by undefined. I am awarding you the bounty as I think this answer is most helpful for future readers.
  • damanptyltd
    damanptyltd over 6 years
    I would argue that the undefined element shouldn't exist in the first place which would negate the need to manipulate it. Please do respond here once you've found an acceptable solution as I'd be interested to know.
  • tatsu
    tatsu over 4 years
    for me it works without the undefined bit. flex was all it needed.