3

In example below I want to position element with id child, so it's right-top corner matches right-top corner of element with id container. In other words, it's desired for child to stick out to the left and to the bottom of container and have its right and top edges aligned with container.

However, as you can see child is compressed to match container width. But not completely - in second example it's clear that child is compressed up to some limit and then begins to behave as desired (i.e. move to the left relative to the container).

Can somebody explain what magic forces are involved in such behavior and how I can specify that child shouldn't compress below its intrinsic size?

In third example I add some less compressible text, which definitely improves the situation. Somehow flex item that are also flex containers are much more compressible than regular block elements.

  <div id="container" style="position: relative; width: 100px; height: 100px; left: 50px; border: 1px solid red">
      <div id="child" style="position: absolute; display:flex; flex-direction: column; right: 0px; border: 1px solid blue">
        <div style="
display:flex">
          <div style="flex: 1 0 auto">Long text 1</div>
          <div style="flex: 0 0 auto">Long text 2</div>
        </div>
        <div style="display:flex">
          <div style="flex: 1 0 auto">Long text 1</div>
          <div style="flex: 0 0 auto">Long text 2</div>
        </div>
      </div>
  </div>
  <hr>
  <div id="container" style="position: relative; width: 50px; height: 100px; left: 50px; border: 1px solid red">
      <div id="child" style="position: absolute; display:flex; flex-direction: column; right: 0px; border: 1px solid blue">
        <div style="
display:flex">
          <div style="flex: 1 0 auto">Long text 1</div>
          <div style="flex: 0 0 auto">Long text 2</div>
        </div>
        <div style="display:flex">
          <div style="flex: 1 0 auto">Long text 1</div>
          <div style="flex: 0 0 auto">Long text 2</div>
        </div>
      </div>
  </div>
  <hr>
  <div id="container" style="position: relative; width: 50px; height: 100px; left: 50px; border: 1px solid red">
      <div id="child" style="position: absolute; display:flex; flex-direction: column; right: 0px; border: 1px solid blue">
        <div style="white-space: nowrap;">This is just&nbsp;ridiculous</div>
        <div style="
display:flex">
          <div style="flex: 1 0 auto">Long text 1</div>
          <div style="flex: 0 0 auto">Long text 2</div>
        </div>
        <div style="display:flex">
          <div style="flex: 1 0 auto">Long text 1</div>
          <div style="flex: 0 0 auto">Long text 2</div>
        </div>
      </div>
  </div>
wonder.mice
  • 7,227
  • 3
  • 36
  • 39
  • I think that your question boils down to wanting the layout to overflow to the left. This isn't possible in LTR text direction because `overflow` in HTML / CSS can only occur in the text direction (otherwise, it's not an overflow). https://stackoverflow.com/a/38830775/3597276 – Michael Benjamin May 11 '19 at 00:39

1 Answers1

2

A bit tricky to explain but here the shrink-to-fit behavior of the absolute element is controling the width of your element. From the specification we have:

Calculation of the shrink-to-fit width is similar to calculating the width of a table cell using the automatic table layout algorithm. Roughly: calculate the preferred width by formatting the content without breaking lines other than where explicit line breaks occur, and also calculate the preferred minimum width, e.g., by trying all possible line breaks. CSS 2.1 does not define the exact algorithm. Thirdly, calculate the available width: this is found by solving for 'width' after setting 'left' (in case 1) or 'right' (in case 3) to 0.

Then the shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width).

The key here is the preferred minimum width which is the minimum boundry.

To better understand let's remove some properties:

#container {
  animation:change 5s linear infinite alternate;
}

@keyframes change {
  from {
    width:300px;
  }
  to {
    width:50px;
  }
}
<div id="container" style="position: relative; height: 100px; left: 50px; border: 1px solid red">
      <div id="child" style="position: absolute; display:flex; flex-direction: column; right: 0px; border: 1px solid blue">
        <div style="
display:flex">
          <div style="/*flex: 1 0 auto*/">Long text 1</div>
          <div style="/*flex: 0 0 auto*/">Long text 2</div>
        </div>
  
      </div>
  </div>

You can clearly see how the absolute element will fit its content (the preferred width) and when there is less space the text will start wrapping until we reach the preferred minimum width and the element will stop shriking. This is the limit you are having.

Adding the flex properties this will change nothing because these properties will not affect how the width of their parent element behave but they will consider that width in order to do the needed calculation (grow, shrink, etc)

#container {
  animation:change 5s linear infinite alternate;
}

@keyframes change {
  from {
    width:300px;
  }
  to {
    width:50px;
  }
}
<div id="container" style="position: relative; height: 100px; left: 50px; border: 1px solid red">
      <div id="child" style="position: absolute; display:flex; flex-direction: column; right: 0px; border: 1px solid blue">
        <div style="
display:flex">
          <div style="/*flex: 1 0 auto*/">Long text 1</div>
          <div style="/*flex: 0 0 auto*/">Long text 2</div>
        </div>
  
      </div>
  </div>
  <div id="container" style="position: relative; height: 100px; left: 50px; border: 1px solid red">
      <div id="child" style="position: absolute; display:flex; flex-direction: column; right: 0px; border: 1px solid blue">
        <div style="
display:flex">
          <div style="flex: 1 0 auto">Long text 1</div>
          <div style="flex: 0 0 auto">Long text 2</div>
        </div>
  
      </div>
  </div>

You can clearly notice that we have the same width in both cases and in the second example we simply told our elements to not shrink so we will have overflow:


In your third example, by adding white-space: nowrap; you simply increased the preferred minimum width since you disabled line break thus the browser will consider the preferred minimum width equal to the preferred width:

#container {
  animation:change 5s linear infinite alternate;
}

@keyframes change {
  from {
    width:300px;
  }
  to {
    width:50px;
  }
}
<div id="container" style="position: relative; height: 100px; left: 50px; border: 1px solid red">
      <div id="child" style="position: absolute; display:flex; flex-direction: column; right: 0px; border: 1px solid blue">
        <div style="
display:flex;white-space:nowrap">
          <div style="/*flex: 1 0 auto*/">Long text 1</div>
          <div style="/*flex: 0 0 auto*/">Long text 2</div>
        </div>
  
      </div>
  </div>
  <div id="container" style="position: relative; height: 100px; left: 50px; border: 1px solid red">
      <div id="child" style="position: absolute; display:flex; flex-direction: column; right: 0px; border: 1px solid blue">
        <div style="
display:flex;white-space:nowrap">
          <div style="flex: 1 0 auto">Long text 1</div>
          <div style="flex: 0 0 auto">Long text 2</div>
        </div>
  
      </div>
  </div>

Since you are using flexbox you can adjust the alignment to control the overflow of the text and make it on the left:

#container {
  animation:change 5s linear infinite alternate;
}

@keyframes change {
  from {
    width:300px;
  }
  to {
    width:50px;
  }
}
  <div id="container" style="position: relative; height: 100px; left: 50px; border: 1px solid red">
      <div id="child" style="position: absolute; display:flex; flex-direction: column; right: 0px; border: 1px solid blue">
        <div style="
display:flex;justify-content:flex-end;">
          <div style="flex: 1 0 auto">Long text 1</div>
          <div style="flex: 0 0 auto">Long text 2</div>
        </div>
  
      </div>
  </div>

how I can specify that child shouldn't compress below its intrinsic size?

The issue is that child (the absolute element) doesn't have any intrinsic size and its size is defined by the shrink-to-fit algorithm. You only way is to make sure the preferred minimum width is big enough to avoid any unwanted shrinking (like using white-space:nowrap)

Community
  • 1
  • 1
Temani Afif
  • 245,468
  • 26
  • 309
  • 415