Div with headers that stick to the top and stack when scrolling

I am working on creating a lengthy scrollable list of grouped items where the group titles remain visible at all times (stacked). When a user clicks on a group header, the page should scroll to the corresponding items.

I have successfully used the position: sticky property to keep the group headers in view. However, please note that this method may have compatibility issues with Internet Explorer.

My challenge arises when I try to scroll to the sticky header upon clicking. The positioning is not as smooth as desired, and the group items end up behind the sticky headers.

For better clarity, I have created a visual example: https://i.sstatic.net/YWy7F.png

Here is a JSFiddle demonstrating my current progress: https://jsfiddle.net/n6urjabk/1/

<style type="text/css">
  body,
  html {
    width: 100%;
    height: 100%;
    padding: 0;
    margin: 0;
  }
  
  body {
    background: #20262E;
    padding: 20px;
    box-sizing: border-box;
    font-family: Helvetica;
  }
  
  #container {
    /*display:flex;*/
    max-height: 100%;
    height: 400px;
  }
  
  .column {
    background: #eee;
    box-sizing: border-box;
    overflow: auto;
    position: relative;
    max-height: 400px;
  }
  
  .row {
    background: #eee;
    border-radius: 0px;
    margin: 0;
    padding: 10px;
  }
  
  .row:nth-child(odd) {
    background: #fff;
  }
  
  .column h4 {
    background: lightblue;
    padding: 10px;
    margin: 0;
    position: sticky;
    height: 40px;
    box-sizing: border-box;
    text-align: center;
  }
  
  .column h4:hover {
    opacity: 0.8;
    cursor: pointer;
  }
  
  .column h4:nth-of-type(odd) {
    background: lightgreen;
  }
</style>


<div id="container">
  <div class="column">
    <h4 class="header1" id="test1">
      Head 1
    </h4>
    <div class="content">
      <div class="row">row 1.1</div>
      <div class="row">row 1.2</div>
      <div class="row">row 1.3</div>
      <div class="row">row 1.4</div>
      <div class="row">row 1.5</div>
      <div class="row">row 1.6</div>
      <div class="row">row 1.7</div>
      <div class="row">row 1.8</div>
    </div>
    <h4 class="header2" id="test2">
      Head 2
    </h4>
    <div class="content">
      <div class="row">row 2.1</div>
      <div class="row">row 2.2</div>
      <div class="row">row 2.3</div>
      <div class="row">row 2.4</div>
      <div class="row">row 2.5</div>
      <div class="row">row 2.6</div>
      <div class="row">row 2.7</div>
      <div class="row">row 2.8</div>
    </div>
    <h4 class="header3" id="test3">
      Head 3
    </h4>
    <div class="content">
      <div class="row">row 3.1</div>
      <div class="row">row 3.2</div>
      <div class="row">row 3.3</div>
      <div class="row">row 3.4</div>
      <div class="row">row 3.5</div>
      <div class="row">row 3.6</div>
      <div class="row">row 3.7</div>
      <div class="row">row 3.8</div>
    </div>
    <h4 class="header4" id="test4">
      Head 4
    </h4>
    <div class="content">
      <div class="row">row 4.1</div>
      <div class="row">row 4.2</div>
      <div class="row">row 4.3</div>
      <div class="row">row 4.4</div>
      <div class="row">row 4.5</div>
      <div class="row">row 4.6</div>
      <div class="row">row 4.7</div>
      <div class="row">row 4.8</div>
    </div>
  </div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript">
  var headers = $('h4').length;
  var headerHeight = 40;
  var maxOffset = (headers * headerHeight) - headerHeight;

  $('h4').each(function() {
    var index = $(this).index('h4');
    var top = index * headerHeight;
    var bottom = maxOffset - top;
    $(this).css('top', top).css('bottom', bottom);
  });

  $('h4').on('click', function() {

    $(this).next()[0].scrollIntoView({
      block: 'start',
      behavior: 'smooth'
    });
  });
</script>

Answer №1

To correctly adjust the scroll parameter, similar to how you did for the top, you can utilize a simple JavaScript function. Although my knowledge of jQuery is limited, I have come up with a solution in pure JS. By grasping the general concept, you should be able to develop your own implementation.

Here is a sample click event function:

document.addEventListener("click", (e) => {
  if (e.target.nodeName == "H4") {
    const index = parseInt(e.target.id.split("").pop());
    const scrollNum = e.target.nextElementSibling.offsetTop - (index * 40);
    document.querySelector(".column").scrollTo({
      top: scrollNum,
      behavior: 'smooth'
    });
  }
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Could you explain the purpose of the app.use(cors()) function call?

I'm aware that accessing an API with a different domain than our own is not allowed. Nonetheless, I often observe individuals incorporating the cors module into their Express.js applications in order to interact with APIs and then utilizing it in this ...

Issue with Chrome Browser Border Radius Bug when applied to element with Display: Table

I'm facing an issue with border radius in the Chrome browser. When applying a border-radius to an element styled with dashed border-style and display:table, the background-color exceeds the limit of the border. Here's how it appears in Chrome: ...

Remove the innerHTML content of dynamically added elements using jQuery

After researching, it seems that event handlers are commonly added using methods such as .live(), .on(), .bind(), or .delegate(). My previous question may not have been clear, so I decided to delete it and ask a simpler one. Is there a way to clear the in ...

What steps can I take to troubleshoot a non-functional button in a Bootstrap 5 Modal?

I have a Django based web site that utilizes Bootstrap 5 for styling. Among the data presented on the site is a table with a notes column containing lengthy text. To enhance readability and keep the table compact, I attempted to integrate the Bootstrap Mod ...

Tips for transferring data via ajax to rails 3. The jQuery function is ensuring the string is properly handled

I am attempting to achieve the following: $.ajax({ type: "PUT", url: /example, data: {_method: "put", "foo_model[bar_attribute]": value_var } }); It is working as expected, but I need to dynamically construct the part foo_model[bar_attribute]. ...

Strategies for styling the contents within <details> while excluding <summary> in CSS

I'm attempting to apply a 10px padding to the Story box using CSS, without introducing any additional HTML elements into the website code. Is there a way to include the padding in the Story box without incorporating a new HTML element? To clarify: H ...

Show input fields in a row

In an attempt to align my select form fields on the same line, I have tried adding display:inline; to both the select and label elements in my code. However, it did not produce the desired result. Here is the HTML code snippet: <form id ="myform1"> ...

Can you show me the method to import these ES6 exports? Are they specifically named exports or the default?

As I reviewed the code in the Material UI project, I came across a section that is exporting a variety of React Components: src/Dialog/index.js: export { default } from './Dialog'; export { default as DialogActions } from './DialogActions ...

Reveal the class to the global scope in TypeScript

ClassExample.ts: export class ClassExample{ constructor(){} } index.html: <script src="ClassExample.js"></<script> // compiled to es5 <script> var classExample = new ClassExample(); //ClassExample is not defined < ...

Displaying variables as HTML in Node.js involves rendering the variable data

Currently experimenting with displaying a Node.js variable as HTML. This is my setup in app.js using Express: Package.json "dependencies": { "body-parser": "~1.12.0", "cookie-parser": "~1.3.4", "debug": "~2.1.1", "express": "~4.12.2", ...

What could possibly be causing my code to execute multiple times?

Within my code, I have the following function that is triggered when the document is ready: $('#file_upload_form').submit(function(){ // show loader [optional line] //if(document.getElementById('upload_frame') == ...

Convert h264 video to GIF using Node.js

Currently, I'm utilizing the "pi-camera" library to successfully record video in a raw h264 format on my Raspberry Pi. However, I am encountering an issue with the node.js library "gifify" which keeps throwing the error "RangeError: Maximum call stack ...

The iPhone encountering issues with Safari's interpretation of @media queries

When it comes to my website on a desktop screen, the body text should not be at the top of the page. However, on an iPhone, it must be displayed at the top. I've created a class with empty paragraphs to control the display on and off, but this class s ...

What Makes Sports Illustrated's Gallery Pages Load So Quickly?

After thoroughly examining their code, I'm still puzzled. Are they loading complete new pages, or are they utilizing jQuery to modify the browser's URL while keeping most of the page unchanged? I'm currently inspecting the source of this pa ...

Different Line Thickness in Dropdown Menu

Is there a way to adjust line heights in CSS within a drop down menu? I have attempted to change the font sizes of each element, but the new font size does not seem to take effect once an option is selected. Any suggestions would be greatly appreciated! & ...

Automatically Adjust Text Size to Fit Input Forms using jQuery

Does anyone know how to use jQuery to dynamically change the font size in a form input field so that it always remains visible and fits even as the user types more text? I want the font size to start at 13px and progressively shrink as the text reaches the ...

Multiple minute delays are causing issues for the Cron server due to the use of setTimeout()

I have an active 'cron' server that is responsible for executing timed commands scheduled in the future. This server is dedicated solely to this task. On my personal laptop, everything runs smoothly and functions are executed on time. However, ...

Error encountered while attempting to send a delete request to MongoDB due to connection refusal

Recently, I've been diving into a Next.js tutorial that involves working with MongoDB. Everything seems to be running smoothly when testing my API endpoints with Postman. POST, GET, and DELETE requests all go through without any hiccups. However, thi ...

Encountering memory leaks and displaying repetitive data due to having two distinct observables connected to the same Firestore

I am currently utilizing @angular/fire to retrieve data from firestore. I have two components - one serving as the parent and the other as the child. Both of these components are subscribing to different observables using async pipes, although they are bas ...

Generating a dynamic list by utilizing database data once a button has been clicked

I'm looking to create a feature on my website where clicking on a button will populate a paragraph below it with data retrieved from a database query containing two columns. The first column provides the text for a list, while the second column contai ...