Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Absolute position element's width truncates when extending beyond relative parent's right border

These position: absolute; divs placed inside/around a position: relative; parent receive height/width from the size and length of the contained text.

However, if one of them extends beyond the right border of the relative parent, its width appears to truncate.

How can I make the div which extends beyond the right side of the relative parent behave as the others which don't, using only css? (Should work on all major browsers including Edge but not IE)

Here is a fiddle, but I will also copy the code + screenshot below:

example

HTML:

<div id="relative">
    <div id="absolute-working-left">
        My width and height are determined by my text content.
    </div>
    <div id="absolute-working-middle">
        Mine, too.
    </div>
    <div id="absolute-problem">
        But not me... I am a problem, because my width is truncated when I extend beyond the right side of my 'relative' parent.  WHY???
    </div>
</div>

...and the styles. Note that I want the absolute div width to reach a max of 200px before wrapping. Otherwise, the width should be determined by the length of the contained text:

#relative {
  position: relative;
  width: 100px;
  height: 100px;
  margin-left: 300px;
  background-color: white;
}

#absolute-problem,
#absolute-working-left,
#absolute-working-middle {
  position: absolute;
  top: 45px;
  font-size: 12px;
  max-width: 200px;
}

#absolute-working-left {
  background-color: lightblue;
  left: -300px;
}
#absolute-working-middle {
  background-color: lightgreen;
}
#absolute-problem {
  background-color: red;
  left: 80px;
}

This issue arose while implementing a tooltip which, when used by a developer, needs to position itself WRT an offsetParent (or the body, if no preceding offsetParent exists in its DOM branch).

Edit: How can I achieve the desired behavior using only css?

The solution needs to work on all major browsers including Edge, but not IE. And just to reiterate, the width of the absolute divs' cannot be predicted as it should be determined by the length of the texts... the only exception being that there will be a max-width (in this example, it is 200px).

like image 993
Manningham Avatar asked Feb 01 '17 05:02

Manningham


2 Answers

The #absolute-problem div has a left set to a particular value, an auto width and an auto right. According to this rule in §10.3.7 of the spec, this would shrink the div's width to fit its contents.

'width' and 'right' are 'auto' and 'left' is not 'auto', then the width is shrink-to-fit . Then solve for 'right'.

While there doesn't seem to be a reliable way to achieve the exact desired behavior (as there aren't enough properties set to calculate the width), following are some ways to work around this problem.

Set a width for the absolute div

A trivial solution would be to set its width, so that it doesn't shrink.

#absolute-problem {
  background-color: red;
  left: 80px;
  width: 100px;
}

body {
  background: #EEE;
}
#relative {
  position: relative;
  width: 100px;
  height: 100px;
  margin-left: 300px;
  background-color: white;
  font-size: 12px;
}
#absolute-problem,
#absolute-working-left,
#absolute-working-middle {
  position: absolute;
  top: 45px;
  font-size: 12px;
  max-width: 200px;
}
#absolute-working-left {
  background-color: lightblue;
  left: -300px;
}
#absolute-working-middle {
  background-color: lightgreen;
}
#absolute-problem {
  background-color: red;
  left: 80px;
  width: 100px;
}
<div id="relative">
  relative parent
  <div id="absolute-working-left">
    My width and height are determined by my text content.
  </div>
  <div id="absolute-working-middle">
    Mine, too.
  </div>
  <div id="absolute-problem">But not me... I am a problem, because my width is truncated when I extend beyond the right side of my 'relative' parent. WHY???</div>
</div>

Set a right for the absolute div

It the width of your div is unknown, one way to get around this is to set the right as well. This adjusts the width of your div accordingly.

#absolute-problem {
  background-color: red;
  right: -80px;
  left: 80px;
}

body {
  background: #EEE;
}
#relative {
  position: relative;
  width: 100px;
  height: 100px;
  margin-left: 300px;
  background-color: white;
  font-size: 12px;
}
#absolute-problem,
#absolute-working-left,
#absolute-working-middle {
  position: absolute;
  top: 45px;
  font-size: 12px;
  max-width: 200px;
}
#absolute-working-left {
  background-color: lightblue;
  left: -300px;
}
#absolute-working-middle {
  background-color: lightgreen;
}
#absolute-problem {
  background-color: red;
  left: 80px;
  right: -80px;
}
<div id="relative">
  relative parent
  <div id="absolute-working-left">
    My width and height are determined by my text content.
  </div>
  <div id="absolute-working-middle">
    Mine, too.
  </div>
  <div id="absolute-problem">But not me... I am a problem, because my width is truncated when I extend beyond the right side of my 'relative' parent. WHY???</div>
</div>

Set the width to fit-content/max-content

Another way would be to use a fit-content or max-content (limited browser compatibility) for the absolute div, instead of setting its right. This helps if the content of your div doesn't necessarily extend to the maximum width.

#absolute-problem {
  background-color: red;
  right: -80px;
  width: fit-content;
}

body {
  background: #EEE;
}
#relative {
  position: relative;
  width: 100px;
  height: 100px;
  margin-left: 300px;
  background-color: white;
  font-size: 12px;
}
#absolute-problem,
#absolute-working-left,
#absolute-working-middle {
  position: absolute;
  top: 45px;
  font-size: 12px;
  max-width: 200px;
}
#absolute-working-left {
  background-color: lightblue;
  left: -300px;
}
#absolute-working-middle {
  background-color: lightgreen;
}
#absolute-problem {
  background-color: red;
  left: 80px;
  width: fit-content;
}
<div id="relative">
  relative parent
  <div id="absolute-working-left">
    My width and height are determined by my text content.
  </div>
  <div id="absolute-working-middle">
    Mine, too.
  </div>
  <div id="absolute-problem">But not me...</div>
</div>

Set min-width and max-width

A realistic approach would be to give the the ability to adjust its size within a given range, in order to keep its overflow in check.

#absolute-problem {
  background-color: red;
  left: 80px;
  min-width: 50px;
  max-width: 200px;
}

body {
  background: #EEE;
}
#relative {
  position: relative;
  width: 100px;
  height: 100px;
  margin-left: 300px;
  background-color: white;
  font-size: 12px;
}
#absolute-problem,
#absolute-working-left,
#absolute-working-middle {
  position: absolute;
  top: 45px;
  font-size: 12px;
  max-width: 200px;
}
#absolute-working-left {
  background-color: lightblue;
  left: -300px;
}
#absolute-working-middle {
  background-color: lightgreen;
}
#absolute-problem {
  background-color: red;
  left: 80px;
  min-width: 50px;
  max-width: 200px;
}
<div id="relative">
  relative parent
  <div id="absolute-working-left">
    My width and height are determined by my text content.
  </div>
  <div id="absolute-working-middle">
    Mine, too.
  </div>
  <div id="absolute-problem">But not me...</div>
</div>
like image 161
John Bupit Avatar answered Oct 11 '22 00:10

John Bupit


I met this problem in one of my projects too and I found a simple solution to this. Just add a negative margin-right to the box.

#absolute-problem {
  margin-right: -9999999px;
}

This should work in that situation. The 9999999px is very high so that the box will extend to the right as long as the content is. If you want a limit, give it a reasonable length will work.

like image 26
Benber Zhang Avatar answered Oct 11 '22 02:10

Benber Zhang