【问题标题】:Preventing a div from expanding the width of a parent table防止 div 扩展父表的宽度
【发布时间】:2016-06-28 03:12:16
【问题描述】:

我正在从事一个项目,我将在我无法控制的页面中注入标记(嵌入脚本)。一个有趣的案例出现了,我注入的 div 包含在一个表中。我的 div 的子元素是一个水平菜单,当它超过父元素的宽度时应该滚动 (overflow-x: auto),但是在父元素是表格的情况下没有 table-layout: fixed,我注入的内容反而导致父表扩展,严重破坏了一些布局。

在这种情况下,表格包含在一个固定宽度的 div 中,如下所示:

<div style="width: 600px;">
  <table width="100%">
    <tr>
      <td>
        <div> <!-- my content --> </div>
      </td>
    </tr>
  </table>
</div>

我发现在桌子上设置table-layout: fixed 可以解决这个问题。但是,这个标记超出了我的控制——我只能从最里面的 div 开始更改标记/CSS。

我确实找到了一个可行的技巧:在我的 div 上设置 width: 100%; display: table; table-layout: fixed;。但是,我不确定这是否符合任何相关规范,因为这个display: table div 的内容都是display: block

这里是重现问题的标记,以及演示黑客:

<div class="outer">
  <table class="bad-table">
    <tr>
      <td>
        <div class="wrapper">
          <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam imperdiet pharetra nunc at condimentum.</div>
          <div class="target">
            <ul class="menu">
              <li style="background-color: #800;"></li>
              <li style="background-color: #880;"></li>
              <li style="background-color: #080;"></li>
              <li style="background-color: #008;"></li>
            </ul>
          </div>
          <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam imperdiet pharetra nunc at condimentum.</div>
        </div>
      </td>
    </tr>
  </table>
</div>

<div class="outer">
  <table class="bad-table">
    <tr>
      <td>
        <div class="wrapper hack">
          <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam imperdiet pharetra nunc at condimentum.</div>
          <div class="target">
            <ul class="menu">
              <li style="background-color: #800;"></li>
              <li style="background-color: #880;"></li>
              <li style="background-color: #080;"></li>
              <li style="background-color: #008;"></li>
            </ul>
          </div>
          <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam imperdiet pharetra nunc at condimentum.</div>
        </div>
      </td>
    </tr>
  </table>
</div>

CSS:

.outer {
  width: 200px;
  border: 1px solid #0f0;
}

.bad-table {
  width: 100%;
  border: 1px solid #f00;
}

.target {
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
}

.wrapper {
  width: 100%;
}

.wrapper.hack {
  display: table;
  table-layout: fixed;
}

ul.menu {
  list-style: none;
  padding: 0;
  margin: 0;
  white-space: nowrap;
  width: 100%;
}

ul.menu li {
  display: inline-block;
  width: 100px;
  height: 50px;
  padding: 0;
  margin: 0;
}

(Fiddle)

请注意,在第一个示例中,菜单块导致表格(红色边框)扩展到其包含的 div(绿色边框)之外。与第二个示例相比,它使用了我的(违反标准的?)hack,成功阻止了父表的增长,同时还允许滚动菜单块。 (用 Chrome 和 Firefox 测试。)

注意以下限制:

  • 我绝对不能在我注入的 div 之外编辑标记。这包括在我注入的 div 之外操作 DOM,因为我不知道我对其他人文档的更改可能会造成什么不良影响。
  • 我注入的 div 的高度应基于其内容(根据正常的文档流),这意味着使用 position: absolute 的解决方案往往会出现问题,因为它们会将我的内容从页面流中删除,使前面和/或以下内容与注入的 div 重叠。通常的解决方法(设置固定高度)意味着我的元素将无法适应其高度以匹配其内容。

这种破解方法是解决这个问题的合法方法,还是有更好的方法?

【问题讨论】:

  • 外部 div 的宽度(本例中为 600px,演示中为 200px)是否已知?
  • @LGSon 不是。目标是让嵌入元素自动调整大小以填充其直接父元素的宽度,无论它可能是什么。

标签: html css


【解决方案1】:

table 总是很棘手,但我在很多情况下都成功使用了position: absolute,所以我的回答/问题是:这对你有用吗?

请注意,wrapper 只是一个包装器,应该只包含 target,因此所有内容都进入 target,否则 target 将与其兄弟姐妹重叠,除非固定边距/填充设置。

.outer {
  width: 200px;
}

.bad-table {
  width: 100%;
}

.wrapper {
  position: relative;
}
.target {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: auto;
  overflow: auto;
}

ul.menu {
  list-style: none;
  table-layout: fixed;
  padding: 0;
  margin: 0;
  white-space: nowrap;
  width: 100%;
}
ul.menu li {
  display: inline-block;
  width: 100px;
  height: 50px;
  padding: 0;
  margin: 0;
}
<div class="outer">
  <table class="bad-table">
    <tr>
      <td>
        <div class="wrapper">
          <div class="target">
          
          
            <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam imperdiet pharetra nunc at condimentum.</div>
            <ul class="menu">
              <li style="background-color: #800;"></li>
              <li style="background-color: #880;"></li>
              <li style="background-color: #080;"></li>
              <li style="background-color: #008;"></li>
            </ul>
            <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam imperdiet pharetra nunc at condimentum.</div>


          </div>
        </div>
      </td>
    </tr>
  </table>
</div>

为了比较,这里是使用display: table的相同代码sn-p

.outer {
  width: 200px;
}

.bad-table {
  width: 100%;
}

.wrapper {
  width: 100%;
  display: table;
  table-layout: fixed;
}
.target {
  overflow: auto;
}

ul.menu {
  list-style: none;
  table-layout: fixed;
  padding: 0;
  margin: 0;
  white-space: nowrap;
  width: 100%;
}
ul.menu li {
  display: inline-block;
  width: 100px;
  height: 50px;
  padding: 0;
  margin: 0;
}
<div class="outer">
  <table class="bad-table">
    <tr>
      <td>
        <div class="wrapper">
          <div class="target">
          
          
            <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam imperdiet pharetra nunc at condimentum.</div>
            <ul class="menu">
              <li style="background-color: #800;"></li>
              <li style="background-color: #880;"></li>
              <li style="background-color: #080;"></li>
              <li style="background-color: #008;"></li>
            </ul>
            <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam imperdiet pharetra nunc at condimentum.</div>


          </div>
        </div>
      </td>
    </tr>
  </table>
</div>

更新

经过更多测试并阅读这些内容,

我找不到任何其他方法来解决这种情况,所以如果在您的 content div 不受控制的 outer div/table 之前和之后会有内容的内容需要有正常的流程,position: absolute 可能无法正常工作,具体取决于页面其余内容的设置方式,但display: table; table-layout: fixed 可以。

根据上述消息来源,使用display: table1 不应该有任何合规性问题,尽管您需要在主要浏览器中测试行为,因为它们都可能处理 @ 987654341@'s inside td's 不同(我确实在 Windows 上测试了 Chrome、FF、Edge、IE11,一切正常)。


1 具体来说,此文本允许将display: block 元素直接放在display: table 元素内,因为中间表格行和表格单元框会自动创建为匿名:

  1. 生成缺少的子包装:
    1. 如果“table”或“inline-table”框的子 C 不是正确的 table child,则围绕 C 和 C 的所有不是正确 table child 的连续兄弟生成一个匿名的“table-row”框.
    2. 如果行组框的子 C 不是“表行”框,则围绕 C 和 C 的所有非“表行”框的连续兄弟生成一个匿名“表行”框。
    3. 如果“table-row”框的子 C 不是“table-cell”,则围绕 C 和 C 的所有非“table-cell”的连续兄弟生成一个匿名“table-cell”框盒子。

【讨论】:

  • 这不会从页面流中删除.target 元素,导致下面的内容显示在它上面吗? (Fiddle)position: absolute 将使前后内容很难在嵌入的 div 周围正确流动。
  • 在这种情况下,wrapper 只是一个包装器,应该只包含target,因此所有内容都进入targetupdated fiddle。现在,取决于页面布局的其余部分是如何设置的,这可能仍然无法正常工作,因此我也需要知道这一点。
  • 新小提琴的两个问题:(1) all 的内容是可滚动的,而只有菜单块应该是可滚动的,以及 (2) 因为 .target 已被删除从文档流来看,.outer.bad-table 现在没有高度。外部 div 前后都有内容。考虑this fiddle——确切的显示顺序应该是“在外部之前”-“在包装之前”-菜单块(可滚动)-“在包装之后”-“在外部之后”。
  • 我添加了 CSS2 规范中的相关文本,完美地回答了我的问题。 +1 并被接受。
  • @cdhowie 1:st 段落,w3.org/TR/CSS2/tables.html#anonymous-boxes,是的,那段,因为您没有将target 显式设置为display: block
【解决方案2】:

如果元素是表格单元格,则可以将元素缩放到其父元素的宽度,但您必须解决一些负面后果。考虑一下:

<style>
  table {
    border-collapse: collapse;
    width: 100%;
  }
  td {
    border: 1px solid gray;
    padding: 20px;
  }

  .prevent-table-expand-wrap {
    position: relative;
  }
  .prevent-table-expand-inner {
    /* Add ellipsis. */
    overflow-x: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;

    /* Make div the width of its parent. */
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
  }
</style>

<table>
  <tr><td>
    Column 1.
  </td><td>
    Column 2.
    <div class="prevent-table-expand-wrap">
      &nbsp;
      <div class="prevent-table-expand-inner" title="This contains way too much text, so prevent scaling table">
        Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text. Lots of text.
      </div>
    </div>
  </td><td>
    Column 3.
  </td></tr>
</table>

https://jsfiddle.net/zgwmLms1/19/

其工作方式是包装器 div 仅获得其容器(表格单元格)的 100% 宽度。它没有影响表格列缩放的内容(嗯,nbsp 太窄了)。然后内部 div 被绝对定位并约束到三个侧面的包装器。也可以做所有 4 个面,但在这种情况下不需要明确地同时做顶部和底部,因为包装器和内部的高度是相同的。

与其他答案的最大区别在于,我将确实影响列宽的内容和的内容结合在同一个表格单元格中。您可以看到所有 3 列的大小都是均匀的,这是由于 Column n 文本。

【讨论】:

    猜你喜欢
    • 2013-08-10
    • 1970-01-01
    • 1970-01-01
    • 2012-12-22
    • 2012-08-07
    • 2013-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多