2

I'm trying to create a 3-column layout where one of the columns scrolls as it overflows.

I have a working prototype here in this code sandbox.

It looks like this:

enter image description here

The teal/cyan color is the overflow scrolling section - and the topmost parent's padding is visible around the frame in gray.

The part that doesn't work - is that when I want to embed/nest this working flexbox within another flexbox that also contains a header - but when I do that, the contained scrolling of this one breaks - and the whole flexbox overflows off screen.

Codesandbox of version that doesn't work

Screenshot:

enter image description here

I guess there's something about flexbox sizing that I don't understand cause I have played around with different height/flex values and can't fix this.

What am I doing wrong?


P.S. I'm using Chakra-UI for components+styling - but the attributes are the same as vanilla CSS. I don't think that makes any difference to this problem. The markup is just more concise.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Vidur
  • 1,442
  • 2
  • 17
  • 37

2 Answers2

1

Adding h="100%" to the parent Flex container, removing h="100%" from the first child Flex container and adding minH="0" to it instead gives the desired result.

The problem here was that the parent height was unbounded meant that the children could take up as much space as they can and the parent would reflow to account for that since the children are set to flex-grow: 1.

import React from "react";
import _ from "lodash";
import {
  Flex,
  Box,
  Center,
  UnorderedList,
  ListItem,
  Heading
} from "@chakra-ui/react";

const Container = (props) => {
  const list = [];
  _.times(100, (i) => list.push(`Item ${i}`));

  return (
    <Flex id="container" flex={1} direction="column" h="100%">
      <Center id="header" h="75px" bg="yellow.300">
        <Heading>Flexbox Scroll Overflow Prototype</Heading>
      </Center>
      <Flex
        id="3-col-container"
        flex={1}
        bg="gray.100"
        p={4}
        minH="0"
        alignItems="stretch"
        gridColumnGap={2}
      >
        <Flex flex={1} bg="gray.50" direction="column" gridRowGap={2}>
          <Box minH="200px" bg="gray.500" />
          <Flex
            direction="column"
            pl={4}
            pt={2}
            flex={1}
            bg="teal.100"
            overflow="scroll"
          >
            <UnorderedList>
              {list.map((item) => (
                <ListItem mb={1} listStyleType="none" color="gray.700">
                  {item}
                </ListItem>
              ))}
            </UnorderedList>
          </Flex>
        </Flex>
        <Flex flex={1} bg="blue.100" />
        <Flex flex={1} bg="blue.200" />
      </Flex>
    </Flex>
  );
};

export default Container;
Vishal Biswas
  • 401
  • 2
  • 8
  • Hmm I see that this works, but what does `min-height: 0` do that allows it to work? Wouldn't `min-height` default to zero anyway? – Vidur Jan 25 '21 at 04:26
  • Default value of `min-height` is dependent on the layout module used. For flex items, you can refer this link -> https://www.w3.org/TR/css-flexbox-1/#min-size-auto For your case the `min-height` of all flex items are content-based. – Vishal Biswas Jan 26 '21 at 05:44
0

Solution

Add this to your code:

#container {
  height: calc(100vh - 75px);
}

#header {
  flex-shrink: 0;
}

Explanation

The height: 100% on the columns container isn't working.

enter image description here

This is because its parent has no defined height, as required by the height definition when using percentage values.

enter image description here

By switching from a percentage value the scrolling function works.

By subtracting the height of the header, an unwanted overflow is prevented.

#container {
   height: calc(100vh - 75px);
}

In some browsers, despite the calc formulation, the header may still shrink (remember it exists in a column-direction flex container). I guess this happens because the rendering engine factors in the height: 100vh before other rules.

To avoid this across browsers, just disable flex-shrink.

#header {
  flex-shrink: 0;
}

More on using the height property with percentage values.


More on the overflow property.

Generally speaking, for the overflow property to work there needs to be a fixed length.

Think of it this way: With a dynamic length, an overflow isn't possible because the element simply contracts or expands to meet the need.

Here's how MDN puts it:

In order for overflow to have an effect, the block-level container must have either a set height (height or max-height) or white-space set to nowrap.

https://developer.mozilla.org/en-US/docs/Web/CSS/overflow

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    Thank you for the detailed answer - I opted to mark the other one as the accepted solution because it was cleaner to implement. – Vidur Jan 27 '21 at 16:52