The sticky element should only be active when the visible section is overflowing vertically. There should be no scrollbar if the height is minimal

I'm currently working on a Whatsapp-style navigation bar and facing an issue with the sticky navbar functionality.

https://i.stack.imgur.com/Cy3lA.gif

Please refer to the details below for more information.

To resolve this issue, I have included a function that checks the height of each section within the container. If the content height exceeds a certain threshold, the scrollbar will be enabled. This ensures that only sections with lengthy text display the scrollbar while maintaining the sticky behavior of the navbar.

Furthermore, to address this challenge in the presence of page transitions, I have implemented additional logic to dynamically manage the scrolling behavior based on the active page index.


If you encounter any issues, please let me know.

Answer №1

One way to take elements out of the flow in a document is by using position: absolute.

let navItems = document.querySelectorAll(".nav-item");
const sections = Array.from(document.querySelectorAll("#container > section"));

sections.forEach((section, index) => section.style.setProperty("--section", index));

// Adding a CSS variable that counts how many items there are, influencing the logic.
document.body.style.setProperty("--total-nav-items", `${navItems.length}`);

navItems.forEach((item, index) => {
  item.addEventListener("click", () => {
    // Altering a CSS variable triggers further CSS logic
    document.body.style.setProperty("--index", `${index}`);
    toggleActive();

    function toggleActive() {
      // Reducing opacity for other unclicked icons
      navItems.forEach((itemWithClass) => {
        itemWithClass.classList.remove("active");
      });

      sections.forEach((section, sectionIndex) => section.classList.toggle("active", sectionIndex === index))

      // Making the clicked item visible
      item.classList.add("active");
    }
  });
});
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@500&display=swap");
:root {
  --nav-height: 3rem;
  --nav-bg: rgb(0, 128, 105);
  --text-color: white;
  --anim-speed: 0.5s;
  color-scheme: light dark;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

header {
  background-color: var(--nav-bg);
  height: var(--nav-height);
  display: grid;
  place-items: center start;
}

nav {
  display: flex;
  height: var(--nav-height);
  background-color: var(--nav-bg);
  color: var(--text-color);
  text-transform: uppercase;
  font-family: poppins;
  user-select: none;
  /* position: fixed; */
  /* top: 0; */
  /* left: 0; */
  position: sticky;
  top: 0;
  width: 100vw;
  z-index: 1;
}
... [truncated for brevity] ...
<header>
  <span>Whatsapp</span>
</header>

<nav>
  <div class="nav-item active">hello 1</div>
  <div class="nav-item">hello 2</div>
  <div class="nav-item">hello 3</div>
  <div class="nav-item">hello 4</div>
  <div class="nav-item">hello 5</div>
</nav>

<div id="container">
  <!-- Inserted HTML Sections Here -->

Answer №2

To achieve the desired effect for your code, I made some changes to your snippet. Instead of using CSS variables to adjust content visibility on different areas of the screen, I created two states for your sections:

  • Active (Flexbox)
  • Inactive (Invisible)

By switching from a grid display to using flexbox on the sections, scrolling behavior is now possible. I also added a fixed max height on active sections and responsive bottom padding for user-friendliness. Feel free to customize these aspects as needed.

If you need further explanation or assistance, please let me know!

let navItems = document.querySelectorAll(".nav-item");
let sections = Array.from(document.getElementById("container").children);

//Initially make all other sections inactive except the first
sections.forEach((section, index) => {
  if(index == 0) section.classList.add("active-section");
  else section.classList.add("inactive-section");
});

navItems.forEach((item, index) => {
  item.addEventListener("click", () => {

    toggleActive(index);

    function toggleActive(index) {
      // for setting opacity low to other not clicked icons
      navItems.forEach(itemWithClass => {
        itemWithClass.classList.remove("active");
      });
      
      //Make sections visible or invisible based on nav item clicked
      sections.forEach((section, i) => {
        if(i != index) {
          section.classList.remove("active-section");
          section.classList.add("inactive-section");
        } else {
        section.classList.remove("inactive-section");
          section.classList.add("active-section");
        }
      });

      // making visible the active clicked item
      item.classList.add("active");
    }
  });
});
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@500&display=swap");
:root {
  --nav-height: 3rem;
  --nav-bg: rgb(0, 128, 105);
  --text-color: white;
  --anim-speed: 0.5s;
  color-scheme: light dark;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  overflow-y: auto;
  overflow-x: hidden;
}

header {
  background-color: var(--nav-bg);
  height: var(--nav-height);
  display: grid;
  place-items: center start;
}

nav {
  display: flex;
  height: var(--nav-height);
  background-color: var(--nav-bg);
  color: var(--text-color);
  text-transform: uppercase;
  font-family: poppins;
  user-select: none;
  /* position: fixed; */
  /* top: 0; */
  /* left: 0; */
  position: sticky;
  top: 0;
  width: 100vw;
}

nav .nav-item {
  flex: 1;
  display: grid;
  place-items: center;
  opacity: 0.5;
  transition: opacity var(--anim-speed);
}

nav .nav-item:active {
  background-color: rgba(255, 255, 255, 0.2);
}

nav .nav-item.active {
  opacity: 1;
}

nav::before {
  --indicator-width: calc(100% / var(--total-nav-items));
  content: "";
  position: absolute;
  height: 0.2rem;
  width: 100px;
  background-color: var(--text-color);
  bottom: 0;
  width: var(--indicator-width);
  left: calc(var(--index, 0) * var(--indicator-width));
  transition: left var(--anim-speed);
  box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.5);
}

#container {
  position: fixed;
  top: --nav-height
  display: flex;
  height: 100vh;
}

.active-section {
    display: flex;
    flex-direction: column;
    max-height: 90vh;
    overflow-y: scroll;
    padding: 5%;
    padding-bottom: 10%;
}

.inactive-section {
    display: none;
}

@media (prefers-color-scheme: dark) {
   :root {
    --nav-bg: rgb(31, 44, 52);
    --text-color: rgb(9, 148, 115);
  }
}
<header>
  <span>Whatsapp</span>
</header>

<nav>
  <div class="nav-item active">hello 1</div>
  <div class="nav-item">hello 2</div>
  <div class="nav-item">hello 3</div>
  <div class="nav-item">hello 4</div>
  <div class="nav-item">hello 5</div>
</nav>

<div id="container">
  <!-- 1 -->
  <section>
    <h1>PAGE 1</h1>
    <p>
      <!-- see the fifth for the longest paragraph -->
     <!-- Your content goes here -->
    </p>
  </section>

  <!-- Repeat for other sections -->

</div>

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

Delete the line height (or leading) for bigger text in CSS

Is there a way to eliminate the space above and below the mandatory span, specifically when using << within it? The height of the field row is determined by the default line-height for the text size, but the mandatory field is taller due to its larg ...

Swapping values in JSON by comparing specific keys: A guide

I have JSON data that contains a key called reportData with an array of values: {"reportData":[ ["1185","R","4t","G","06","L","GT","04309","2546","2015","CF FE","01H1","20","23840","FF20"], ["1186","R","5t","R","01","L","TP","00110","1854","2016" ...

Error: The navigation property is not defined - React Native

Utilizing Firebase in combination with react-native for user authentication. The main file is App.js which directs users to the Login component and utilizes two components for managing routes: Appnavigator.js to create a switchNavigator and DrawerNavigator ...

Responsiveness of the element along the vertical axis

I have an element that, when clicked, should display additional content. However, when the headline contains a lot of text, the element does not expand vertically as it should. Thank you for your help! Check out how it looks currently This is my HTML co ...

What are the different ways to share data between components in React?

There are two components in my code, one named <Add /> and the other named <Modal>. The <Add /> component has a state for handling click events. Whenever the <Add /> component is clicked, the state is set to true. I need to utilize ...

Leveraging the power of jquery-tmpl with the responseText

I am currently working on populating jquery-templates retrieved through an ajax call from a different folder on the server. I attempted to fill the responseTexts using .tmpl({..}) but unfortunately, it didn't work as expected. Here is my approach: va ...

I am puzzled as to why my Details Modal keeps appearing whenever I click anywhere, even when I have specifically added it to only show up on the event of today. Additionally, I am encountering

ERROR Function components cannot have string refs. We recommend using useRef() instead. Learn more about using refs safely here: https://reactjs.org/link/strict-mode-string-ref at coerceRef (http://localhost:3000/static/js/bundle.js:59386:21) at createChil ...

Issues with Implementing Scroll Directive in Angular JS

Apologies for asking what may seem like a silly question. I'm still new to using AngularJS and recently came across a neat little scroll directive on http://jsfiddle.net/88TzF/622/. However, when I tried implementing the code in the HTML snippet below ...

What is the best way to incorporate the skrollr-body tag without altering the overall height of the

Skrollr has been a game-changer, so thank you to the geniuses behind it. I made sure to properly place the skrollr-body tag around all elements except for the fixed background in order to make it work on mobile. However, I'm noticing that it is cutti ...

Troubleshooting: jQuery click event not functioning correctly with if-else statement

For some reason, I can't seem to figure out how to toggle the color of all list items with a class of "link" between blue and black. I've searched through numerous posts but still can't find a solution. Working Example: http://jsfiddle.net/ ...

ReactJS experiencing issue with the functionality of the all-the-cities library

Encountering an issue where importing the library all-the-cities causes reactjs to malfunction and display the following error: TypeError: fs.readFileSync is not a function (anonymous function) C:myproject/node_modules/all-the-cities/index.js:6 3 | cons ...

Include an iframe with hidden overflow specifically for Safari browsers

I have a situation where I'm using a third-party iframe to display specific content. The iframe is enclosed within a div container that has border-radius and overflow: hidden properties applied. Strangely, the content inside the iframe doesn't se ...

Jquery is causing some issues with the code provided:

This is the code snippet from script.js: $(document).ready(function() { $('#mainobject').fadeOut('slow'); }); Here is a glimpse of index.html: <!DOCTYPE html> <html> <head> <title>Hitler Map&l ...

Updating Angular.js scope after a variable has been modified

On my website, I have implemented a search bar that communicates with a controller receiving JSON responses from the server. The response is stored in a global variable called assetResult. It works as expected initially; however, subsequent searches do no ...

Styling a webpage with a two-row layout using just CSS

I am looking to design a 2-row layout for a webpage where one row will contain filters and the other row will display results. The layout should meet the following criteria: The page height should not exceed 100% The first row's height will vary bas ...

What is the best way to refresh information following its removal?

In my app, I have implemented a feature where posts are displayed as HTML cards using a component called PostList. Each card has a delete button to remove it from the list. The issue I am facing is that when I delete a card, it remains visible in the post ...

The map feature is not working on the imported Obj file

After my previous question here, I'm attempting to give each side of this obj a different texture. However, despite applying everything in the correct order, nothing is showing up and there are no console errors. It seems like a simple task but I&apo ...

Tips for iterating through a JSON object in JavaScript and building a table from it

My JSON data is structured like this: diferencias = { "1": { "1": 543.0, "0": 542.0 }, "2": { "0 1": 0.3333333333333333 } } I am trying to create a table with the outer keys as columns. This is the code I have written ...

Handling errors in chained promises and routes in Node.js/ExpressJS

I'm currently dealing with some confusion regarding how to handle errors when making function calls. To demonstrate this, I'll be using sequelizeJS as an example. Usually: First.Ctrl var second_ctrl = require( '../ctrl/second'); testC ...

Is it possible to define a shared function for enums in TypeScript?

I have created an enumeration called VideoCategoryEnum: enum VideoCategoryEnum { knowledge = 0, condition = 1, interview = 2, speech = 3, entertainment = 4, news = 5, advertisement = 6, others = 7, } I am looking to implement a shared met ...