I am working on a project where I will be injecting markup into pages I don't have control over (an embed script). An interesting case has come up where my injected div is contained within a table. A child of my div is a horizontal menu that should scroll (overflow-x: auto
) when it exceeds the width of the parent element, but in the case where a parent element is a table without table-layout: fixed
, my injected content instead causes the parent table to expand, horribly breaking some layouts.
In this case, the table is contained within a fixed-width div, something like this:
<div style="width: 600px;">
<table width="100%">
<tr>
<td>
<div> <!-- my content --> </div>
</td>
</tr>
</table>
</div>
I found that setting table-layout: fixed
on the table fixes this problem. However, this markup is beyond my control -- I can only change markup/CSS starting from the innermost div.
I did find one hack that works: setting width: 100%; display: table; table-layout: fixed;
on my div. However, I'm not sure if this is compliant with any relevant specs, as the contents of this display: table
div are all display: block
.
Here is markup that reproduces the problem, as well as demonstrates the hack:
<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)
Note that in the first example, the menu blocks cause the table (red border) to expand beyond its containing div (green border). Compare to the second example, which uses my (standards-violating?) hack that successfully prevents the parent table from growing, while also allowing the menu blocks to be scrolled. (Tested with Chrome and Firefox.)
Note the following constraints:
- I absolutely cannot edit the markup outside of my injected div. This includes manipulating the DOM outside of my injected div, because I don't know what bad effects my changes to someone else's document might cause.
- The height of my injected div should be based on its contents (as per normal document flow) which means that solutions using
position: absolute
will tend to be problematic as they will remove my content from the page flow, making preceding and/or following content overlap the injected div. The usual fix for this (setting a fixed height) means my element will be unable to fit its height to match its contents.
Is this hack a legitimate way to solve this problem, or is there a better approach?