Open gampleman opened 5 years ago
Yup. I ran into this exact behavior when I was learning Elm by building a browser for my photos. I wanted a top bar that allowed me to change the viewing mode and only the view would scroll.
[ (Element.layout [] <|
column [ width fill, height fill ]
[ row
[ paddingXY 20 0
, spacing 10
, verticalGrayGradient
, width fill
, height (px 60)
]
[ modeButton "Grid" Grid
, modeButton "Timeline" Timeline
, modeButton "Slideshow" Slideshow
, Input.button
[ alignRight ]
{ onPress = Just TodoInput
, label = Element.el
[ padding 8
, verticalBlueGradient
, Border.rounded 3
, Font.color offWhite
]
(text "Autoplay")
}
]
, el
[width fill, height fill, scrollbarY] -- !!! PROBLEM RIGHT HERE !!!
(case model.appMode of
Grid ->
(viewGrid model)
Timeline ->
(viewTimeline model)
Slideshow ->
none -- TODO. Not implemented
)
]
)]
The viewGrid
and viewTimeline
functions actually handle the rendering of the view but the idea is that the containing el
will be constrained to the screen size so whatever DOM elements those functions produce will scroll inside of the el
rather than causing the el
to keep growing. Correct me if I am wrong about this expectation as I still an Elm n3wb.
Anyways, I worked around this by keeping the Viewport
information from Browser.Dom
around in my model and forcing the maximum size of my container el
to be whatever was left after subtracting out the top bar. Note that this only works however if you know the size of all of your elements.
-- Problematic line changes to this
[width fill, height (fill |> maximum (Basics.round (model.viewport.viewport.height - 60.0))), scrollbarY]
Because AFAIK, we don't know IDs of anything elm-ui
produces so Browser.Dom.getViewportFor
is of no use.
I discovered by accident that a workaround is to add scrollbarY to the parent of the intended container, see https://ellie-app.com/538HjqscB6ka1
I've done some digging. I think the root cause is that flex-shrink is set to 0 except in scrolling elements. So if a would-be scrolling element is contained in something which doesn't have a fixed size, that container will grow indefinitely rather than triggering the scrollbars. Liberal application of htmlAttribute <| HtmlAttr.style "flex-shrink" "1"
to containers resolves the issue for me.
@mdgriffith Would something break if you just set flex-shrink to 1 for everything?
Wait, is this just #12?
The more I read, the more complicated this sounds. flex-shrink might not be sufficient? I'm unclear. https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size
In the past I've found wrapping children in a div with position absolute can help resolve flexbox issues. If you're stuck you can use this helper for now
scrollbarYEl : List (Attribute msg) -> Element msg -> Element msg
scrollbarYEl attrs body =
el [ height fill, width fill ] <|
el
([ htmlAttribute <| Html.Attributes.style "position" "absolute"
, htmlAttribute <| Html.Attributes.style "top" "0"
, htmlAttribute <| Html.Attributes.style "right" "0"
, htmlAttribute <| Html.Attributes.style "bottom" "0"
, htmlAttribute <| Html.Attributes.style "left" "0"
, Element.scrollbarY
]
++ attrs
)
body
Anyone figure a good solution to this?
Indeed, experiencing this issue as well.
@kmBlaine your post got me thinking - I was able to do some measuring by putting in an HTML element of zero size that has an ID, and then doing a getViewportFor on it. You have to add in the padding afterwards.
topBar : Model a -> Element Msg
topBar model =
E.row
[ E.width E.fill]
[ EI.button buttonStyle { label = E.text "select pdf", onPress = Just SelectClick }
<... more stuff ... >
, E.html <| Html.div [ HA.id "topbarheight", HA.style "height" "100%" ] [ Html.text "" ]
]
, Task.attempt TopViewport <| Browser.Dom.getViewportOf "topbarheight"
the way I worked around it was by adding htmlAttribute <| Html.Attributes.style "height" "100vh"
to the outer row
and adding scrollbarY
to the column
s, and it worked.
Also happens with elm-ui 1.1.5. #bug #has-ellie
I want this fixed. It's the only thing that has ever frustrated me a lot when using Elm.
Maybe having an easy workaround listed somewhere would help, since this is a hard-to-fix issue. There's a few listed in this thread, but maybe there could be one canonical solution.
@opsb 's solution was the most straightforward to apply for me.
https://ellie-app.com/3TtR8yh7Rw5a1
Expected behavior
The column above is marked
height fill
, so one would expect it to fill the container. It has children that overflow that height, butElement.scrollbarY
has been set there.So my expectation would be that the marked column would take the remaining space of the container but would allow all its children to scroll.
Versions
Motivation
This came up when building a sidebar for our application where in the main area the user can make a selection and related data to the selected items appears in the sidebar. We wanted the navigation and other items to remain visible in the sidebar, but have just the related data part scroll.