-->

Responsive CSS Grid layout with position: fixed

2020-08-09 17:09发布

问题:

I'm building a responsive template with CSS Grid Layout (still learning) and thanks to a few of you on here, I've got most of it working.

  • mobile (max-width: 767px)

    • everything should appear on its own row
  • tablet (min-width: 768px)

    • nav is on the first row
    • aside and main on the second
  • desktop (min-width: 992px)

    • same as tablet but with 10% of spacing horizontally
  • xl desktop (min-width: 1920px)

    • same as desktop but has a max-width of 1920px

The thing is I'm using a header tag to color the spacing to the left and right of the nav. Whether I use a header or a div, it doesn't seem right having an empty container just for coloring the empty space. Is there a way of doing this in a way that lets me apply position: fixed on the entire top section?

* {
  margin: 0;
  padding: 0;
}

body {
  display: grid;
  font-family: sans-serif;
}

a {
  text-decoration: none;
  color: white;
}

header,
nav {
  background: blue;
  color: #fff;
}

nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

nav span {
  margin-right: auto;
}

header {
  display: none;
}

aside {
  background: lightgreen;
}

main {
  background: pink;
}


/* mobile  */

@media (max-width: 767px) {
  body {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr 1fr 1fr;
  }
  nav,
  aside,
  main {
    grid-column: 1 / 1;
    padding: 0 15px;
  }
}


/* tablets */

@media (min-width: 768px) {
  body {
    grid-template-columns: 275px 1fr;
    grid-template-rows: 1fr 1fr;
  }
  nav {
    grid-column: 1 / 4;
    grid-row: 1;
    height: 50px;
    grid-row: 1;
  }
  aside {
    grid-column: 1;
  }
  main {
    grid-column: 2;
  }
  nav,
  aside,
  main {
    padding: 0 15px;
  }
}


/* desktops */

@media (min-width: 992px) {
  body {
    grid-template-columns: 10% 275px 1fr 10%;
    grid-template-rows: 1fr 1fr;
  }
  header {
    display: block;
    grid-column: 1 / -1;
    grid-row: 1;
  }
  nav {
    grid-column: 2 / 4;
    grid-row: 1;
  }
  aside {
    grid-column: 2 / 3;
  }
  main {
    grid-column: 3 / 4;
  }
}


/* xl desktops */

@media (min-width: 1920px) {
  body {
    grid-template-columns: 1fr minmax(auto, 300px) minmax(auto, 1620px) 1fr;
    grid-template-rows: 1fr 1fr;
  }
}
<header></header>
<nav>
  <span>Logo</span>
  <a href="#">login</a>
</nav>
<aside>aside</aside>
<main>main</main>

https://jsfiddle.net/90kotz8d/1/

回答1:

If I understand your intent, you are not really using header for spacing, you are really using it to get the blue background to cover all the space.

Since you seem also wanting the logo and login to vertically align with the boundaries, I don't think that there is any posible solution to do this with the nav.

So, the only solution that I could find involves using a pseudo element. At least this is more semantic. I got rid of the media queries, since now they don't play a role here:

* {
  margin: 0;
  padding: 0;
}

.container {
  display: grid;
    grid-template-columns: 10% 275px 1fr 10%;
    grid-template-rows: 1fr 1fr;
}

.container::after {
    content: "";
    background-color: blue;
    grid-column: 1 / 5;
    grid-row: 1;
    z-index: -1;
}

a {
  text-decoration: none;
  color: white;
}


nav {
  background: blue;
  color: #fff;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

nav span {
  margin-right: auto;
}

header {
  display: none;
}

aside {
  background: lightgreen;
}

main {
  background: pink;
}
nav {
    grid-column: 2 / 4;
    grid-row: 1;
  }
  aside {
    grid-column: 2 / 3;
  }
  main {
    grid-column: 3 / 4;
  }
<div class="container">
<nav>
  <span>Logo</span>
  <a href="#">login</a>
</nav>
<aside>aside</aside>
<main>main</main>
</div>



回答2:

I guess, this is something, what you want. I have used grid-column: 1 / 8; in the @media (min-width: 992px) and added manual padding on both sides. I hope, without this solution, till now no more options you are having without using extra <div>, <header> or any other containers.

* {
  margin: 0;
  padding: 0;
}

body {
  display: grid;
  font-family: sans-serif;
}

a {
  text-decoration: none;
  color: white;
}

header,
nav {
  background: blue;
  color: #fff;
}

nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

nav span {
  margin-right: auto;
}

header {
  display: none;
}

aside {
  background: lightgreen;
}

main {
  background: pink;
}

/* mobile  */


@media (max-width: 767px) {
  body {
    grid-template-columns: 1fr;
    grid-template-rows: 1fr 1fr 1fr;
  }
  
  nav,
  aside,
  main {
    grid-column: 1 / 1;
    padding: 0 15px;
  }
}


/* tablets */


@media (min-width: 768px) {
  body {
    grid-template-columns: 275px 1fr;
    grid-template-rows: 1fr 1fr;
  }
  
  nav {
    grid-column: 1 / 4;
    grid-row: 1;
    height: 50px;
    grid-row: 1;
  }
  
  aside {
    grid-column: 1;
  }
  
  main {
    grid-column: 2;
  }
  
  nav,
  aside,
  main {
    padding: 0 15px;
  }
}


/* desktops */


@media (min-width: 992px) {
  body {
    grid-template-columns: 10% 275px 1fr 10%;
    grid-template-rows: 1fr 1fr;
  }
  
  nav {
    grid-column: 1 / 8;
    grid-row: 1;
    padding-right: 11.3vw;
    padding-left: 11.3vw;
  }
  
  aside {
    grid-column: 2 / 3;
  }
  
  main {
    grid-column: 3 / 4;
  }
}


/* xl desktops */


@media (min-width: 1920px) {
  body {
    grid-template-columns: 1fr minmax(auto, 300px) minmax(auto, 1620px) 1fr;
    grid-template-rows: 1fr 1fr;
  }
}
<nav>
  <span>Logo</span>
  <a href="#">login</a>
</nav>
<aside>aside</aside>
<main>main</main>



回答3:

From what I can see, you might need to add a rule saying it is display: block; before you can add the position: fixed rule, because I am pretty sure <header>s are inline elements.

You could also try and add media queries, linking to different stylesheets, that display different tables, using the display: tableRow;, tableCell and table values.

Hope this works