DEV Community

Stephen Charles Weiss
Stephen Charles Weiss

Posted on • Originally published at stephencharlesweiss.com on

1 4

Dealing With Disappearing “Position: Fixed” On Overflow?

Have you ever tried to have an element overflow when one of its children is in a fixed positioned relative to it?

Fun fact: It doesn’t work. The fixed element is hidden. Not in an “off the screen” way. Not in an underneath another element way. It’s just hidden or “cut” as it was described on StackOverflow. 1

The only thing to do is to reorient the elements so that the element that was the relatively positioned parent is now a sibling — which mostly defeats the purpose.

Disappearing Button On Overflow

This was the problem I was facing with a Modal element I was working on. I wanted a Modal that’s body was too long for the screen to scroll internally but still have a Close Icon in the top right that a user could hit to close the window.

The original Modal Dialog (the part of the Modal that has content - as opposed to the “mask” which covers the original document) looked something like this:

<ModalStyled {...props}>
  {onClose && <CloseButton onClick={onClose}>X</CloseButton>}
  {children}
</ModalStyled>

The ModalStyled was just a styled div, but the key was that it has position: relative.

This meant that the button could be something like (using styled-components):

import styled from styled-components
export const CloseButton = styled.button`
  position: absolute;
  top: -18px;
  right: -24px;
`;

If you look at the .gif, however, you’ll notice that when the ModalStyled is made overflow:auto, the button disappears!

The best solution I could come up with was to wrap the whole thing in a div and use flex box to orient it so that my CloseButton would still appear above the Modal, if not slightly off to the top right corner as initially.

<Wrapper>
  <MiniWrapper>
    {onClose && <InternalScrollCloseButton name={closeIcon} onClick={onClose} />}
  </MiniWrapper>
  <ModalStyled {...props}>
    {children}
  </ModalStyled>
</Wrapper

Import styled from styled-components;

export const Wrapper = styled.div`
  display: flex;
  flex-direction: column;
  max-height: 100%;
  margin: auto;
  overflow: auto;
`;

Export const MiniWrapper = styled.div`
  display: flex;
  Justify-content: flex-end;
`;

Once I had this - I could flip between the two using a prop, internalScroll.

It basically turned into:

export const Dialog = props => {

const { internalScroll, rest } = props;

return ( internalScroll
  ? (
    <Wrapper>
      <MiniWrapper>
        {onClose && <InternalScrollCloseButton name={closeIcon} onClick={onClose} />}
      </MiniWrapper>
      <ModalStyled {...props}>
        {children}
      </ModalStyled>
    </Wrapper)
  : (
    <ModalStyled {...props}>
      {onClose && <CloseButton onClick={onClose}>X</CloseButton>}
      {children}
    </ModalStyled>)
)};

Is it perfect? Hardly. Does it work and get me most of the way there without a significant amount of additional effort? Barring a generous internet soul divining the answer to me … absolutely.

Modal With Internal Scroll

P.S. I told a friend I’d made a Modal that had an internal scroll. His response? “Wince. Maybe that shouldn’t be a modal then?” Touché. None-the-less, this was my first blush with an interesting quirk of fixed position elements and overflow and I’ll never apologize for an opportunity to learn.

Footnotes

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read full post →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more