Absolute positioned HTML element still shrinking when it reaches the edge of parent element

Issue

I’m making a node editor (along the lines of UE4’s blueprints or Blender’s shader nodes) and running into a problem where the absolute positioned nodes are having their insides squished when they reach the edge of the viewport.

Here’s a video of the problem in action: https://youtu.be/ZglXI7BOx-k (the reason it’s squishing before the edge is because I have a translate(-50%, -50%) on it)

I’ve set up the following simplified example that still demonstrates the problem

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>CSS Squish test</title>
    <style>
        .wrapper{
            position: relative;
            width: 500px;
            height: 500px;
            background: #EEEEEE;
        }

        .node{
            position: absolute;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            background: #AAAAFF;
            padding: 4px;
        }

        .body{
            display: flex;
            flex-direction: row;
        }

        .column{
            display: flex;
            flex-direction: column;
            align-items: stretch;
            flex-shrink: 0;
        }

        .entry{
            display: flex;
            flex-direction: row;
            flex-shrink: 0;
        }

        .left{
            justify-content: flex-start;
        }

        .right{
            justify-content: flex-end;
        }
    </style>
    <script>
        window.onload = ()=>{
            let node = document.getElementById('node');
            node.style.left = '0px';
            main();
        }

        function main(){
            let node = document.getElementById('node');
            let oldPos = parseInt(node.style.left);
            node.style.left = (oldPos + 2) + 'px';

            requestAnimationFrame(main);
        }
    </script>
</head>
<body>
    <div class="wrapper">
        <div id="node" class="node">
            <div class="title">Title</div>
            <div class="body">
                <div class="column" style="background: #AAFFAA">
                    <div class="entry left">
                        <div>&lt;</div>
                        <div>Text</div>
                    </div>
                </div>
                <div class="column" style="background: #FFAAAA">
                    <div class="entry right">
                        <div>Text</div>
                        <div>&gt;</div>
                    </div>
                    <div class="entry right">
                        <div>A whole bunch of text</div>
                        <div>&gt;</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

Since in the real program the viewport can be panned around, I’d prefer it if nodes didn’t squish, but instead retained their original size no matter where they were positioned. I’d also like to do this without setting a defined width for the nodes as I’d rather have different sized nodes that adjust based on their contents.

I was under the assumption that making an element absolute removed it from the page flow, so I’m pretty confused as to why it’s still adjusting its size. Any solutions on how to fix this?

Solution

A possible fix is to add width: fit-content to the node.

Current browser compatibility looks decent according to MDN, except on IE.

<!DOCTYPE html>
<head>
    <meta charset="UTF-8">
    <title>CSS Squish test</title>
    <style>
        .wrapper{
            position: relative;
            width: 500px;
            height: 500px;
            background: #EEEEEE;
        }

        .node{
            position: absolute;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            background: #AAAAFF;
            padding: 4px;
            width: fit-content;
        }

        .body{
            display: flex;
            flex-direction: row;
        }

        .column{
            display: flex;
            flex-direction: column;
            align-items: stretch;
            flex-shrink: 0;
        }

        .entry{
            display: flex;
            flex-direction: row;
            flex-shrink: 0;
        }

        .left{
            justify-content: flex-start;
        }

        .right{
            justify-content: flex-end;
        }
    </style>
    <script>
        window.onload = ()=>{
            let node = document.getElementById('node');
            node.style.left = '0px';
            main();
        }

        function main(){
            let node = document.getElementById('node');
            let oldPos = parseInt(node.style.left);
            node.style.left = (oldPos + 2) + 'px';

            requestAnimationFrame(main);
        }
    </script>
</head>
<body>
    <div class="wrapper">
        <div id="node" class="node">
            <div class="title">Title</div>
            <div class="body">
                <div class="column" style="background: #AAFFAA">
                    <div class="entry left">
                        <div>&lt;</div>
                        <div>Text</div>
                    </div>
                </div>
                <div class="column" style="background: #FFAAAA">
                    <div class="entry right">
                        <div>Text</div>
                        <div>&gt;</div>
                    </div>
                    <div class="entry right">
                        <div>A whole bunch of text</div>
                        <div>&gt;</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>

Answered By – Anis R.

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published