在没有预定义高度的嵌套元素上溢出
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>
我正在构建一个网格组件,并试图让主体在内容超出外部元素的视口时触发滚动条。不幸的是,我只有在 .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>