title: boundingClientRect to get position of element relative to document
body: <p>I'm trying to implement a drag and drop program, using <code>boundingClientRect</code> from the DOM package to get the dimensions of the element to be moved, and <code>position</code> from the Mouse to track the movement of the mouse when dragging. </p>
  
  <p>The program works fine before I have scrolled, but when I scroll down, the dragging element appears higher in the view than before I clicked it. What I suspect is happening is, <code>boundingClientRect</code> gets the position of the element relative to the viewpoint, and then I use those values to set the <code>top</code> and <code>left</code> values. However, <code>top</code> and <code>left</code> are relative to the document or to a parent element. However, I have no idea what I could use instead of or in addition to <code>boundingClientRect</code> to get the <code>left</code> and <code>top</code> values relative to the document or parent element. </p>
  
  <p>Here's the code, it's probably clearer than my rambling. </p>
  
  <pre><code>type alias Model =
      { movableItemsList : List Item
      , originalMovableItems : List Item
      , movingItem : Maybe ( Item, Rectangle )
      , receivingItemsList : List Item
      , updatedItemsList : List ( Item, Rectangle )
      , drag : Maybe Drag
      , scrollTop : Float
      }
  
  update : Msg -&gt; Model -&gt; ( Model, Cmd Msg )
  update msg model =
      case msg of
          DragAndDelete deleteMsg xy movingItem movingRectangle -&gt;
              model
                  ! [ command (DragStart xy movingItem movingRectangle)
                    , command (deleteMsg movingItem)
                    ]
  
          DragStart xy selectedItem movingRectangle -&gt;
              let
                  movingItem =
                      List.head (List.filter (\i -&gt; i.id == selectedItem.id) model.originalMovableItems)
                          |&gt; Maybe.withDefault (Item "" "" 0 "")
              in
                  { model
                      | drag = Just (Drag xy xy)
                      , movingItem = Just ( movingItem, movingRectangle )
                  }
                      ! []
  
          DragAt xy -&gt;
              { model
                  | drag =
                      (Maybe.map (\{ start } -&gt; Drag start xy) model.drag)
              }
                  ! []
  
          DragEnd _ -&gt;
              { model
                  | movingItem = Nothing
                  , drag = Nothing
              }
                  ! []
  
          DeleteFromUpdatedList movingItem -&gt;
              let
                  isKeepable iteratingItem =
                      iteratingItem.id /= movingItem.id
  
                  updatedItemsData =
                      List.filter (\( i, _ ) -&gt; isKeepable i) model.updatedItemsList
              in
                  { model
                      | updatedItemsList = updatedItemsData
                  }
                      ! []
  
          DeleteFromMovableList movingItem -&gt;
              let
                  isKeepable iteratingItem =
                      iteratingItem.id /= movingItem.id
  
                  movableItemsData =
                      List.filter isKeepable model.movableItemsList
              in
                  { model
                      | movableItemsList = movableItemsData
                  }
                      ! []
  
          UpdateReceivingItemsOnOverlap receivingRectangle receivingItem -&gt;
              let
                  receivingItemsData =
                      if (checkOverlap (getCurrentMovingRectangle model) receivingRectangle) then
                          List.map (\i -&gt; updateItemColor i receivingItem) model.receivingItemsList
                      else
                          model.receivingItemsList
              in
                  { model | receivingItemsList = receivingItemsData } ! []
  
          RestoreReceivingItemsListColor _ -&gt;
              let
                  receivingItemsData =
                      List.map restoreReceivingItemColor model.receivingItemsList
              in
                  { model | receivingItemsList = receivingItemsData } ! []
  
          AddValues receivingRectangle receivingItem -&gt;
              let
                  movingItem =
                      movingItemMaybe model.movingItem
  
                  updatedItemsData =
                      if (checkOverlap (getCurrentMovingRectangle model) receivingRectangle) then
                          ( { movingItem
                              | value = receivingItem.value + movingItem.value
                              , color = "#1A6B0D"
                            }
                          , receivingRectangle
                          )
                              :: model.updatedItemsList
                      else
                          model.updatedItemsList
              in
                  { model
                      | updatedItemsList = updatedItemsData
                  }
                      ! [ command (DeleteFromMovableList movingItem)
                        ]
  
          RestoreListContent -&gt;
              let
                  movingItem =
                      movingItemMaybe model.movingItem
  
                  listItems =
                      movingItem :: model.movableItemsList
              in
                  { model | movableItemsList = listItems } ! []
  
  
  getCurrentMovingRectangle : Model -&gt; Rectangle
  getCurrentMovingRectangle model =
      let
          movingItemTuple =
              Maybe.withDefault ( Item "" "" 0 "0", Rectangle 0 0 0 0 ) model.movingItem
  
          ( _, movingRect ) =
              movingItemTuple
      in
          case model.drag of
              Nothing -&gt;
                  movingRect
  
              Just { start, current } -&gt;
                  Rectangle
                      (movingRect.top + toFloat (current.y - start.y))
                      (movingRect.left + toFloat (current.x - start.x))
                      (movingRect.width)
                      (movingRect.height)
  
  
  
  -- VIEW
  
  
  view : Model -&gt; Html Msg
  view model =
      div
          []
          [ receivingAndUpdatedItemsLayersDiv model
          , movableItemsListDiv model
          , if model.movingItem /= Nothing then
              movingItemDiv model
            else
              div [] []
          ]
  
  
  receivingAndUpdatedItemsLayersDiv : Model -&gt; Html Msg
  receivingAndUpdatedItemsLayersDiv model =
      div
          [ style [ ( "position", "relative" ) ] ]
          [ div
              [ style
                  [ ( "position", "relative" )
                  , ( "top", "10px" )
                  , ( "left", "80px" )
                  ]
              ]
              [ div
                  [ style
                      [ ( "z-index", "3" )
                      , ( "position", "absolute" )
                      ]
                  , attribute "class" "drag-here-overlay"
                  ]
                  (List.map receivingItemOverlay model.receivingItemsList)
              , div
                  [ style
                      [ ( "z-index", "0" )
                      , ( "position", "absolute" )
                      ]
                  , attribute "class" "drag-here-underlay"
                  ]
                  (List.map receivingItemUnderlay model.receivingItemsList)
              ]
          , div
              []
              [ div
                  [ style
                      [ ( "position", "absolute" )
                      , ( "z-index", "1" )
                      ]
                  , attribute "class" "drag-here-updated"
                  ]
                  (List.map updatedItemUnderlay model.updatedItemsList)
              , div
                  [ style
                      [ ( "position", "absolute" )
                      , ( "z-index", "4" )
                      ]
                  ]
                  (List.map updatedItemOverlay model.updatedItemsList)
              ]
          ]
  
  
  movableItemsListDiv : Model -&gt; Html Msg
  movableItemsListDiv model =
      div
          [ style
              [ ( "position", "relative" )
              , ( "top", "10px" )
              , ( "left", "800px" )
              ]
          ]
          (List.map movableItemDiv model.movableItemsList)
  
  
  updatedItemUnderlay : ( Item, Rectangle ) -&gt; Html Msg
  updatedItemUnderlay ( item, rectangle ) =
      div
          [ attribute "class" "drag-here-updated-underlay-item"
          , sharedStyles
          , style
              [ ( "background-color", item.color )
              , ( "border", "1px solid #000" )
              , ( "position", "absolute" )
              , ( "left", px rectangle.left )
              , ( "top", px rectangle.top )
              ]
          ]
          [ text item.text
          , br [] []
          , text (toString item.value)
          ]
  
  
  updatedItemOverlay : ( Item, Rectangle ) -&gt; Html Msg
  updatedItemOverlay ( item, rectangle ) =
      div
          [ onDragStart DeleteFromUpdatedList item
          , attribute "class" "drag-here-updated-overlay-item"
          , sharedStyles
          , style
              [ ( "background-color", "transparent" )
              , ( "position", "absolute" )
              , ( "left", px rectangle.left )
              , ( "top", px rectangle.top )
              ]
          ]
          []
  
  
  receivingItemUnderlay : Item -&gt; Html Msg
  receivingItemUnderlay item =
      div
          [ attribute "class" "drag-here-underlay-item"
          , sharedStyles
          , style
              [ ( "background-color", item.color )
                -- , ( "border", "1px solid #1A6B0D" )
              ]
          ]
          [ text item.text
          , br [] []
          , text (toString item.value)
          ]
  
  
  receivingItemOverlay : Item -&gt; Html Msg
  receivingItemOverlay item =
      div
          [ on "mouseenter" (Decode.map (\d -&gt; UpdateReceivingItemsOnOverlap d item) (DOM.target DOM.boundingClientRect))
          , on "mouseleave" (Decode.map (\d -&gt; RestoreReceivingItemsListColor d) (DOM.target DOM.boundingClientRect))
          , on "mouseup" (Decode.map (\d -&gt; AddValues d item) (DOM.target DOM.boundingClientRect))
          , attribute "class" "drag-here-overlay-item"
          , sharedStyles
          , style
              [ ( "background-color", "transparent" ) ]
          ]
          []
  
  
  movableItemDiv : Item -&gt; Html Msg
  movableItemDiv item =
      div
          [ onDragStart DeleteFromMovableList item
          , attribute "id" ("drag-me " ++ toString item.value)
          , sharedStyles
          , style
              [ ( "background-color", item.color )
              , ( "border", "1px solid #DD0848" )
              , ( "position", "relative" )
              ]
          ]
          [ text "Drag Me!"
          , br [] []
          , text (toString item.value)
          ]
  
  
  movingItemDiv : Model -&gt; Html Msg
  movingItemDiv model =
      let
          movingItem =
              movingItemMaybe model.movingItem
  
          realRectangle =
              getCurrentMovingRectangle model
      in
          div
              [ onMouseUp RestoreListContent
              , sharedStyles
              , style
                  [ ( "background-color", "#FF3C8C" )
                  , ( "border", "1px solid #DD0848" )
                  , ( "position", "absolute" )
                  , ( "top", px (realRectangle.top) )
                  , ( "left", px (realRectangle.left) )
                  , ( "z-index", "2" )
                  ]
              ]
              [ text movingItem.text
              , br [] []
              , text (toString movingItem.value)
              ]
  
  
  sharedStyles : Attribute a
  sharedStyles =
      style
          [ ( "width", "100px" )
          , ( "height", "100px" )
          , ( "border-radius", "4px" )
          , ( "color", "white" )
          , ( "justify-content", "center" )
          , ( "align-items", "center" )
          , ( "display", "flex" )
          ]
  
  
  onDragStart : (Item -&gt; Msg) -&gt; Item -&gt; Attribute Msg
  onDragStart deleteMsg item =
      on "mousedown"
          (Mouse.position
              `Decode.andThen`
                  (\posit -&gt;
                      DOM.target DOM.boundingClientRect
                          `Decode.andThen`
                              (\rect -&gt;
                                  Decode.succeed (DragAndDelete deleteMsg posit item rect)
                              )
                  )
          )
  
  
  px : countable -&gt; String
  px number =
      toString number ++ "px"
  </code></pre>
  
  <p>So, as you can see, when one clicks a <code>movableItemDiv</code>, the model's <code>drag</code> and <code>movingItem</code> fields are updated with the position of the mouse and the dimensions (Rectangle) of the <code>movableItem</code> respectively. However, these dimensions are relative to the viewpoint. <code>movingItemDiv</code> then calls <code>getCurrentMovingRectangle</code>, which sets the <code>left</code> and <code>top</code> styles of <code>movingItemDiv</code> according to the dimensions of the <code>movingItem</code> and the <code>drag</code> in the model. Because the dimensions of the <code>movingItem</code> are based on dimensions of the <code>movableItemDiv</code> relative to the viewpoint, not relative to the document, while the values set for the <code>top</code> and <code>left</code> values of the <code>movingItemDiv</code> establish the position of the element relative to the document (or the parent element, I'm not sure to be honest), the <code>movingItemDiv</code> is not positioned correctly. I hope this is clear!</p>