Fixed header in CSS Grid
Asked Answered
D

6

19

I've just begun fiddling with the CSS Grid and I'm curious as to how to create a fixed header. Should I create a two row grid where row one is the header and row two is another grid for the content? Or is there an easier way to approach this?

I've added height to the divs within the grid to enable scrolling.

Here is the HTML/CSS I've set up for testing:

html, body, div, span, applet, object, iframe,
    h1, h2, h3, h4, h5, h6, p, blockquote, pre,
    a, abbr, acronym, address, big, cite, code,
    del, dfn, em, img, ins, kbd, q, s, samp,
    small, strike, strong, sub, sup, tt, var,
    b, u, i, center,
    dl, dt, dd, ol, ul, li,
    fieldset, form, label, legend,
    table, caption, tbody, tfoot, thead, tr, th, td,
    article, aside, canvas, details, embed,
    figure, figcaption, footer, header, hgroup,
    menu, nav, output, ruby, section, summary,
    time, mark, audio, video {
    	margin: 0;
    	padding: 0;
    	border: 0;
    	font-size: 100%;
    	font: inherit;
    	vertical-align: baseline;
    }
    /* HTML5 display-role reset for older browsers */
    article, aside, details, figcaption, figure,
    footer, header, hgroup, menu, nav, section {
    	display: block;
    }
    body {
    	line-height: 1;
    }
    ol, ul {
    	list-style: none;
    }
    blockquote, q {
    	quotes: none;
    }
    blockquote:before, blockquote:after,
    q:before, q:after {
    	content: '';
    	content: none;
    }
    table {
    	border-collapse: collapse;
    	border-spacing: 0;
    }
    
    /* DEFAULTS */

    body {
      color: white;
    }
    
    /* SETTING UP THE GRID LAYOUT */
    
    .wrapper {
      display: grid;
      grid-template-columns: repeat(12, [col-start] 1fr);
      grid-template-rows: 10vh 1fr;
    }
    
    .header {
      grid-column: col-start / span 12;
      background-color: black;
    }
    
    .jumbotron {
      grid-column: col-start / span 12;
      height: 30vh;
      background-color: yellow;
    }
    
    .content-one-left {
      grid-column: col-start / span 6;
      height: 30vh;
      background-color: red;
    }
    
    .content-one-right {
      grid-column: col-start 7 / span 6;
      height: 30vh;
      background-color: blue;
    }
    
    .content-two-left {
      grid-column: col-start / span 6;
      height: 30vh;
      background-color: blue;
    }
    
    .content-two-right {
      grid-column: col-start 7 / span 6;
      height: 30vh;
      background-color: red;
    }
    
    .footer {
      grid-column: col-start / span 12;
      height: 10vh;
      background-color: black;
    }
<div class="wrapper">

  <div class="header">
    <p> Header </p>
  </div>

  <div class="jumbotron">
    <p> Jumbotron </p>
  </div>

  <div class="content-one-left">
    <p> Content 1 Left </p>
  </div>

  <div class="content-one-right">
    <p> Content 1 Right </p>
  </div>

  <div class="content-two-left">
    <p> Content 2 Left </p>
  </div>

  <div class="content-two-right">
    <p> Content 2 Right </p>
  </div>

  <div class="footer">
    <p> Footer </p>
  </div>

</div>
Darsey answered 13/3, 2018 at 14:23 Comment(0)
H
13

Once you set a child of a grid container to position: fixed it is removed from the document flow and no longer participates in grid layout (see section 9.2 of the grid spec).

Therefore, it makes sense to remove an element from a grid container if you want it fixed to the viewport. If it's a header, just place it above the grid container.

If you still want the header to be a grid that's not a problem. Fixed elements can be grid containers. They just don't do well as grid items.

codepen demo

html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}


/* HTML5 display-role reset for older browsers */

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
  display: block;
}

body {
  line-height: 1;
}

ol,
ul {
  list-style: none;
}

blockquote,
q {
  quotes: none;
}

blockquote:before,
blockquote:after,
q:before,
q:after {
  content: '';
  content: none;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}


/* DEFAULTS */

body {
  color: white;
}


/* SETTING UP THE GRID LAYOUT */

.wrapper {
  display: grid;
  grid-template-columns: repeat(12, [col-start] 1fr);
  grid-template-rows: 1fr;
  height: 90vh;
  overflow: auto;
}

.header {
  height: 10vh;
  background-color: black;
}

.jumbotron {
  grid-column: col-start / span 12;
  height: 30vh;
  background-color: yellow;
}

.content-one-left {
  grid-column: col-start / span 6;
  height: 30vh;
  background-color: red;
}

.content-one-right {
  grid-column: col-start 7 / span 6;
  height: 30vh;
  background-color: blue;
}

.content-two-left {
  grid-column: col-start / span 6;
  height: 30vh;
  background-color: blue;
}

.content-two-right {
  grid-column: col-start 7 / span 6;
  height: 30vh;
  background-color: red;
}

.footer {
  grid-column: col-start / span 12;
  height: 10vh;
  background-color: black;
}
<div class="header">
  <p> Header </p>
</div>

<div class="wrapper">



  <div class="jumbotron">
    <p> Jumbotron </p>
  </div>

  <div class="content-one-left">
    <p> Content 1 Left </p>
  </div>

  <div class="content-one-right">
    <p> Content 1 Right </p>
  </div>

  <div class="content-two-left">
    <p> Content 2 Left </p>
  </div>

  <div class="content-two-right">
    <p> Content 2 Right </p>
  </div>

  <div class="footer">
    <p> Footer </p>
  </div>

</div>
Heathenry answered 13/3, 2018 at 15:12 Comment(2)
I wasn't sure if there was a way of doing this within the grid I had already created, but this makes sense. Thanks for the thorough reply!Darsey
So in that way we will have to use media queries to adjust the header, right?Barrett
J
53

In 2018, you can use position: sticky

header {
  position: sticky;
  top: 0;
}

Here is a JSFiddle demoing it.

Browser support - it works for the header element (tested in Chrome and Edge).

Jonniejonny answered 7/9, 2018 at 16:35 Comment(0)
H
13

Once you set a child of a grid container to position: fixed it is removed from the document flow and no longer participates in grid layout (see section 9.2 of the grid spec).

Therefore, it makes sense to remove an element from a grid container if you want it fixed to the viewport. If it's a header, just place it above the grid container.

If you still want the header to be a grid that's not a problem. Fixed elements can be grid containers. They just don't do well as grid items.

codepen demo

html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
}


/* HTML5 display-role reset for older browsers */

article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
  display: block;
}

body {
  line-height: 1;
}

ol,
ul {
  list-style: none;
}

blockquote,
q {
  quotes: none;
}

blockquote:before,
blockquote:after,
q:before,
q:after {
  content: '';
  content: none;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}


/* DEFAULTS */

body {
  color: white;
}


/* SETTING UP THE GRID LAYOUT */

.wrapper {
  display: grid;
  grid-template-columns: repeat(12, [col-start] 1fr);
  grid-template-rows: 1fr;
  height: 90vh;
  overflow: auto;
}

.header {
  height: 10vh;
  background-color: black;
}

.jumbotron {
  grid-column: col-start / span 12;
  height: 30vh;
  background-color: yellow;
}

.content-one-left {
  grid-column: col-start / span 6;
  height: 30vh;
  background-color: red;
}

.content-one-right {
  grid-column: col-start 7 / span 6;
  height: 30vh;
  background-color: blue;
}

.content-two-left {
  grid-column: col-start / span 6;
  height: 30vh;
  background-color: blue;
}

.content-two-right {
  grid-column: col-start 7 / span 6;
  height: 30vh;
  background-color: red;
}

.footer {
  grid-column: col-start / span 12;
  height: 10vh;
  background-color: black;
}
<div class="header">
  <p> Header </p>
</div>

<div class="wrapper">



  <div class="jumbotron">
    <p> Jumbotron </p>
  </div>

  <div class="content-one-left">
    <p> Content 1 Left </p>
  </div>

  <div class="content-one-right">
    <p> Content 1 Right </p>
  </div>

  <div class="content-two-left">
    <p> Content 2 Left </p>
  </div>

  <div class="content-two-right">
    <p> Content 2 Right </p>
  </div>

  <div class="footer">
    <p> Footer </p>
  </div>

</div>
Heathenry answered 13/3, 2018 at 15:12 Comment(2)
I wasn't sure if there was a way of doing this within the grid I had already created, but this makes sense. Thanks for the thorough reply!Darsey
So in that way we will have to use media queries to adjust the header, right?Barrett
U
3
.header{
    position: fixed;
    left:0;
    right:0;
    top:0;
}

Using position fixed for header it will work definitely.

Underpainting answered 13/3, 2018 at 15:14 Comment(1)
This snippet works if you need the element to stretch the full viewport.Tablet
D
1

The trick is to create a parent content container with overflow set to auto and fixed height (to trigger the overflow), and then add your content to as its children.

body {
  margin: 0;
}

.page {
  display: grid;
  grid-template-rows: 55px calc(100vh - 55px); /* height limitation on second row */
  grid-template-areas: "header" 
                       "content";
}

.header {
  grid-area: header;
  background-color: darkgray;
}

.content {
  grid-area: content;
  background-color: grey;
  overflow: auto;  /* overflow condition on parent */
}

article {
  height: 500px;  /* height set on child; triggers scroll */
}
<div class='page'>
    <div class='header'>Header</div>
    <div class='content'>
        <article>
            <h1>title</h1>
        </article>
        <article>
            <h1>title</h1>
        </article>
    </div>
</div>

References: Original source

Durango answered 1/7, 2021 at 19:50 Comment(0)
F
0

With .wrapper {margin-top; 80px; position:relative;} and .header {position:fixed; height: 80px; z-index: 10;} a grid definition within .wrapper will flow beneath the fixed header. For good measure, place the ruleset for .header at the top, before .wrapper.

/* Globals */

body {
  color: white;
}


/* Grid Layout - Not necessarily display:inline-grid; */

.header {
  top: 0px;
  height: 80px;
  background-color: black;
  position: fixed;
  left: 2vw;
  right: 2vw;
  z-index: 10;
  overflow: hidden;
  }

.wrapper {
  position: relative;
  left: 10vw;
  width: 80vw;
  top: 20px;
  margin-top: 80px;
  display: -ms-inline-grid;
  display: -moz-inline-grid;
  display: inline-grid;
  grid-template-columns: repeat(12, [col-start] 1fr);
  grid-template-rows: 1fr; 
  overflow: auto;
}

.jumbotron {
  grid-column: col-start / span 12;
  height: 30vh;
  background-color: yellow;
}

.content-one-left {
  grid-column: col-start / span 6;
  height: 30vh;
  background-color: red;
}

.content-one-right {
  grid-column: col-start 7 / span 6;
  height: 30vh;
  background-color: blue;
}

.content-two-left {
  grid-column: col-start / span 6;
  height: 30vh;
  background-color: blue;
}

.content-two-right {
  grid-column: col-start 7 / span 6;
  height: 30vh;
  background-color: red;
}

.footer {
  grid-column: col-start / span 12;
  height: 10vh;
  background-color: black;
}
<div class="header">
  <p> Header </p>
</div>

<div class="wrapper">



  <div class="jumbotron">
    <p> Jumbotron </p>
  </div>

  <div class="content-one-left">
    <p> Content 1 Left </p>
  </div>

  <div class="content-one-right">
    <p> Content 1 Right </p>
  </div>

  <div class="content-two-left">
    <p> Content 2 Left </p>
  </div>

  <div class="content-two-right">
    <p> Content 2 Right </p>
  </div>

  <div class="footer">
    <p> Footer </p>
  </div>

</div>
Faint answered 1/9, 2019 at 18:51 Comment(0)
P
-1
.header-container {
    position: sticky;
    position: -webkit-sticky; /* For macOS/iOS Safari */
    top : 0;
}
Pride answered 28/6, 2020 at 9:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.