1

I have a container with lots of content and hence I have set overflow: auto; to make it scrolling.

I also need a button in the bottom-right corner of this container at a fixed position (similar to a FAB button in Material Design).

The button is nicely placed in the bottom-right of the container. Unfortunately when I scroll the content, the button moves with it. My understanding of absolute positioning is that it will position the element relative to its parent (with position: relative;). So why is this button moving? What's the right way to fix it to the parent?

The expected behavior is that the button stays in the bottom-right corner regardless of the scroll position. For an example, see this page and search for the phrase "Animation of toolbar off-screen during scrolling".

Note that I am looking to make this work with absolute positioning, not fixed positioning. The button should be in bottom-right corner of its container, not matter how deeply the container is nested in the browser window.

* { 
    box-sizing: border-box; 
}
.container {
    position: relative;
    overflow: auto;
    height: 256px;
    width: 256px;
    margin-right: 16px;
    border: solid 1px red;
    padding: 4px;
}
.fab {
    position: absolute;
    right: 20px;
    bottom: 20px;
    color: white;
    background-color: blue;
}
<div class="container">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur mollitia maxime facere quae cumque perferendis cum atque quia repellendus rerum eaque quod quibusdam incidunt blanditiis possimus temporibus reiciendis deserunt sequi eveniet necessitatibus maiores quas assumenda voluptate qui odio laboriosam totam repudiandae? Doloremque dignissimos voluptatibus eveniet rem quasi minus ex cumque esse culpa cupiditate cum architecto! Facilis deleniti unde suscipit minima obcaecati vero ea soluta odio cupiditate placeat vitae nesciunt quis alias dolorum nemo sint facere. Deleniti itaque incidunt eligendi qui nemo corporis ducimus beatae consequatur est iusto dolorum consequuntur vero debitis saepe voluptatem impedit sint ea numquam quia voluptate quidem.
    <Button class="fab">
        Ok
    </Button>
</div>

Please see my JSFiddle here

Naresh
  • 23,937
  • 33
  • 132
  • 204
  • there is no button in your fiddle – Claire Oct 21 '17 at 16:21
  • 1
    There is no floating button in the JSfiddle. Also please read the following as there is no need to use JSfiddle, css/js/html snippets can be created all in SO. https://stackoverflow.blog/2014/09/16/introducing-runnable-javascript-css-and-html-code-snippets/ – Dale Oct 21 '17 at 16:21
  • 1
    @Dale_dale12, didn't realize that css/js/htm snippets can be created in SO directly. Will do that next time. – Naresh Oct 21 '17 at 17:41
  • 1
    @TylerH, that question provides a solution with fixed positioning, which works relative to the browser window. I need it relative to the container which could be nested inside many other containers. I have also added an example of the expected behavior. It would also help if someone could explain why my original code is not working - it goes against my understanding of absolute positioning! – Naresh Oct 21 '17 at 18:31
  • @Naresh You're correct. However I'm confident this question has been asked on the site already. – TylerH Oct 21 '17 at 19:58
  • 1
    This deserves to be reopened. The linked question about absolute positioning in a parent container, which is supposed to be duplicated by this one, has very little to do with what @Naresh asked for. I myself would love to find out why the position absolute works like it does in a scrollable parent. – Dan Macak Dec 10 '19 at 22:19

3 Answers3

2

You can do this by adding a wrapper div for the text. The wrapper div will its width and height set to 100% and overflow set to auto, so it will have the scroll box and your FAB can be positioned within the outer div like so:

* {
  box-sizing: border-box;
}

.fab {
  position: absolute;
  right: 20px;
  bottom: 20px;
}

.container {
  position: relative;
  border: solid 1px red;
  height: 256px;
  width: 256px;
  float: left;
  margin-right: 16px;
}

.text-wrapper {
  overflow: auto;
  height: 100%;
  width: 100%
}
<div class="container">
  <div class="text-wrapper">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur mollitia maxime facere quae cumque perferendis cum atque quia repellendus rerum eaque quod quibusdam incidunt blanditiis possimus temporibus reiciendis deserunt sequi eveniet necessitatibus
    maiores quas assumenda voluptate qui odio laboriosam totam repudiandae? Doloremque dignissimos voluptatibus eveniet rem quasi minus ex cumque esse culpa cupiditate cum architecto! Facilis deleniti unde suscipit minima obcaecati vero ea soluta odio
    cupiditate placeat vitae nesciunt quis alias dolorum nemo sint facere. Deleniti itaque incidunt eligendi qui nemo corporis ducimus beatae consequatur est iusto dolorum consequuntur vero debitis saepe voluptatem impedit sint ea numquam quia voluptate
    quidem.
  </div>

  <Button class="fab">
        Ok
    </Button>
</div>
Dale
  • 1,911
  • 11
  • 18
  • then you need to explain in more detail what the result is, where do you want the FAB to be positioned? – Dale Oct 21 '17 at 16:37
  • The snippet does not behave as expected. The button should not scroll when the content is scrolled. – Naresh Oct 21 '17 at 17:42
  • So you want it to be only visible at the bottom of the scrollable section, but not scroll in? How do you want it to appear? – Dale Oct 21 '17 at 17:46
  • please see my update - I have included an example of the expected behavior. – Naresh Oct 21 '17 at 18:34
1

There are many ways of achieving this, but I would prefer wrapping the .container with a .container-parent of the same height and width, and position: relative. This gives you a non-scrolling element to position the .fab button against.

<div class="container-parent">
  <div class="container">
    Lorem ipsum dolor sit amet...
  </div>
  <Button class="fab">
    Ok
  </Button>

</div>

With CSS:

.container-parent {
  position: relative;
  height: 256px;
  width: 256px;
}

.fab {
  position: absolute;
  bottom: 20px;
  right: 20px;
}

Here's the fiddle: http://jsfiddle.net/t702Lknz/4/

Alternatively, you could use your original markup, with .fab having a fixed position. The CSS would be like:

.fab {
    position: fixed;
    top: 225px;
    left: 190px;
}

Here's the fiddle for that: http://jsfiddle.net/t702Lknz/3/

Nisarg Shah
  • 14,151
  • 6
  • 34
  • 55
  • @VXp What is the expected result? Also, are you associated with Naresh?? If yes, please edit the question to highlight what exactly is required. – Nisarg Shah Oct 21 '17 at 16:44
  • both your solutions work as expected - still trying to digest the first one. The second one is less desirable since it is relative to top and the size of my container is not fixed. – Naresh Oct 21 '17 at 18:08
  • @Naresh The problem we are trying to solve is the scroll. By adding a parent-container, and setting it as the frame of reference, we don't have to worry about the scrolling in the container. – Nisarg Shah Oct 21 '17 at 18:11
  • looking at your first answer, the hard-coding of the container-parent's height is not ideal. It's giving me issues in the real code where the parent's height varies with the window height. I need more flexibility there. I do agree that we need to somehow set a frame of reference for the absolute positioning. – Naresh Oct 21 '17 at 19:30
  • I found a solution without duplicating container heights. It uses Flexbox. I posted it as an answer. – Naresh Oct 21 '17 at 19:45
1

I finally figured out how to do this. Since only the text should scroll, it should be inside its own scrolling container. This makes the button latch on to its parent without being affected by the scrolling. Here's the final code.

* { box-sizing: border-box; }

.container {
    /* keep the add button in a fixed location relative to this container */
    position: relative;
    display: flex;
    flexDirection: column;
    height: 200px;
    width: 200px;
    margin-right: 16px;
    border: solid 1px red;
    padding: 4px;
}

.text-container {
    /* ensure that only the text scrolls, not the button */
    flex: 1;
    overflow: auto;
}

.fab {
    position: absolute;
    right: 20px;
    bottom: 20px;
    color: white;
    background-color: blue;
}
<div class="container">
    <div class="text-container">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur mollitia maxime facere quae cumque perferendis cum atque quia repellendus rerum eaque quod quibusdam incidunt blanditiis possimus temporibus reiciendis deserunt sequi eveniet necessitatibus maiores quas assumenda voluptate qui odio laboriosam totam repudiandae? Doloremque dignissimos voluptatibus eveniet rem quasi minus ex cumque esse culpa cupiditate cum architecto! Facilis deleniti unde suscipit minima obcaecati vero ea soluta odio cupiditate placeat vitae nesciunt quis alias dolorum nemo sint facere. Deleniti itaque incidunt eligendi qui nemo corporis ducimus beatae consequatur est iusto dolorum consequuntur vero debitis saepe voluptatem impedit sint ea numquam quia voluptate quidem.    
    </div>
    <Button class="fab">
        Ok
    </Button>
</div>
Naresh
  • 23,937
  • 33
  • 132
  • 204
  • Seems like the accepted answer should be [this one](https://stackoverflow.com/a/46865409/5783990) – Alex Aug 24 '23 at 21:25