【问题标题】:How to make overflown flexbox element to have width of its children?如何使溢出的 flexbox 元素具有其子元素的宽度?
【发布时间】:2016-03-07 03:21:02
【问题描述】:

我一直在尝试使用 Flexbox 滚动创建类似表格的网格。

大部分都可以,但是有没有办法在水平滚动开启时强制行具有其内容的宽度?

如您所见,每个偶数行都有白色背景,因此很容易发现宽度存在问题。

http://jsbin.com/fedisozafe/embed?html,css,output

$('.tbody').on('scroll', function(e) {
    $(this).siblings().scrollLeft($(this).scrollLeft());
});

$('.tbody').perfectScrollbar();

$(window).on('resize', function(e) {
    $('.tbody')
      .perfectScrollbar('update')
      .siblings()
        .scrollLeft($(this).scrollLeft());
});


angular.module('app', [])
    .controller('testController', [
        '$scope',
        function($scope) {
            this.n = 5;
            $scope.$watch(() => this.n, () => this.collection = _.range(this.n));
        }
    ]);
* {
    box-sizing: border-box;
    border-collapse: collapse;
}
.table {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    border: solid 1px red;
}
.table > * {
    border-top: solid 1px transparent;
    border-bottom: solid 1px transparent;
}
.thead {
    border-bottom: solid 1px red;
}
.tfoot {
    border-top: solid 1px red;
}
.thead {
    flex: none;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    order: -1;
    background-color: lightgoldenrodyellow;
}
.tbody {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    justify-content: space-between;
    background-color: lightgray;
}
.tfoot {
    flex: none;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    order: 1;
    background-color: lightblue;
}
.tr {
    display: flex;
    flex: 1 0 20px;
    justify-content: space-between;
    align-items: center;
}
.tr:nth-child(2n) {
    background-color: white;
}
.td,
.th {
    flex: 1 0 60px;
    display: inline-flex;
}
.th {
    font-weight: bold;
}
<!doctype html>
<html ng-app="app">
    <head>
        <meta charset="utf-8">
        <title></title>
        <meta name="viewport" content="width=device-width">

		<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
		<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
		<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.5.1/lodash.min.js"></script>
		<script src="//cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/0.6.10/js/min/perfect-scrollbar.jquery.min.js"></script>

		<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/0.6.10/css/perfect-scrollbar.min.css"/>
	</head>
	<body ng-controller="testController as ctrl">
	<input type="number" ng-model="ctrl.n" ng-max="100" />
	<div style="display: flex">
		<div style="flex: 1 1 auto">
			<table class="table" style="width: 40vw; height: 40vh">
				<tbody class="tbody" style="height: calc(100% - 60px)">
					<tr class="tr" ng-repeat="item in ctrl.collection" style="min-width: 200px">
						<th class="th">{{item}}</th>
						<th class="td" style="flex-basis: 200px">{{item}}</th>
						<th class="td">{{item}}</th>
						<th class="td">{{item}}</th>
						<th class="td">{{item}}</th>
					</tr>
				</tbody>
				<thead class="thead">
					<tr class="tr">
						<td class="th">A</td>
						<td class="th" style="flex-basis: 200px">B</td>
						<td class="th">C</td>
						<td class="th">D</td>
						<td class="th">E</td>
					</tr>
				</thead>
				<tfoot class="tfoot">
					<tr class="tr">
						<th class="th">A</th>
						<th class="th" style="flex-basis: 200px">B</th>
						<th class="th">C</th>
						<th class="th">D</th>
						<th class="th">E</th>
					</tr>
				</tfoot>
			</table>
		</div>
		<div style="flex: 1 1 auto">
			<div class="table" style="width: 40vw; height: 40vh">
				<div class="tbody" style="height: calc(100% - 60px)">
				<div class="tr" ng-repeat="item in ctrl.collection">
					<div class="th">{{item}}</div>
					<div class="td" style="flex-basis: 200px">{{item}}</div>
					<div class="td">{{item}}</div>
					<div class="td">{{item}}</div>
					<div class="td">{{item}}</div>
				</div>
				</div>
				<div class="thead">
				<div class="tr">
					<div class="th">A</div>
					<div class="th" style="flex-basis: 200px">B</div>
					<div class="th">C</div>
					<div class="th">D</div>
					<div class="th">E</div>
				</div>
				</div>
				<div class="tfoot">
				<div class="tr">
					<div class="th">A</div>
					<div class="th" style="flex-basis: 200px">B</div>
					<div class="th">C</div>
					<div class="th">D</div>
					<div class="th">E</div>
				</div>
				</div>
			</div>
		</div>
	</div>

	</body>
</html>

有什么想法吗?


编辑 1

重要的是,行根据其单元格计算其宽度,而不是相反。在理想的世界中,行会在空间可用时增长(并允许单元格也增长),但不会缩小 - 这就是启用滚动的原因。

我知道有可能无法完成。我已经花了很长时间,但我仍然坚持希望我没有你们那么聪明。

【问题讨论】:

  • 所以你想让每一行符合它的孩子的总宽度?还是您希望每个“单元格”都符合列中最宽的内容?你有一个真实的表,你有一个伪 div 表。那是为了实验?
  • 第一个。我认为,如果没有 javascript 或没有列优先方法,后者是不可能的。或者是吗? :-)
  • 如果没有 JS,第一种方法确实令人望而生畏,谢天谢地,您有能力要求前者:P IE 是必需的吗,先生?
  • 不,仅限浏览器 :-)
  • 哈!你在我的书中没事@m1gu3l ????

标签: html css flexbox


【解决方案1】:

没有任何错误,HTML、CSS 和 JS(我假设 Angular 和 loDash 都不错)都很好。所以 OP 只需要一种 shrink wrap 行的方法。行在奇怪的溢出中延伸? CSS 有一些变化,但更多是为了美观和小调整。主要风格变化如下:

    .tr {
      display: flex;
      min-width: -moz-fit-content;
      min-width: -webkit-fit-content;
      min-width: fit-content;
      flex: 1 0 20px;
      justify-content: flex-end;
    } 

fit-content 是一个古老但鲜为人知的属性,仍处于实验阶段。它的基本作用是让一个元素完美地包装它的内容。因此,如果将其应用于父元素,则父元素将与其内容一样宽,并且会随着内容的增加和减少而增加和减少。

- Result: The overflow was gone but `tr` did not extend.

删除了flex-direction: column,因此它默认为flex-direction: row 我认为tr 在垂直方向上流动可能会突然停止。

- Result: The `tr` extended, but the `td`s and `th`s were not aligned.

justify-content: flex-end 应用以​​便将列向右移动,回忆问题出在表格的右侧。

- Result: http://jsbin.com/godoqi/3/edit?css,output

table-layout: fixed 也应用于表格,因此可以更好地控制列宽。

- Result: See previous result.

jsBin

片段

$('.tbody').on('scroll', function(e) {
  $(this).siblings().scrollLeft($(this).scrollLeft());
});

$('.tbody').perfectScrollbar();

$(window).on('resize', function(e) {
  $('.tbody')
    .perfectScrollbar('update')
    .siblings()
    .scrollLeft($(this).scrollLeft());
});


angular.module('app', [])
  .controller('testController', [
    '$scope',
    function($scope) {
      this.n = 5;
      $scope.$watch(() => this.n, () => this.collection = _.range(this.n));
    }
  ]);
* {
  box-sizing: border-box;
}
.table {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  border: solid 1px red;
  border-collapse: collapse;
  table-layout: fixed;
}
.table > * {
  border-top: solid 1px transparent;
  border-bottom: solid 1px transparent;
}
.thead {
  border-bottom: solid 1px red;
}
.tfoot {
  border-top: solid 1px red;
}
.thead {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  order: -1;
  background-color: lightgoldenrodyellow;
}
.tbody {
  position: relative;
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-content: space-between;
  background-color: lightgray;
}
.tfoot {
  flex: none;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  order: 1;
  background-color: lightblue;
  text-align: center;
}
.tr {
  display: flex;
  min-width: -moz-fit-content;
  min-width: -webkit-fit-content;
  min-width: fit-content;
  flex: 1 0 20px;
  justify-content: flex-end;
}
.tr:nth-child(2n) {
  background-color: white;
}
.td,
.th {
  flex: 0 1 60px;
  text-align: center;
}
.th {
  font-weight: bold;
}
.ng-not-empty {
  text-align: center;
  width: 8ex;
}
<!doctype html>
<html ng-app="app">

<head>
  <meta charset="utf-8">
  <title></title>
  <meta name="viewport" content="width=device-width">

  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.1/jquery.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/4.5.1/lodash.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/0.6.10/js/min/perfect-scrollbar.jquery.min.js"></script>

  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.perfect-scrollbar/0.6.10/css/perfect-scrollbar.min.css" />
</head>

<body ng-controller="testController as ctrl">
  <input type="number" ng-model="ctrl.n" ng-max="100" />
  <div style="display: flex">
    <div style="flex: 1 1 auto">
      <table class="table" style="width: 40vw; height: 40vh">
        <tbody class="tbody" style="height: calc(100% - 60px)">
          <tr class="tr" ng-repeat="item in ctrl.collection" style="min-width: 200px">
            <th class="th">{{item}}</th>
            <th class="td" style="flex-basis: 200px">{{item}}</th>
            <th class="td">{{item}}</th>
            <th class="td">{{item}}</th>
            <th class="td">{{item}}</th>
          </tr>
        </tbody>
        <thead class="thead">
          <tr class="tr">
            <td class="th">A</td>
            <td class="th" style="flex-basis: 200px">B</td>
            <td class="th">C</td>
            <td class="th">D</td>
            <td class="th">E</td>
          </tr>
        </thead>
        <tfoot class="tfoot">
          <tr class="tr">
            <th class="th">A</th>
            <th class="th" style="flex-basis: 200px">B</th>
            <th class="th">C</th>
            <th class="th">D</th>
            <th class="th">E</th>
          </tr>
        </tfoot>
      </table>
    </div>
    <div style="flex: 1 1 auto">
      <div class="table" style="width: 40vw; height: 40vh">
        <div class="tbody" style="height: calc(100% - 60px)">
          <div class="tr" ng-repeat="item in ctrl.collection">
            <div class="th">{{item}}</div>
            <div class="td" style="flex-basis: 200px">{{item}}</div>
            <div class="td">{{item}}</div>
            <div class="td">{{item}}</div>
            <div class="td">{{item}}</div>
          </div>
        </div>
        <div class="thead">
          <div class="tr">
            <div class="th">A</div>
            <div class="th" style="flex-basis: 200px">B</div>
            <div class="th">C</div>
            <div class="th">D</div>
            <div class="th">E</div>
          </div>
        </div>
        <div class="tfoot">
          <div class="tr">
            <div class="th">A</div>
            <div class="th" style="flex-basis: 200px">B</div>
            <div class="th">C</div>
            <div class="th">D</div>
            <div class="th">E</div>
          </div>
        </div>
      </div>
    </div>
  </div>

</body>

</html>

【讨论】:

  • +1 用于探索 fit-content。这是一个答案,但这不是我正在寻找的答案,原因如下:1)缩小行在小屏幕上或当有很多列时不起作用 - 这就是为什么需要溢出和滚动 2)缩小行似乎也是导致列不对齐的原因 3) 右侧的表格看起来根本不起作用 无论如何谢谢!
  • 尝试将fit-content 更改为max-content 右侧的表格似乎对我来说是右侧的表格。您使用的是 Mac 还是 PC,您使用的是什么浏览器?你评论jsbin.com/godoqi/3/edit?css,output了吗?
  • 顺便说一句,不能指望右边的桌子模仿左边的桌子,除非你指定 display: table/table-cell/table-row 哪个 atm 是不可能的,因为每个 div 都有一个 display: flex 之间的行为总会有差异这 2 个表是因为 div 和表、tr 或 td 之间的差异。
  • 仍然没有雪茄。 Windows 上的 Chrome 49 和 Firefox 44,你呢?尝试将输出窗口的大小调整为 400 像素或更小 - 你有水平滚动条吗?
  • overflow: hidden添加到.tbody
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-16
  • 1970-01-01
  • 2017-10-04
  • 2020-01-31
  • 2013-05-13
  • 1970-01-01
  • 2017-07-03
相关资源
最近更新 更多