speak
speak

Reputation: 5382

Nested absolute positioning breaks inline-block child elements

I am having difficulties sustaining my display: inline-block on li elements when they're deeply nested in numerous parent containers with varying position: absolute|relative, I am wondering if there is a set of rules that govern this?

In a sandboxed environment this works fine: JS Fiddle.

ul {
  margin: 0;
  padding: 0;
}
li {
  display: inline-block;
  color: white;
}
.body {
  position: absolute;
}
.one {
  position: absolute;
}
.two {
  position: absolute;
  display: inline-block;
  width: 100%;
  vertical-align: top;
}
.three {
  position: relative;
  display: inline-block;
  height: 100%;
}
.four {
  position: relative;
  z-index: 5;
}
.agent-dropdown {
  position: asbolute;
}
.box {
  background: grey;
  padding: 8px;
}
.box-container {
  border: 1px solid red;
}
<div class="agent-dropdown">
  <div class="box-container">
    <div class="box">
      <ul>
        <li>
          <a>
            <img src="https://i.sstatic.net/fhgTc.jpg" />
          </a>
        </li><li>
        <a>
          <img src="https://i.sstatic.net/fhgTc.jpg" />
        </a>
        </li><li>
        <a>
          <img src="https://i.sstatic.net/fhgTc.jpg" />
        </a>
        </li>
      </ul>
    </div>
  </div>
</div>

But when nested to the level that it is on the live website, the li elements lose their formation, it seems to break after the 3rd position: absolute. JS Fiddle (Broken)

ul {
  margin: 0;
  padding: 0;
}
li {
  display: inline-block;
  color: white;
}
.body {
  position: absolute;
}
.one {
  position: absolute;
}
.two {
  position: absolute;
  display: inline-block;
  width: 100%;
  vertical-align: top;
}
.three {
  position: relative;
  display: inline-block;
  height: 100%;
}
.four {
  position: relative;
  z-index: 5;
}
.agent-dropdown {
  position: asbolute;
}
.box {
  background: grey;
  padding: 8px;
}
.box-container {
  border: 1px solid red;
}
<div class="body">
  <div class="one">
    <div class="two">
      <div class="three">
        <div class="four">
          <div class="agent-dropdown">
            <div class="box-container">
              <div class="box">
                <ul>
                  <li>
                    <a>
                      <img src="https://i.sstatic.net/fhgTc.jpg" />
                    </a>
                  </li><li>
                  <a>
                    <img src="https://i.sstatic.net/fhgTc.jpg" />
                  </a>
                  </li><li>
                  <a>
                    <img src="https://i.sstatic.net/fhgTc.jpg" />
                  </a>
                  </li>
                </ul>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

I am unable to use fixed widths or heights anywhere.

Upvotes: 1

Views: 1277

Answers (1)

Oriol
Oriol

Reputation: 288120

In your absolutely positioned elements, all left, margin-left, width, margin-right and right are set to auto.

Therefore, according to 10.3.7 Absolutely positioned, non-replaced elements,

the width is shrink-to-fit

The algorithm to calculate the shrink-to-fit width is

min(max(preferred minimum width, available width), preferred width).

Therefore,

  • .body is absolutely positioned and its content is out of flow. So the preferred width is 0. So the shrink-to-fit width is 0.

  • The same applies to .one.

  • .two is also absolutely positioned, but its content is not out of flow. The shrink to fit width is the minimal width needed when placing the images in different lines, because

    • The preferred minimum width is the minimal width needed when placing the images in different lines.
    • The preferred width is the width needed when placing the images in the same line.
    • The available width is 0.

    0 = available width < preferred minimum width < preferred width
    

If you don't want that behavior, you can

  • Increase the available width, so that

    preferred minimum width < preferred width < available width
    

    For example,

    .body, .one {
      left: 0;
      right: 0;
    }
    

    ul {
      margin: 0;
      padding: 0;
    }
    li {
      display: inline-block;
      color: white;
    }
    .body, .one {
      position: absolute;
      left: 0;
      right: 0;
    }
    .two {
      position: absolute;
      display: inline-block;
      width: 100%;
      vertical-align: top;
    }
    .three {
      position: relative;
      display: inline-block;
      height: 100%;
    }
    .four {
      position: relative;
      z-index: 5;
    }
    .agent-dropdown {
      position: asbolute;
    }
    .box {
      background: grey;
      padding: 8px;
    }
    .box-container {
      border: 1px solid red;
    }
    <div class="body">
      <div class="one">
        <div class="two">
          <div class="three">
            <div class="four">
              <div class="agent-dropdown">
                <div class="box-container">
                  <div class="box">
                    <ul>
                      <li>
                        <a>
                          <img src="https://i.sstatic.net/fhgTc.jpg" />
                        </a>
                      </li><li>
                      <a>
                        <img src="https://i.sstatic.net/fhgTc.jpgt" />
                      </a>
                      </li><li>
                      <a>
                        <img src="https://i.sstatic.net/fhgTc.jpg" />
                      </a>
                      </li>
                    </ul>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    • Increase the preferred minimum width, so that

    preferred minimum width = preferred width
    

    This can be achieved preventing line breaks:

    .two {
      white-space: nowrap;
    }
    

    ul {
      margin: 0;
      padding: 0;
    }
    li {
      display: inline-block;
      color: white;
    }
    .body, .one {
      position: absolute;
    }
    .two {
      position: absolute;
      display: inline-block;
      width: 100%;
      vertical-align: top;
      white-space: nowrap;
    }
    .three {
      position: relative;
      display: inline-block;
      height: 100%;
    }
    .four {
      position: relative;
      z-index: 5;
    }
    .agent-dropdown {
      position: asbolute;
    }
    .box {
      background: grey;
      padding: 8px;
    }
    .box-container {
      border: 1px solid red;
    }
    <div class="body">
      <div class="one">
        <div class="two">
          <div class="three">
            <div class="four">
              <div class="agent-dropdown">
                <div class="box-container">
                  <div class="box">
                    <ul>
                      <li>
                        <a>
                          <img src="https://i.sstatic.net/fhgTc.jpg" />
                        </a>
                      </li><li>
                      <a>
                        <img src="https://i.sstatic.net/fhgTc.jpgt" />
                      </a>
                      </li><li>
                      <a>
                        <img src="https://i.sstatic.net/fhgTc.jpg" />
                      </a>
                      </li>
                    </ul>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

Upvotes: 2

Related Questions