My learning diary

Sticky

I found myself entangled in CSS. I needed app-header to stick to the top at all times. I also needed template-header to be right beneath app-header at all times. Lastly, embedded-content should begin immediately after template-header and shouldn’t be sticky. Here’s how the page organisation might look like:

<div class="app">
  <div class="app-header">
    <!-- Content -->
  </div>
  <div class="app-content">
    <div class="template-container">
      <div class="template-header">
        <!-- Content -->
      </div>
      <div class="embedded-content">
        <!-- Content -->
      </div>
    </div>
  </div>
</div>

The simplest approach is to place app-header and template-header inside a single div. Then, we will only need to stick one element at the top. However, app-header and app-content are independent of each other. They are of different scopes in React. Here’s my initial approach:

.app-header {
  position: sticky;
  top: 0;
  width: 100vw;
  z-index: 1;
}

.app-content {
  margin-top: 70px;
}

.template-header {
  padding: 2px;
  position: fixed; /* Changing to position: sticky; didn't work for me. */
  top: 56px;
  z-index: 1;
}

Having margin-top: 70px and top: 56px was disturbing. Depending on the viewport, the height of app-header changes due to overflow. A quick fix for top: 56px is to use media queries. But, I’d want to defer that. The overflow problem may no longer apply when the content in app-header gets condensed into something like a hamburger button.

As for margin-top: 70px, it becomes a problem when there are pages without template-container. They look like:

<div class="app">
  <div class="app-header">
    <!-- Content -->
  </div>
  <div class="app-content">
    <!-- Content -->
  </div>
</div>

This poses a problem because margin-top: 70px means there will be a space between app-header and app-content. In a world where CSS can do whatever we want, we can have app-content conditionally choose a style based on the presence of template-container. But for now, this ideal approach isn’t possible.

A quick remedy for margin-top: 70px is to refactor pages without template-container to now have a header of a similar height. Sounds quick but I expect this to be rather tedious.

Update: Changing the position value for template-header to sticky didn’t work at first because of the superfluous margin-top: 70px. Here’s the simplified solution:

.app-header {
  position: sticky;
  top: 0;
  width: 100vw;
  z-index: 1;
}

.template-header {
  padding: 2px;
  position: sticky;
  top: 56px;
  z-index: 1;
}

I will sign off this post with a caniuse lookup.

Relevant posts