4

I'm creating a React PWA for a client using Tailwind CSS and I want to achieve a layout in which there's a header fixed to the top of the screen and a navbar fixed to the bottom of the screen. In between I'll display scrollable content of dynamic size.

I've been struggling with this problem for the most part of the day and I'm following the instructions on this answer as well as the code it provided here.

I though I got it, as I implemented all the recommended classes in the relevant components and I got this result on my browser dev tools:

Apparent success in my dev tools

However, I got curious and decided to open the page on my phone. This is the result there and, as you can see, neither of the desired elements are actually fixed to the screen:

It doesn't behave as expected

At this point I'm completely lost. I've tried using className={fixed} in the Navbar, but it ends up clipping part of the content even when adding margin or padding to either the navbar or the content.

How can I fix both header and navbar to the screen while keeping the content scrollable?

These are the relevant parts of my code:

App.js:

function App() {
    return (
        <Router>
            <div className='flex flex-col h-screen overflow-hidden'>
                <Header></Header>
                <div className='MainContent flex-1 overflow-y-scroll py-2 mx-2'>
                    <Routes>
                        <Route path="/" element={<OrderView />} />
                        <Route path="/DeliverymenView" element={<DeliverymenView />} />
                        <Route path="/InventoryView" element={<InventoryView />} />
                        <Route path="/RouteGenerationView" element={<RouteGenerationView />} />
                        <Route path="/AdministrativeView" element={<AdministrativeView />} />
                        <Route path="*" element={<ErrorView />} />
                    </Routes>
                </div>
                <Navbar></Navbar>
            </div>
        </Router>
    );
}

Header.js:

const Header = () => {
    return (
        <div className="Header shadow-md bg-white w-full ">
            <CurrentPage />
        </div>
    )
}

Navbar.js:

function Navbar() {
    return (
        <div className="Navbar w-full flex flex-row gap-x-2 justify-evenly py-1 bg-white drop-shadow-md-top">
            <Link to="/">
                <MdShoppingCart className="text-zinc-400 text-5xl "></MdShoppingCart>
            </Link>
            <Link to="/DeliverymenView">
                <MdPerson className="text-zinc-400 text-5xl "></MdPerson>
            </Link>
            <Link to="/InventoryView">
                <MdViewList className="text-zinc-400 text-5xl "></MdViewList>
            </Link>
            <Link to="/RouteGenerationView">
                <MdDeliveryDining className="text-zinc-400 text-5xl "></MdDeliveryDining>
            </Link>
        </div>
    )
}
LeperAffinity666
  • 364
  • 4
  • 14
  • Is your second screenshot showing an example of the `flex-col` solution? Because the header is showing some "fixed" behavior before it scrolls off the top, which should not happen. – Ed Lucas Jan 22 '22 at 17:14
  • Also, what styles are you applying with the `Header`, `Navbar`, and `MainContent` classes? – Ed Lucas Jan 22 '22 at 17:16
  • I ended up "downgrading" to "position: fixed" and adding padding to both the Header and Navbar. – LeperAffinity666 Jan 26 '22 at 17:56

2 Answers2

8

One way to keep flex on the parent container is to add sticky to the header and footer divs, with top-0 or bottom-0, like this:

Modified code from the tailwind play linked in your question.

<div class="flex flex-col h-screen">
  <header class="w-full text-center border-b border-grey p-4 sticky top-0">Some header</header>
  <main class="flex-1 overflow-y-scroll">
    <div class="min-h-screen bg-slate-100">
      <p>This is a very long section that consumes 100% viewport height!</p>
    </div>
    <div class="min-h-screen bg-slate-200">
      <p>This is second long section that consumes 100% viewport height!</p>
    </div>
    <div class="min-h-screen bg-slate-100">
      <p>This is third long section that consumes 100% viewport height!</p>
    </div>
    <div class="min-h-screen bg-slate-200">
      <p>This is fourth long section that consumes 100% viewport height!</p>
    </div>
    <div class="min-h-screen bg-slate-100">
      <p>This is fifth long section that consumes 100% viewport height!</p>
    </div>
  </main>
  <footer class="w-full text-center border-t border-grey p-4 sticky bottom-0">some footer</footer>
</div>


Michael McGreal
  • 521
  • 4
  • 7
  • 1
    I came back to this issue, implemented your solution and it finally worked. I did have to set a fixed `y` margin to my `
    ` component since it's height is variable.
    – LeperAffinity666 Mar 09 '22 at 21:49
0

Actually you don't need to set the position to "fixed" or "absolut". The problem can be solved simpler.

You need 4 divs. One as a container (we can call its class "root") which contains the further 3 divs.

For defining how much space each inner div can take from the root div we can use "flex" (with "flex" you can define the proportion to other components).

(You can of course change height and width of root as you like)

.root {
  height: 70vh;
  width: 50vw;
  display: flex;
  flex-direction: column;
  justify-content: stretch;
}

.Header--container {
  flex: 1;
  background-color: green;
}

.Footer--container {
  flex: 1;
  background-color: red;
}

.Content--container {
  flex: 5;
  background-color: white;
  overflow-y: scroll;
}
<div class="root">
  <div class="Header--container">
  </div>
  <div class="Content--container">
    Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
    sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
    Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
  </div>
  <div class="Footer--container">
  </div>
</div>
Maziar B.
  • 105
  • 1
  • 4