0

I want to place the footer at the bottom of the layout page (when the height is shorter than the window). It is commonly mentioned that the solution is min-height:100vh, but this expands the height of other elements too. I want to limit the height of all rows limited to the height of their contents while the footer is pushed at the bottom (whenever it is necessary).

body {
  font-family: Helvetica;
}

.wrapper {
  display: grid;
  grid-template-columns: auto;
  min-height:100vh;
}

.box {
  background-color: #20262e;
  color: #fff;
  border-radius: 3px;
  padding: 20px;
  font-size: 14px;
  width:100%;
}

.a {grid-area: 1/1/2/2;}
.b {grid-area: 2/1/3/2;}
.footer {grid-area: 4/1/5/2;}
<div class="wrapper">
  <div class="box a">A</div>
  <div class="box b">B</div>
  <div class="box footer">Footer</div>
</div>

JSFIDDLE

Googlebot
  • 15,159
  • 44
  • 133
  • 229

1 Answers1

2

You have a few mistakes about sizing.

for a full page, and padding on body, you cannot use here min-height:100vh because it will be the viewport height being offset of 20px from the padding of body and eventually the horizontal scrollbar. Use min-height:100% instead and set body to 100vh of height. (box-sizing needs also to be reset).

width : 100% is not necessary for block element (unless you have a specific reason)

examples.

  • fixing the sizing and setting footer at bottom (sticky optionnal)

body {
  padding: 20px;
  font-family: Helvetica;
  margin: 0;
  height: 100vh;/* reference for the direct child */
  box-sizing: border-box;/* include padding and border into size calculation */
}

.wrapper {
  display: grid;
  grid-template-columns: auto;
  min-height: 100%;/*of avalaible space of sized(height:xx) parent */ 
}

.box {
  background-color: #20262e;
  color: #fff;
  border-radius: 3px;
  padding: 20px;
  font-size: 14px;
}

.a {
  grid-area: 1/1/2/2;
}
.b {
  grid-area: 2/1/3/2;
}
.footer {
  grid-area: 4/1/5/2;
  /* ?? should I stick at the bottom of the viewport ?? */
  position:sticky;
  bottom:0;
}
<div class="wrapper">
  <div class="box a">A</div>
  <div class="box b">B</div>
  <div class="box footer">Footer</div>
</div>

if the footer do not need to be seen anytime, remove position:sticky and bottom:0.

  • trick to follow your grid-area settings idea (without row template) to shrink the first rows, insert an exta virtual container that will use so many rows .(not elegant and average, breaks if vertical gaps are set.)

body {
  padding: 20px;
  font-family: Helvetica;
  margin: 0;
  height: 100vh;/* reference for the direct child */
  box-sizing: border-box;/* include padding and border into size calculation */
}

.wrapper {
  display:grid;
  min-height: 100%;/*of avalaible space of sized(height:xx) parent */ 
}

.box {
  background-color: #20262e;
  color: #fff;
  border-radius: 3px;
  padding: 20px;
  font-size: 14px;
}

.a {
  grid-area: 1/1/2/2;
}
.b {
  grid-area: 2/1/3/2;
}
.footer {
  grid-area: 0/1/21/2;

}

/* fill a few rows if any rooms left */
.wrapper:before {
  content:'';
  grid-area:3/1/19/2;/* about 15 rows */
}
<div class="wrapper">
  <div class="box a">A</div>
  <div class="box b">B</div>
  <div class="box footer">Footer</div>
</div>
  • to use grid with the right option here on a grid-template-rows (there is no grid-template-area set in your original piece of code):

body {
  padding: 20px;
  font-family: Helvetica;
  margin: 0;
  height: 100vh;
  /* reference for the direct child */
  box-sizing: border-box;
  /* include padding and border into size calculation */
}

.wrapper {
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  min-height: 100%;
  /*of avalaible space of sized(height:xx) parent */
}

.box {
  background-color: #20262e;
  color: #fff;
  border-radius: 3px;
  padding: 20px;
  font-size: 14px;
}

.footer {
  grid-row: 4
}
<div class="wrapper">
  <div class="box a">A</div>
  <div class="box b">B</div>
  <div class="box footer">Footer</div>
</div>

edit : For an unknown numbers of rows, then flex would be efficient .

body {
  padding: 20px;
  font-family: Helvetica;
  margin: 0;
  height: 100vh;
  /* reference for the direct child */
  box-sizing: border-box;
  /* include padding and border into size calculation */
}

.wrapper {
  display: flex;
  flex-direction: column;
  min-height: 100%;
}

.box {
  background-color: #20262e;
  color: #fff;
  border-radius: 3px;
  padding: 20px;
  font-size: 14px;
}
/* if you need a gap , use margin , a pseudo stands here ! */
.box + .box {
margin-top:2px;
}
.wrapper:after {
  content: '';
  flex: 1;
}

.footer {
  order: 2;
}
<div class="wrapper">
  <div class="box a">A</div>
  <div class="box b">B</div>
  <div class="box footer">Footer</div>
</div>
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
  • When I open your snippet in full-page, each row is exactly 1/4 of the page height. Do I miss something? The whole point is to keep the height of `a`, `b` and `footer` limited to the height of their contents. – Googlebot May 24 '21 at 11:52
  • if you set a min-height to your grid, it will stretch the rows to fill that height. That is the normal behavior, you need to insert an extra virtueal row than will stretch as much as it can if there is room.@Googlebot I'll update the snippet with an example of the idea. – G-Cyrillus May 24 '21 at 11:54
  • That's the basis of my question: how to place the footer at the bottom of the page without affecting/stretching other rows. I mentioned that `min-height` does not work here. I look for another solution. – Googlebot May 24 '21 at 11:57
  • @Googlebot however, you'll need to manage also the sizing to avoid overflow/offset when not needed. updated your snippet with grid area. using grid-template-rows would be more efficient here. (grid-area is not enought flexible to my taste most of the time, just a personnal opinion). added 2 snippets, to me the last one is the most efficient. – G-Cyrillus May 24 '21 at 12:07
  • Although adding `1fr` to the second last ("non-existing") row works magically, if the the number of children is undefined, (say you may creating this as a general style sheet) it is hard to change `grid-template-row` every time and with pure css. The concerns comes as I have some webpage compiled with dynamic content at server end, and client may disabled JS, so such property cannot be changed with JS. – jimmymcheung Feb 20 '23 at 18:53
  • @jimmymcheung if one has to stand at bottom always, it would be a footer outside, not a sibbling . To me the markup would be more relevant and much easier to style . A wrapper &inside: a list + a real footer tag. ;) Else a pseudo and order could do via flex – G-Cyrillus Feb 21 '23 at 15:29
  • @jimmymcheung added a flex example to the answer ;) – G-Cyrillus Feb 21 '23 at 15:35
  • @G-Cyrillus using `display:flex` is my current practice, but our web layout is in transition to grid layout and a `footer` outside wouldn't have inherited grid when subgrid is widely supported. Although there's currently no need to use any of the inherit grid in the design yet. – jimmymcheung Feb 21 '23 at 18:56
  • grid and flex work together, they have 2 different purpose. + here you have a **1d** grid where flex is fully efficient ;) *( out off subject: there is also display:table and Column CSS in your CSS toolbox , all of them still fully working but also for specific purpose, only float is now back to what it was designed for in the first place)* ... grid and flex are two great tools, they do not replace each others ;) (even bootstrap is adding class to use grid , but will keep flex ) @jimmymcheung – G-Cyrillus Feb 21 '23 at 19:01
  • Do you have any snippet that shows your issue @jimmymcheung – G-Cyrillus Feb 21 '23 at 19:05
  • It's not yet an issue, but I imagine the [following scenario](https://codepen.io/jimmymcheung/pen/PodNydL): we need to style element with `subgrid`, putting element inside flex cannot inherit parent grid (last example in the link), nor sibling grid (second example). In the examples subgrid would just have the same columns `.grid`, thus it is not yet a big problem, but if footer only occupies e.g. 2/3 of the columns, it would then be a problem. @G-Cyrillus – jimmymcheung Feb 22 '23 at 15:56
  • @jimmymcheung one way can be to trick the grid and set the footer down very far in the rows . A partial fork of your pen to demonstrate the idea : https://codepen.io/gc-nomade/pen/JjaXqqM (quick fixed seen only in FireFox 64bits/wind ... no warranties else where ;) ) – G-Cyrillus Feb 22 '23 at 20:27
  • On safari, which is the one of the only two browser that currently support subgrid, I can see that your change `grid-template-rows: repeat(auto-fill,minmax(0,auto)) auto` is not taken any effect, but the other change that sets footer on a far away column takes the effect. I tried to comment out the `grid-template-rows` property and it still gives good result. – jimmymcheung Feb 24 '23 at 11:24
  • I also tried to set the footer's `grid-row` to a way higher value (3000) on a static page (no js, no animation), but the performance is drastically reduced, setting it to a value under 1000 is not an problem on a mid-aged laptop (from 2016), but consider people viewing on a old machine or a page with many animations, this value should not be set high. – jimmymcheung Feb 24 '23 at 11:35