Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extend height to include absolutely positioned children

I'm building an html/javascript theme designer for a CMS. Elements are positioned absolutely and can be moved/resized via the mouse, and/or contain editable text whose height may be determined by the number of lines. However I'm running into the problem where a parent element's height does not expand to include its absolutely positioned children.

Minimal code (also on JSFiddle here):

<style>
    div.layer { position: absolute }
    div.layer1 { width: 400px; border: 1px solid #ccc }
    div.layer2 { top: 15px; left: 100px; width: 100px; border: 1px solid blue }
</style>
<div class="layer layer1">container should expand to the bottom of the child.
    <div class="layer layer2" contentEditable>Child with<br/>editable text.</div>
</div>

A CSS-only solution is ideal and I'm not concerned about older browsers. But I'm mostly looking for any way to prevent the need for javascript to run on every page using a created theme to set their height (since pages with the same theme may have different amounts of text).

There are already a few similar questions but their accepted answers (e.g. don't use absolute positioning) won't work in my case. Unless there is a way to have multiple layers of draggable/resizable elements without them being position: absolute.

like image 886
EricP Avatar asked Sep 22 '13 19:09

EricP


People also ask

What is absolute position?

Absolute positioning defines the position of a given bounding box from the top and left side margins of the web page. This not only allows objects to be placed in an exact location, it also allows objects to be placed one on top of another.

What is the difference between fixed and absolute positioning?

Absolutely positioned elements are positioned with respect to a containing block, which is the nearest postioned ancestor. If there is no positioned ancestor, the viewport will be the containing block. Elements with fixed positioning are fixed with respect to the viewport—the viewport is always their containing block.

What is position sticky?

position: sticky;A sticky element toggles between relative and fixed , depending on the scroll position. It is positioned relative until a given offset position is met in the viewport - then it "sticks" in place (like position:fixed).

What is CSS positioning?

What is the CSS position property? The CSS position property defines the position of an element in a document. This property works with the left, right, top, bottom and z-index properties to determine the final position of an element on a page.


3 Answers

I found a pure-css solution! In summary:

  1. Set the child elements to position: relative instead of absolute.
  2. Set their margin-right to be their negative width, to give them zero effective width, and make them float: left to keep them all on the same line. This makes all of them have an origin of 0, 0.
  3. Then we can set their left and margin-top properties to position them absolutely within their parents. Note that margin-top is required instead of top because top won't push down the bottom of the parent element.

JSFiddle here or code below:

<style>
    div.layer { position: relative; float: left; }
    div.layer1 { width: 400px; border: 1px solid black }
    div.layer2 { margin-top: 20px; left: 100px; width: 100px; margin-right: -100px; border: 1px solid blue }
    div.layer3 { margin-top: 30px; left: 170px; width: 100px; margin-right: -100px; border: 1px solid red }
    div.layer4 { margin-top: 30px; left: 20px; width: 60px; margin-right: -60px; border: 1px solid green }
</style>
<div class="layer layer1" style="position: relative; display: block; width: 400px; border: 1px solid black;">
    Container
    <div class="layer layer2" contentEditable>Edit me</div>
    <div class="layer layer3">
        <div class="layer layer4" contentEditable>Edit me</div>
    </div>
</div>
like image 120
EricP Avatar answered Oct 06 '22 23:10

EricP


absolute positioned elements are removed from the flow, thus ignored by other elements

the only way you have is to set the child position to position:relative, in this way it is possible to move it using right,left,top and bottom and also change parent display to display:inline-block

like image 40
M a m a D Avatar answered Oct 06 '22 23:10

M a m a D


If you want keep the children absolutely positioned, you can use the following script to resize the container : http://jsfiddle.net/6csrV/7/

var layer1 = document.getElementsByClassName('layer1'),
    i = 0, len = layer1.length, childHeight;
for(; i < len; i++) {
    childHeight = layer1[i].getElementsByClassName('layer')[0].clientHeight;
    layer1[i].style.height = childHeight + 'px';
}
document.addEventListener('keyup', function(e) {
    if(e.target.className.indexOf('layer2') !== false) {
        e.target.parentNode.style.height = e.target.clientHeight + 'px';
    }
});
like image 38
user2804989 Avatar answered Oct 06 '22 21:10

user2804989