DEV Community

Stephen Charles Weiss
Stephen Charles Weiss

Posted on • Originally published at stephencharlesweiss.com on

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

Top comments (0)