CSS/HTML - Scroll Header before content

耗尽温柔 提交于 2019-12-19 10:24:22

问题


I try to figure out if it is possible to hide only the upper part of the nav-bar. See Img below (green marked area). This should mimic the navbar behaviour like the whatsapp-app.

I am using material-ui for this use-case. With my implementation the app-bar only extends again if the scroll position is < 48px. On the .gif-file (see below) it extends on every scroll up event. It also looks like the app-bar scrolls only first until it reaches position fixed. After then the rest of the content begins to scroll.

Edit

I implemented a proof-of-concept, but it is not quite working as expected: stackblitz

My approach looks as follows:

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>
  );
}

I created a gif how the behaviour should look like: dropbox-link


回答1:


Most probably it is not the most elegent solution, but after trying around I came up with the following way:

import React from "react";
import PropTypes from "prop-types";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import 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>
  );
}

--> Just put another sticky app bar in your content container and modify the useScrollTrigger with threshold option

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




回答2:


Here is my solution: https://stackblitz.com/edit/react-ts-azrqoy

I am making the Container with text scrollable (I have left the scrollbars visible, so you can see better what happens, but you can easily remove them with css)

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

The trick is to stop pointer-events for the container if you want fingers/scrolling to move the page scroll and enable it back if you want to scroll inside. So this is pretty much CSS solution and I personally prefer these more than pushing values with JS - they are smoother and more optimised.

There are two problems: - when the pointer-events switch happens, you have to move your mouse (1px) to have the scroll work again (This can probably be fixed if you ref and manually change containerRef.style.pointerEvents instead of setting states and rerendering components. - the logic of this script doesn't handle scrolling up exactly like your gif animation, you will probably have to detect scrolling up and stop the pointer-events until the bar shows

I have never written a line in TypeScript, so I couldn't really try everything I wanted.




回答3:


I have seen the whatsapp navbar and I understood what you wanted.

You can actually use the window.pageYOffset and set the style.top of the navbar in the window.onscroll function.

A sample is shown in the w3schools website which is working as the way you mentioned.



来源:https://stackoverflow.com/questions/57945569/css-html-scroll-header-before-content

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!