Search code examples
cssshadow-dom

have CSS, including position: absolute; contained to a container node


How to have CSS, including position: absolute; contained to a container node? i.e. elements with position: absolute should be at container node top-left, not at entire document top-left. Like the equivalent of an iframe

Example code using shadow DOM to isolate CSS in styleNode, which I can't control:

test.html

<html>
<body>
<div>this should still be visible and not affected by container styling</div>

<div id="container"></div>


<script>
    let container = document.querySelector('#container')
    const shadow = container.attachShadow({mode: 'open'}); 
    const styleNode = document.createElement('style');
    styleNode.textContent = `
    div {
        background: blue;
        font-size: 32px;
        position: absolute;
        top: 0;
        left: 0;
    }
    `;

    shadow.appendChild(styleNode);
    const contentNode = document.createElement('div');
    contentNode.textContent = `Hello World`;
    shadow.appendChild(contentNode);
</script>
</body>
</html>

Desired result: 'Hello World' to show under 'this should still be visible', not on top of it.


Solution

  • The absolute positioning is happening relative to the first ancestor going upwards that itself has a position set.

    By default the body element is used if no such explicit positioning can be found.

    If you give the parent element position relative positioning will happen in relation to that instead.

    <html>
    <body>
    <div>this should still be visible and not affected by container styling</div>
    
    <div id="container"></div>
    
    
    <script>
        let container = document.querySelector('#container')
        const shadow = container.attachShadow({mode: 'open'}); 
        const styleNode = document.createElement('style');
        styleNode.textContent = `
        div {
            background: blue;
            font-size: 32px;
            position: absolute;
            top: 0;
            left: 0;
        }
        `;
    
        shadow.appendChild(styleNode);
        const contentNode = document.createElement('div');
        contentNode.textContent = `Hello World`;
        shadow.appendChild(contentNode);
    </script>
    </body>
    </html>