Styling a Fixed Header in CSS/HTML - Scroll Effect

Is it possible to hide only the upper part of the nav-bar, similar to the behavior in WhatsApp? I am using material-ui for this particular use-case. Currently, my implementation causes the app-bar to extend only when the scroll position is less than 48px, unlike the behavior shown in the .gif below where it extends on every scroll up event. It seems like the app-bar scrolls first until it reaches a fixed position, after which the rest of the content begins to scroll.

Edit

I tried implementing a proof-of-concept but it doesn't work as expected: stackblitz

This is how my approach looks:

export default function TabBar() {
  const [value, setValue] = React.useState(0);
  const [yOffset, setYOffset] = React.useState(0);

  function handleChange(event: React.ChangeEvent<{}>, newValue: number) {
    setValue(newValue);
  }

  function transitionY() {
    const transitionYthreshold = 48;
    return Math.min(transitionYthreshold, yOffset);
  }

  useEffect(() => {
    window.addEventListener('scroll', handleScroll, { passive: true });
    return () => window.removeEventListener('scroll', handleScroll);
  });

  function handleScroll() {
    setYOffset(window.pageYOffset);
  }

  return (
    <React.Fragment>
      <AppBar
        position="sticky"
        color="default"
        style={{
          transition: 'all 0.1s',
          transform: `translateY(-${transitionY()}px)`
        }}
      >
        <Toolbar style={{ minHeight: '48px' }}>
          <div style={{ width: '30px', marginRight: '1em' }} />
          <span style={{ fontWeight: 'bold', fontSize: '20px', verticalAlign: 'super' }}>Help-Educate</span>
        </Toolbar>
        <Tabs
          value={value}
          onChange={handleChange}
          indicatorColor="primary"
          textColor="primary"
          variant="fullWidth"
        >
          <Tab label="Home"  {...a11yProps(0)}/>
          <Tab label="Donations"  {...a11yProps(1)}/>
          <Tab label="About Us"  {...a11yProps(2)}/>
        </Tabs>
      </AppBar>
      <TabPanel value={value} index={0}>
        <Container>
          {**SomeSuperLongText**}
        </Container>
      </TabPanel>
      <TabPanel value={value} index={1}>
         {**SomeSuperLongText**}
      </TabPanel>
      <TabPanel value={value} index={2}>
         {**SomeSuperLongText**}
      </TabPanel>
    </React.Fragment>
  );
}

A gif showcasing the desired behavior can be found here: dropbox-link

https://i.stack.imgur.com/YFjIA.png

Answer №1

Although it may not be the most elegant solution, I managed to come up with a workaround after experimenting:

import React from "react";
import PropTypes from "prop-types";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
Typography from "@material-ui/core/Typography";
import CssBaseline from "@material-ui/core/CssBaseline";
import useScrollTrigger from "@material-ui/core/useScrollTrigger";
import Box from "@material-ui/core/Box";
import Container from "@material-ui/core/Container";
import Slide from "@material-ui/core/Slide";

function HideOnScroll(props) {
const { children } = props;
const trigger = useScrollTrigger({
threshold: 0
});

return (
<Slide appear={false} direction="down" in={!trigger}>
{children}
</Slide>
);
}

HideOnScroll.propTypes = {
children: PropTypes.element.isRequired
};

export default function HideAppBar(props) {
return (
<React.Fragment>
<CssBaseline />
<HideOnScroll {...props}>
<AppBar>
<Toolbar>
<Typography variant="h6">Scroll to Hide App Bar</Typography>
</Toolbar>
</AppBar>
</HideOnScroll>
<Toolbar />
<AppBar position="sticky">
<Toolbar>
<Typography variant="h6">Bar will stay</Typography>
</Toolbar>
</AppBar>
<Container>
<Box my={2}>
{[...new Array(20)]
.map(
() => `Cras mattis consectetur purus sit amet fermentum.
Cras justo odio, dapibus ac facilisis in, egestas eget quam.
Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
Praesent commodo cursus magna, vel scelerisque nisl consectetur et.`
)
.join("\n")}
</Box>
</Container>
</React.Fragment>
);
}

--> You can add another sticky app bar within the content container and adjust the useScrollTrigger with threshold option accordingly.

Check it out here: https://codesandbox.io/s/serverless-cache-rcxen

Answer №2

Check out my unique solution here: https://stackblitz.com/edit/react-ts-opelwo

In this code snippet, I have created a Container with a scrollable text area. You can adjust the visibility of scrollbars using CSS.

<Container
          style={{
          top:48,
          paddingTop:48,
          bottom: - 48,
          scrollTop: yOffset - transitionY(),
          pointerEvents: transitionY()<48?"none":"auto"
        }} className="cont" onScroll={handleInsideScroll}>

The key is to control the pointer-events property for the container to either enable or disable scrolling functionality based on user interaction. This approach utilizes CSS instead of JS for smoother and more optimized results.

There are a couple of issues: - After switching pointer-events, you may need to move your mouse slightly to resume scrolling (this could potentially be resolved by directly modifying containerRef.style.pointerEvents rather than updating states). - The script does not handle scrolling up exactly like in the gif animation provided, requiring additional logic to detect upward scrolling behavior.

As a TypeScript beginner, I couldn't explore all possibilities, but I find CSS solutions preferable for their efficiency and fluidity over JavaScript alternatives.

Answer №3

I checked out the whatsapp navbar and I see what you're looking for.

One way to achieve this effect is by using window.pageYOffset to adjust the style.top of the navbar within the window.onscroll function.

You can find a working example on the w3schools website that demonstrates this exact behavior.

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

Error: The constructor for JsSHA is not valid for the TOTP generator

Attempting to create a TOTP generator similar to Google's timed-based authenticator using the React framework. I am utilizing the bellstrand module for TOTP generation, but I am encountering issues when trying to import it into my React code. Here is ...

The grid is out of alignment, causing elements to jump to the next row

After taking an online course at TreeHouse, I used the provided HTML & CSS code and made some adjustments to create a layout with 10 columns instead of the original 12 within a 1000px container. The columns were converted to percentages to fit my needs. I ...

Does Mui datatables have the capability to handle nested arrays retrieved from an API

I am interested in using MUI datatable and currently have a nested array setup that is working as expected: {this.state.posts.map((posts,index) => ( <> {posts.map((item, j) => ( <tr key={j}> <td>{item.id} ...

Master the art of React JS with our comprehensive course

I am facing an issue while trying to run a command in my terminal npx create-react-app. I'm currently following a React JS crash course tutorial from January 2021. To check the version of npm installed on my system, I executed "npm --version" and foun ...

Customize component designs using Box

The documentation for MUI mentions that a Box wrapper has the ability to override its child's styling using the "clone" option, as demonstrated here: <Box color="red" clone> <Button>Click me</Button> </Box> From w ...

I'm having trouble adding a background image, even though I have set it to static. What could be

I attempted to add a background image to my Django website, but unfortunately, it was not successful. I followed the steps provided in this Stack Overflow answer here, however, it did not work. I even made changes to the database by migrating them, but s ...

There was a TypeScript error found at line 313, character 9 in the file @mui/material/styles/experimental_extendTheme.d

Encountering Typescript error while using Material UI component for date range picker Link - https://mui.com/x/react-date-pickers/date-range-picker/ Snippet of the code import * as React from 'react'; import { Dayjs } from 'dayjs'; im ...

Using Jquery to attach an event to a particular div which is part of a group of divs sharing

I am trying to implement a mouseup event on a series of divs that, when clicked, will reveal a child div ('menu'). All the parent divs have the same class. Here is an example: <div class="container"> <div class="menu"><p>Text ...

Eliminating unnecessary whitespace between the bottom of the document and an element

I have a HTML page that when scrolled should limit scroll to the document height. It must not exceed the bottom of an element. Here is a screenshot for better understanding: https://i.stack.imgur.com/RaVg8.jpg The scrolling should be limited after the En ...

Managing dynamic backend ports while using axios in React.js- a comprehensive guide!

This morning, I successfully deployed a login app using the MERN stack on Heroku. However, when attempting to log in GET http://localhost:5000/user/login/email/password net::ERR_CONNECTION_REFUSED appeared in the console. I realized that the error w ...

CSS Styling for Adjusting Table Cell Widths

In my HTML table, I am trying to set the overall width while ensuring that the label column does not become too wide. Although it functions correctly in Firefox 4, IE 9 seems to be completely ignoring the width property. <html> <head> <sty ...

What is the correct way to maintain focus on a nested scrolling div over another scrolling div with jQuery?

I have encountered an issue with a modal view that contains content extending beyond its boundaries. To remedy this, I applied the overflow-y: scroll property. However, the problem arises when the modal view overlaps with the body, which also has scrolling ...

Issues with hover styles and transitions not being correctly applied to newly appended elements in Firefox

Utilizing an SVG as an interactive floor plan, I have implemented a feature where hovering over different areas on the floor plan (<g> elements) causes them to expand and float above other areas. The element scaling is triggered by CSS, but I use jQu ...

Implementing a filter in React with data fetched from MongoDB

Hey there! I'm encountering an issue while using the code in Project.jsx and ProductList.jsx. Every time I run the code, it gives me this error message: Warning: Each child in a list should have a unique "key" prop. Check the render method of Product ...

Is it a shallow copy or something else when updating state in React JS?

I am currently dealing with a particular state within my application: const [work, setWork] = useState([ { company: "Company", position: "President", website: "example.com", startDate: "2013-01-01", endDate: "2014-01- ...

Ascending to the Peak within a div

<script type="text/javascript"> $(document).ready(function(){ updateContent(); }); function updateContent(){ $('#mainDiv').load('home.php', function(){ scrollToTop(); }); } ...

div is consistently correct across all web browsers

After creating the following CSS code for a div to always be positioned on the right: #button > .right { background-position: -268px 1415px; height: 180px; position: fixed; right: -90px; top: 40%; width: 263px; -webkit-transform ...

How to Eliminate the Border on the Final Item within a React List

Hi everyone, I need help with removing the border of the last item in an unordered list when the list reaches a certain size. I initially tried this: document.querySelector('.employee-list-item:last-child').style.border = "none"; However, I enc ...

Aligning enlarged text that spills over

Within my html/css application, I have defined a button as a class named .button with specific attributes. Here is a simplified example: .button { width: 120px; height: 30px; line-height: 30px; background: yellow; text-align: center; } <div ...

Is there a way to make the onKeyDown event function properly in Next.js/React?

I'm currently developing a website with Next.js and am facing an issue trying to execute a simple function when a key is pressed. Strangely, the onKeyDown event isn't getting triggered as expected in my code snippet: <main onKeyDown={e => c ...