mdgriffith / elm-ui

What if you never had to write CSS again?
https://package.elm-lang.org/packages/mdgriffith/elm-ui/latest/
BSD 3-Clause "New" or "Revised" License
1.35k stars 111 forks source link

wrappedRow with centerX does not render centered when wrapped #57

Open sturgman opened 6 years ago

sturgman commented 6 years ago

Originally brought up in the Slack channel.

SSCCE

https://ellie-app.com/3Fsk9QQ9D6za1

module Main exposing (main)

import Element as E
import Element.Background as BG

myelement num =
    E.el [ E.centerX
         , E.width (E.px 100)
         , E.height (E.px 100)
         , BG.color (E.rgb 0 0.5 0.5)
        -- , E.explain Debug.todo
         ] (E.text (String.fromInt num))

view =
    E.wrappedRow [ E.spacing 10
                 , E.width E.fill
                -- , E.explain Debug.todo
                 , E.centerX]
        [ myelement 1
        , myelement 2
        , myelement 3
        , myelement 4
        , myelement 5
        , myelement 6
        ]

main =
    E.layout [] view

Expected behavior

Expected that both the first and second row remain centered when wrapping occurs. What actually happens is that the first row becomes right aligned and the second row becomes left aligned.

Versions

Diagnosis

Currently the way horizontal centering is achieved on the wrapped row is by adding property flex-grow: 1 to the first and last elements of the row. This strategy breaks down when the row is wrapped since the first element of the second row does not in general have flex-grow: 1

Temporary workarounds

The following Ellie has an attempt to add styles via Element.htmlAttribute but it fails because the css is added to the wrong elements: https://ellie-app.com/3FvRsWjVqrJa1

module Main exposing (main)

import Element as E
import Element.Background as BG
import Html.Attributes as HA

myelement attr num =
    E.el (attr ++ [ E.centerX
         , E.width (E.px 100)
         , E.height (E.px 100)
         , BG.color (E.rgb 0 0.5 0.5)
        -- , E.explain Debug.todo
         ]) (E.text (String.fromInt num))

view =
    E.wrappedRow [ E.spacing 10
                 , E.width E.fill
                -- , E.explain Debug.todo
                 , E.centerX
                 , E.htmlAttribute (HA.style "justify-content" "center")]
        [ myelement [E.htmlAttribute (HA.style "flex-grow" "0")] 1
        , myelement [] 2
        , myelement [] 3
        , myelement [] 4
        , myelement [] 5
        , myelement [E.htmlAttribute (HA.style "flex-grow" "0")] 6
        ]

main =
    E.layout [] view

The following is a workaround that works by adding css manually: https://ellie-app.com/3Fw9nkQX29ya1 It is the same as the SSCCE but with the following styles added manually (untested):

    .s.r > s:first-of-type.accx { flex-grow: 0 !important; }
    .s.r > s:last-of-type.accx { flex-grow: 0 !important; }
    .cx > .wrp { justify-content: center !important; }

I haven't tested how this would affect other content rendered by elm-ui

simvux commented 5 years ago

Another temporary workaround that doesn't require writing and importing css (but might be a bit more hacky) is if you have a Browser.Events.onResize subscription you could do something like

 (if m.window.width < 1100 then
            column
         else
            row) [] <| none
AlienKevin commented 4 years ago

I encountered this similar issue when trying to center an input slider in a column. A simple workaround to center one element in a column is:

E.column
        []
        [ ......
        , E.el
            [ E.htmlAttribute (Html.Attributes.style "marginLeft" "auto")
            ,  E.htmlAttribute (Html.Attributes.style "marginRight" "auto")
            ]
            yourElementHere
        , ......
        ]

Also remember to do

import Element as E
import Html.Attributes

in the header.

I also extracted out a function for centering an element:

center : E.Element msg -> E.Element msg
center element =
    E.el
        [ E.htmlAttribute (Html.Attributes.style "marginLeft" "auto")
        ,  E.htmlAttribute (Html.Attributes.style "marginRight" "auto")
        ]
        element

so the above example can be simplified as:

E.column
        []
        [ ......
        , center
          yourElementHere
        , ......
        ]

If you have many elements that needs to be centered, I created this helper function:

centerAll : List (E.Element msg) -> List (E.Element msg)
centerAll elements =
    List.map
    center
    elements

Use centerAll like so:

E.column
        []
        ( centerAll
        [ element1
        , element2
        , element3
        , element4      
        ])

To preserve the spacing of the row/column, you can use centerList:

centerList : List (E.Element msg) -> List (E.Element msg)
centerList elements =
    let
        length =
            List.length elements
    in
    List.indexedMap
        (\index element ->
            if index == 0 then
                E.el
                    [ E.htmlAttribute (Html.Attributes.style "marginLeft" "auto") ]
                    element

            else if index == length - 1 then
                E.el
                    [ E.htmlAttribute (Html.Attributes.style "marginRight" "auto") ]
                    element

            else
                element
        )
        elements
alexkorban commented 4 years ago

unexpected

eelcoh commented 3 years ago

Bit late to this one, but had the same problem. Found out that the culprit is the CenterX attribute on the element (not the row). Remove that one, and the row will align left. Or wrap it in an Element.el []