R·ex / Zeng


音游狗、安全狗、攻城狮、业余设计师、段子手、苦学日语的少年。

CSS 中关于 overflow 的限制和绕过方法

注意:本文发布于 2549 天前,文章中的一些内容可能已经过时。

在写毕设的时候遇到了一个看起来很难搞的问题。假设有如下 HTML 结构:

<div class="scrollable">
    <table>
        <thead>
            <!-- headers -->
        </thead>
        <tbody>
            <!-- contents -->
        </tbody>
        <tfoot>
            <tr>
                <!-- several `td`s -->
                <td>
                    <custom-select
                        :options="options">
                    </custom-select>
                </td>
            </tr>
        </tfoot>
    </table>
</div>

其中,.scrollable 的作用是当表格的一行过长时,可以让其横向滚动而不影响页面的其它部分;<custom-select> 元素是一个用 ul 模拟出来的 select 效果,被包在 <tfoot> 中当作添加的新项的选项。一个可能的效果如下:

0

注意表格是可以左右滑动的。

因为 <custom-select> 是被包在 .scrollable 里面的,所以需要写这样一个 CSS 来确保选择框多出来的地方能够显示出来:

.scrollable {
    overflow-x: auto;
    overflow-y: visible;
}

这时候问题出现了。渲染之后的 overflow-y 被强行设置成了 auto!W3C 的 这个页面 中是这么写的:

The computed values of ‘overflow-x’ and ‘overflow-y’ are the same as their specified values, except that some combinations with ‘visible’ are not possible: if one is specified as ‘visible’ and the other is ‘scroll’ or ‘auto’, then ‘visible’ is set to ‘auto’.

计算所得的 'overflow-x' 和 'overflow-y' 与 CSS 中定义的相同,除了带有 'visible' 的其中一种情况:如果其中有一个是 'visible',另一个是 'scroll' 或者 'auto',那么这个 'visible' 会被设置为 'auto'。

什么鬼?!

一番谷歌之后,发现了万能的 Stack Overflow 上面有一个 看似很靠谱的答案(具体代码请看 这里),大体思想是用两个标签来限制:先把要溢出的元素包在 B 中,再把 B 包在 A 中;B 设置 overflow-x: auto,高度必须大于算上溢出元素和滚动条之后的总高度;A 设置 overflow-y: visible,固定高度。

这思路似乎可行,于是我改了一下 HTML:

<div class="scrollable-hack-a">
    <div class="scrollable-hack-b">
        <table>
            <!-- original table -->
        </table>
    </div>
</div>

我的 <custom-select> 有一个 max-height: 400px,由于我项目中的滚动条不占用空间,所以可以忽略滚动条的高度。那么 B 的高度应该是 之前的高度 + 400px,可以利用 padding-bottom: 400px 来实现;A 的高度应该是 之前的高度 - 400px,可以利用 margin-bottom: -400px 来实现。

/* outer, set overflow-y, original height */
.scrollable-hack-a {
    overflow-y: visible;
    margin-bottom: -400px;
}
/* inner, set overflow-x, enough height */
.scrollable-hack-b {
    overflow-x: auto;
    padding-bottom: 400px;
}

当然,效果就是一开始的那张截图啦!

Disqus 加载中……如未能加载,请将 disqus.com 和 disquscdn.com 加入白名单。

这是我们共同度过的

第 3070 天