Search code examples
htmlcssscrollresizecss-position

Scrollable resizable div with fixed button


The following HTML shows a scrollable resizable div with a button and a further content div in it.

.container {
  width: 100%;
  max-width: 100%;
  height: 150px;
  position: relative;
  overflow: auto;
  resize: both;
  white-space: nowrap;
  background: lightgray;
}

.container .fixed {
  position: absolute;
  right: 5px;
  top: 5px;
}
<div class="container">
  <button class="fixed">Test</button>
  <div class="content">
    texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
    text<br>
  </div>
</div>

The button should be fixed at the top right corner in the div. This works fine for resizing, however, when I scroll, the button moves too. How can I fix this?


Solution

  • I initially misunderstood the pinning of the button. Anyway, the following works. You can resize the div and the button stays in the top right corner. [Edit] - So because the two elements are decoupled, I don't believe CSS can do it, so I added a little bit of JS to finish the job. It's crude but effective, and you can expand on this.

    const resizer = new ResizeObserver((items) => {
        items.forEach(item => {
            const btn = document.getElementById("content-button-id");
            btn.style["right"] = item.target.clientHeight < item.target.scrollHeight ? "25px" : "5px";
        })
    });
    window.addEventListener('DOMContentLoaded', () => {
        const el = document.getElementById("content-id");
        resizer.observe(el);
    });
    .container {
        position: relative;  /* Required for inner absolute position */
        height: 150px;
        resize: both; /* overflow is required to accompany this */
        overflow: auto;
        display: flex; /* use flex box to fill vertical spaces */
        flex-flow: column;
    }
    
    .container .content {
        position: relative;
        flex: 1 1 auto;
        white-space: nowrap;
        background: lightgray;
        overflow: auto;
        z-index: 5;
    }
    
    .container .content-button {
        position: absolute; /* pin to outer container */
        right: 5px;
        top: 5px;
        z-index: 10;
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>Resize Component Example</title>
    </head>
    <body>
        <div class="container">
            <button id="content-button-id" class="content-button">Test</button>
            <div id="content-id" class="content">
                <p>
                texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                </p>
                <p>
                    texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                </p>
                <p>
                    texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                </p>
                <p>
                    texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                </p>
                <p>
                    texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                </p>
                <p>
                    texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                </p>
                <p>
                    texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                </p>
                <p>
                    texttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttexttext
                </p>
            </div>
        </div>
    </body>
    </html>

    Some screenshots of it in action enter image description here

    enter image description here