防止div扩展父表

时间:2016-03-12 23:22:18

标签: html css

我正在开发一个项目,我将把标记注入我无法控制的页面(嵌入脚本)。一个有趣的案例出现了,我的注入div包含在一个表中。我的div的子节点是一个水平菜单,当它超出父元素的宽度时应该滚动(overflow-x: auto),但是如果父元素是表没有 {{ 1}},我注入的内容反而导致父表扩展,可怕地破坏了一些布局。

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

table-layout: fixed

我发现在表上设置<div style="width: 600px;"> <table width="100%"> <tr> <td> <div> <!-- my content --> </div> </td> </tr> </table> </div> 可以解决这个问题。但是,这个标记是我无法控制的 - 我只能从最里面的div开始更改标记/ CSS。

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

这是标记,可以重现问题,并演示黑客攻击:

display: block

CSS:

<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>

Fiddle

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

请注意以下约束:

  • 我绝对无法编辑注入div之外的标记。这包括在我注入的div之外操纵DOM,因为我不知道我对其他人的文档所做的更改会产生什么不良影响。
  • 我注入的div的高度应该基于其内容(按照正常的文档流程),这意味着使用.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; } 的解决方案往往会有问题,因为它们将从页面流中删除我的内容,和/或以下内容与注入的div重叠。通常的解决方法(设置固定高度)意味着我的元素将无法适应其高度以匹配其内容。

这种黑客攻击是解决这个问题的合法途径,还是有更好的方法?

2 个答案:

答案 0 :(得分:3)

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

的相同代码段

.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>

更新

经过一些更多的测试,并阅读这些,

我找不到任何其他方法来解决这种情况,所以如果你的内容div 不受控制的外部div / table 之前和之后会有内容的内容需要有正常的流量,position: absolute可能不起作用,具体取决于页面内容的其余部分是如何设置的,但display: table; table-layout: fixed会。{/ p>

根据以上消息来源,使用display: table 1 不应该存在任何合规性问题,但是您需要测试主要浏览器中的行为,因为它们都可以处理divtd的{​​{1}}不同(我在Windows上测试过Chrome,FF,Edge,IE11,都有效)。

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

  
      
  1. 生成丢失的子包装器:      
        
    1. 如果'table'或'inline-table'框的子C不是正确的表子项,则在C周围生成一个匿名的“table-row”框,并且C的所有连续兄弟都不是正确的表子项
    2.   
    3. 如果行组框的子C不是“表行”框,则在C周围生成一个匿名的“表行”框,并且所有C的连续兄弟都不是“表行”框。
    4.   
    5. 如果'table-row'框的子C不是'table-cell',则在C周围生成一个匿名的'table-cell'框,并且所有C的连续兄弟都不是'table-cell'框。
    6.   
  2.   

答案 1 :(得分:0)

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

<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%的宽度,即表格单元格。它没有影响表列缩放的内容(嗯,它太窄了)。然后内部div被绝对定位并限制在三面的包装上。不妨做所有4个边,但在这种情况下没有必要同时明确地做顶部和底部,因为包装和内部的高度是相同的。

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