在没有预定义高度的嵌套元素上溢出

Overflow on nested element without predefined height

我正在构建一个网格组件,并试图让主体在内容超出外部元素的视口时触发滚动条。不幸的是,我只有在 .body 元素上应用高度时才能使它正常工作。我想避免这种情况,因为它需要我在运行时通过脚本应用高度,并且必须跟踪影响其高度的元素的任何更改。

有什么我可以探索的,纯粹 CSS 明智地完成这件事吗?请注意,代码段中可见的滚动条是基于代码段内容溢出,而不是基于正文元素溢出。

.outer {
  overflow: hidden;
  height: 500px;
}

.grid {
  border: 1px solid black;
}

.headerwrap {
  overflow: hidden;
  border: 1px solid blue;
}

.bodywrap {
  overflow: hidden;
  border: 1px solid red;
}

.body {
  overflow: auto;
  border: 1px solid green;
  /*height:300px;*/
}
<div class="outer">
  <div class="grid">
    <div class="headerwrap">
      <div class="header">
        <table border="1" style="width:2000px;">
          <tr>
            <td>a</td>
            <td>b</td>
            <td>c</td>
            <td>d</td>
            <td>e</td>
            <td>f</td>
          </tr>
        </table>
      </div>
    </div>
    <div class="bodywrap">
      <div class="body">
        <table border="1" style="width:2000px;height:1000px">
          <tr>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
            <td>5</td>
            <td>6</td>
          </tr>
        </table>
      </div>
    </div>
  </div>
</div>

您可以在 outer 上添加 overflow: scroll; 以在内容超出 y-axis 的视口时允许滚动。当内容超出水平视口时,这也可以在 x-axis 上滚动。

使用 tables 时,我喜欢使用 body::-webkit-scrollbar 添加手动滚动条。请参阅 ~Snippet 2 进行演示。

.outer {
  overflow: scroll;
  height: 500px;
}

.grid {
  border: 1px solid black;
}

.headerwrap {
  overflow: hidden;
  border: 1px solid blue;
}

.bodywrap {
  overflow: hidden;
  border: 1px solid red;
}

.body {
  overflow: auto;
  border: 1px solid green;
  /*height:300px;*/
}
<div class="outer">
  <div class="grid">
    <div class="headerwrap">
      <div class="header">
        <table border="1" style="width:2000px;">
          <tr>
            <td>a</td>
            <td>b</td>
            <td>c</td>
            <td>d</td>
            <td>e</td>
            <td>f</td>
          </tr>
        </table>
      </div>
    </div>
    <div class="bodywrap">
      <div class="body">
        <table border="1" style="width:2000px;height:1000px">
          <tr>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
            <td>5</td>
            <td>6</td>
          </tr>
        </table>
      </div>
    </div>
  </div>
</div>

编辑 ~ 片段 2

.outer {
  overflow-y: scroll;
}

.grid {
  border: 1px solid black;
}

.headerwrap {
  overflow: hidden;
  border: 1px solid blue;
}

.bodywrap {
  overflow: hidden;
  border: 1px solid red;
}

.body {
  overflow-y: auto;
  border: 1px solid green;
  /*height:300px;*/
}

body::-webkit-scrollbar {
  width: 1em;
}
 
body::-webkit-scrollbar-track {
  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
}
 
body::-webkit-scrollbar-thumb {
  background-color: darkgray;
  border-radius: 10px;
  outline: 1px solid slategrey;
}
<div class="outer">
  <div class="grid">
    <div class="headerwrap">
      <div class="header">
        <table border="1" style="width:2000px;">
          <tr>
            <td>a</td>
            <td>b</td>
            <td>c</td>
            <td>d</td>
            <td>e</td>
            <td>f</td>
          </tr>
        </table>
      </div>
    </div>
    <div class="bodywrap">
      <div class="body">
        <table border="1" style="width:2000px;height:1000px">
          <tr>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
            <td>5</td>
            <td>6</td>
          </tr>
        </table>
      </div>
    </div>
  </div>
</div>

解决方案已解决;不得不使用 flex box 并且它变得有点受限,因为我必须设置固定的 header 高度。但这已经比必须将所有内容都编写在一起要好得多了。

function Throttle(ms, callback) {
    let lastCall = 0;
    return function () {
        let now = new Date().getTime(),
            diff = now - lastCall;
        if (diff >= ms) {
            lastCall = now;
            callback.apply(this, arguments);
        }
    };
}

function Grid(){
    this.head = document.querySelector('.head');
    this.body = document.querySelector('.body');
    this.frozenBody = document.querySelector('.bodywrap>.frozen');
    
    this.body.addEventListener('scroll', Throttle(5, this.Scroll.bind(this)));
}
Grid.prototype = {
    Scroll : function(){
        let scrollLeft = event.srcElement.scrollLeft;
        let scrollTop = event.srcElement.scrollTop;

        this.head.style.transform = `translateX(-${scrollLeft}px)`;
        this.frozenBody.style.transform = `translateY(-${scrollTop}px)`;
    }
}
new Grid();
html,margin{
    margin:0;
    border:0;
}
.outer{
    border:1px solid red;
    height:500px;
}
.grid{
    position:relative;
    height:100%;
    display:flex;
    flex-direction:column;  
}
.headwrap{
    display:flex;
    flex:0 0 75px;
    flex-direction:row;     
    margin-right:20px;
    overflow:hidden;
    background:blue;
}   
    .headwrap .frozen{
        flex:0 0 50px;
        overflow:hidden;
        background:lime;
        z-index:1;
        
    }
    .head{
        flex:1 1 auto;
        overflow:hidden;
        z-index:0;
    }
.bodywrap{
    display:flex;
    flex:1 1 auto;
    flex-direction:row;         
    overflow:auto;
    
}
    .bodywrap .frozen{
        flex:0 0 50px;
        overflow:hidden;
        margin-bottom:20px;
        background:lime;
        z-index:1;
    }
    .body{
        flex:1 1 auto;
        overflow:auto;
        background:silver;
        z-index:0;
    }
td{
    height:100px;
}
<div class="outer">
    <div class="grid">
        <div class="headwrap">
            <div class="frozen">
                <table border="1" style="height:75px">
                    <tr>
                        <td style="width:50">1</td>
                    </tr>
                </table>
            </div>
            <div class="head">
                <table border="1" style="width:2000px;height:75px">
                    <tr>
                        <td>2</td>
                        <td>3</td>
                        <td>4</td>
                        <td>5</td>
                        <td>6</td>                  
                    </tr>
                </table>
            </div>
        </div>
        <div class="bodywrap">
            <div class="frozen">
                <table border="1" style="width:50px;">
                    <tr>
                        <td>1</td>
                    </tr>
                    <tr>
                        <td>2</td>
                    </tr>
                    <tr>
                        <td>3</td>
                    </tr>
                    <tr>
                        <td>4</td>
                    </tr>
                    <tr>
                        <td>5</td>
                    </tr>
                    <tr>
                        <td>6</td>
                    </tr>
                </table>
            </div>
            <div class="body">
                <table border="1" style="width:2000px;">
                    <tr>
                        <td>1</td>
                    </tr>
                    <tr>
                        <td>2</td>
                    </tr>
                    <tr>
                        <td>3</td>
                    </tr>
                    <tr>
                        <td>4</td>
                    </tr>
                    <tr>
                        <td>5</td>
                    </tr>
                    <tr>
                        <td>6</td>
                    </tr>
                </table>
            </div>
        </div>
    </div>
</div>