Robert Todar
Robert Todar

Reputation: 2145

How to switch headers using only CSS?

The effect I'm trying to get

I was looking at how GraphQL designed their header on their website and saw that it changes after scrolling it past the hero section without using JavaScript. It is more of an overlapping effect vs just a sticky scrollbar.

GraphQL Navbar example


What I've tried so far

I've looked through the source code and stylesheet to see how they accomplished this effect and don't see anything that stands out to me, such as position: sticky;.

I also tried to play around with the z-index of both headers but still can't figure out how they layered it to overlap like this.

The things that do stand out that they used are: clip, z-index, and position: fixed;.

Here is an attempt I made to recreate this effect:

/* Basic styles just for visual */

body {
  margin: 0;
  color: #aaa;
}

section {
  min-height: 1250px;
  padding: 100px;
}

.header-content {
  display: flex;
  justify-content: center;
}


/* Attempt at overlapping headers */

header {
  display: flex;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 50px;
  background: white;
  box-shadow: inset 0 -1px 0 0px rgba(0, 0, 0, 0.1);
  z-index: 10;
}

.hero {
  position: fixed;
  background: #171e26;
  position: relative;
  min-height: 450px;
  max-height: 900px;
  height: 65vh;
  margin-top: -50px;
  padding-top: 50px;
  z-index: 11;
}

.hero .abs {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  clip: rect(0, auto, auto, 0);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
}

.hero .header {
  background: linear-gradient(rgba(23, 30, 38, 0.8), rgba(23, 30, 38, 0));
  box-shadow: none;
  display: block;
}
<header>
  <div class="header-content">
    First Header
  </div>
</header>
<div class="hero">
  <div class="abs">
    <header>
      <div class="header-content">
        Header in hero
      </div>
    </header>
  </div>
</div>
<section>
  Lorem ipsum dolor sit amet, consectetur adipisicing elit. Similique, ipsum. Est exercitationem eum voluptates neque suscipit natus repudiandae perferendis minima ipsum eveniet possimus esse nam excepturi maxime, odit, debitis numquam.
</section>

This is somewhat close, but you can tell the top header is just staying white vs being transparent.


Summary question

Really, I don't need a full example back as an answer, although it is welcome. I really just want to understand how they did this.

How are they able to accomplish this using only CSS?

Upvotes: 0

Views: 219

Answers (1)

Cray
Cray

Reputation: 2850

A basic example of how this can be achieved using two navbars with absolute and fixed positions. This, however, does not work with the hero section as GraphQL website has as both navbars are positioned at the top of the page.

.show-when-scrolling {
  background-color: #333;
  position: fixed; /* Remain in position when scrolling */
  z-index: 1; /* Hide navbar under main navbar */
}

.main-nav {
  background-color: #666;
  position: absolute; /* Show on top of other content */
  z-index: 2; /* Show main navbar on top of second navbar */
}

body {
  margin: 0; /* Remove browser default margin to fill whole screen */
  height: 200vh; /* Makes page scrollable */
}

/* Random styling */
.nav {
  width: 100%;
  height: 48px;
}

.nav a {
  float: left;
  color: #fff;
  text-align: center;
  padding: 15px;
  cursor: pointer;
}

.nav a:hover {
  background-color: #bbb;
  color: black;
}
<div class="nav main-nav">
  <a>My</a>
  <a>main</a>
  <a>navbar</a>
</div>

<div class="nav show-when-scrolling">
  <a>Visible</a>
  <a>when</a>
  <a>scrolling</a>
</div>

Another solution, for when you want to implement a hero section as in your example, can be done using sticky position.

.show-when-scrolling {
  background-color: #333;
  position: fixed; /* Remain in position when scrolling */
  z-index: -1;
}

.main-nav {
  position: sticky; /* Remains inside wrapper, so it will be hidden when scrolled enough */
  top: 0; /* Stick to the top */
}

body {
  margin: 0; /* Remove browser default margin to fill whole screen */
  height: 200vh; /* Makes page scrollable */
}

/* Random styling */
.nav {
  width: 100%;
  height: 48px;
}

.nav a {
  float: left;
  color: #f00;
  text-align: center;
  padding: 15px;
  cursor: pointer;
}

.nav a:hover {
  background-color: #bbb;
  color: black;
}

.top-section {
  height: 200px;
  background-size: cover;
  background-image: url(https://images.unsplash.com/photo-1562347810-18a0d370ba36?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80)
}
<div class="nav show-when-scrolling">
  <a>Visible</a>
  <a>when</a>
  <a>scrolling</a>
</div>
<div class="top-section">
  <div class="nav main-nav">
    <a>My</a>
    <a>main</a>
    <a>navbar</a>
  </div>
</div>

Upvotes: 1

Related Questions