垂直 flexbox 溢出的水平全宽

Horizontal full width with overflow in vertical flexbox

我正在尝试创建一个 flexbox,它既可以水平滚动,也可以垂直滚动,以备不时之需。 这有点像 flexbox 中的 table 布局。 在下图中,您可以看到我正在努力实现的概念。当视口不是太小或太短时,这可以正常工作。

然后我们可以调整视口的大小。这适用于垂直溢出。出现一个滚动条,我们可以向下滚动。 遗憾的是,这在水平方向上无法正常工作。 我们还获得了水平部分的滚动条。但是黄色行(带测试)不是我需要的全宽。

const groups = [];
for (let i = 0; i < 15; i++) {
  const rows = [];
  for (let j = 0; j < 15; j++) {
    rows.push({
      cols: [
        "col 1",
        "col 2",
        "col 3",
        "col 4",
        "col 5",
        "col 6",
        "col 7",
        "col 8",
        "col 9",
      ]
    });
  }

  groups.push({
    group: 'test' + i,
    open: false,
    rows
  });
}

var app = new Vue({
  el: '#app',
  data: {
    rows: groups
  }
})
.container {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-width: 100vh;
}

.header {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: row;
}

.header .col {
  flex-basis: 100px;
  flex-grow: 1;
  flex-shrink: 0;
  background: red;
  padding: 0 2px;
  border: 2px solid black;
}

.vertical-content {
  display: flex;
  flex-direction: column;
}

.vertical-content .grouped-row {
  flex-grow: 1;
  background: yellow;
  border: 2px solid black;
  display: flex;
  flex-direction: column;
}

.vertical-content .row {
  display: flex;
  flex-direction: row;
}

.vertical-content .row .col {
  flex-basis: 100px;
  flex-grow: 1;
  flex-shrink: 0;
  background: blue;
  padding: 0 2px;
  border: 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.js"></script>

<body>
  <div class="container" id="app">
    <div class="header">
      <div class="col">Col 1</div>
      <div class="col">Col 2</div>
      <div class="col">Col 3</div>
      <div class="col">Col 4</div>
      <div class="col">Col 5</div>
      <div class="col">Col 6</div>
      <div class="col">Col 7</div>
      <div class="col">Col 8</div>
      <div class="col">Col 9</div>
    </div>
    <div class="vertical-content">
      <div class="grouped-row" v-for="row of rows" @click="row.open = !row.open">
        <div>
          {{ row.group }}
        </div>
        <div class="row" v-for="actualRow of row.rows" v-if="row.open">
          <div class="col" v-for="col of actualRow.cols">{{ col }}</div>
        </div>
      </div>
    </div>
  </div>
</body>

在 fiddle 中单击黄色条以展开包含更多内容的行。

如何使黄色条成为全角而不是部分宽度?

每个红色和蓝色单元格都有最小宽度(flex-basisflex-shrink: 0)但黄色没有。

黄色的正在使用可能的最大宽度,但其他人正在走出他们的容器。

在这种情况下,“修复”它的最简单方法是也为黄色条设置最小宽度。

一个小例子(带有变量以简化可维护性)

差异:

:root {
  --nb-cells: 9;
  --cell-width: 100px;
}

.container {
  box-sizing: border-box;
}

.header .col,
.vertical-content .row .col {
  box-sizing: border-box;
  flex-basis: var(--cell-width);
}

.vertical-content .grouped-row {
  box-sizing: border-box;
  min-width: calc(var(--cell-width) * var(--nb-cells));
}

全面测试

const groups = [];
for (let i = 0; i < 15; i++) {
  const rows = [];
  for (let j = 0; j < 15; j++) {
    rows.push({
      cols: [
        "col 1",
        "col 2",
        "col 3",
        "col 4",
        "col 5",
        "col 6",
        "col 7",
        "col 8",
        "col 9",
      ]
    });
  }

  groups.push({
    group: 'test' + i,
    open: false,
    rows
  });
}

var app = new Vue({
  el: '#app',
  data: {
    rows: groups
  }
})
:root {
  --nb-cells: 9;
  --cell-width: 100px;
}

.container {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-width: 100vh;
  box-sizing: border-box;
}

.header {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: row;
}

.header .col {
  flex-basis: var(--cell-width);
  flex-grow: 1;
  flex-shrink: 0;
  background: red;
  padding: 0 2px;
  border: 2px solid black;
  box-sizing: border-box;
}

.vertical-content {
  display: flex;
  flex-direction: column;
}

.vertical-content .grouped-row {
  flex-grow: 1;
  background: yellow;
  border: 2px solid black;
  display: flex;
  flex-direction: column;
  min-width: calc(var(--cell-width) * var(--nb-cells));
  box-sizing: border-box;
}

.vertical-content .row {
  display: flex;
  flex-direction: row;
}

.vertical-content .row .col {
  flex-basis: var(--cell-width);
  flex-grow: 1;
  flex-shrink: 0;
  background: blue;
  padding: 0 2px;
  border: 2px solid black;
  box-sizing: border-box;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.js"></script>

<body>
  <div class="container" id="app">
    <div class="header">
      <div class="col">Col 1</div>
      <div class="col">Col 2</div>
      <div class="col">Col 3</div>
      <div class="col">Col 4</div>
      <div class="col">Col 5</div>
      <div class="col">Col 6</div>
      <div class="col">Col 7</div>
      <div class="col">Col 8</div>
      <div class="col">Col 9</div>
    </div>
    <div class="vertical-content">
      <div class="grouped-row" v-for="row of rows" @click="row.open = !row.open">
        <div>
          {{ row.group }}
        </div>
        <div class="row" v-for="actualRow of row.rows" v-if="row.open">
          <div class="col" v-for="col of actualRow.cols">{{ col }}</div>
        </div>
      </div>
    </div>
  </div>
</body>

几个问题:

  • 您需要为 min-width 使用 view-width(vw)。将 min-width: 100vh; 更改为 min-width: 100vw;。仅此一项并不能解决问题。
  • 主要问题是因为 .header 溢出了。您可以通过向其添加粗边框和 .container 元素来检查这一点。我们可以使用两个更改来解决此问题:
    .container {
      ...
      width: max-content;
    }

    .header .col {
      ...
      width: 100px;
    }

演示:

const groups = [];

for (let i = 0; i < 15; i++) {
  const rows = [];
  for (let j = 0; j < 15; j++) {
    rows.push({ cols: ["col 1", "col 2", "col 3", "col 4", "col 5", "col 6", "col 7", "col 8", "col 9" ] });
  }

  groups.push({ group: 'test' + i, open: false, rows});
}

var app = new Vue({el: '#app', data: { rows: groups } })
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.container {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-width: 100vw;
  
  width: max-content;
}

.header {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: row;
}

.header .col {
  flex-basis: 100px;
  flex-grow: 1;
  flex-shrink: 0;
  background: rgb(250, 189, 189);
  padding: 0 2px;
  outline: 2px solid black;
  
  width: 100px;
}

.vertical-content {
  display: flex;
  flex-direction: column;
}

.vertical-content .grouped-row {
  flex-grow: 1;
  background: rgb(251, 251, 180);
  outline: 2px solid black;
  display: flex;
  flex-direction: column;
}

.vertical-content .row {
  display: flex;
  flex-direction: row;
  width: 100%;
}

.vertical-content .row .col {
  flex-basis: 100px;
  flex-grow: 1;
  flex-shrink: 0;
  background: rgb(150, 150, 238);
  padding: 0 2px;
  outline: 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.1/vue.js"></script>

<body>
  <div class="container" id="app">
    <div class="header">
      <div class="col">Col 1</div>
      <div class="col">Col 2</div>
      <div class="col">Col 3</div>
      <div class="col">Col 4</div>
      <div class="col">Col 5</div>
      <div class="col">Col 6</div>
      <div class="col">Col 7</div>
      <div class="col">Col 8</div>
      <div class="col">Col 9</div>
    </div>
    <div class="vertical-content">
      <div class="grouped-row" v-for="row of rows" @click="row.open = !row.open">
        <div>
          {{ row.group }}
        </div>
        <div class="row" v-for="actualRow of row.rows" v-if="row.open">
          <div class="col" v-for="col of actualRow.cols">{{ col }}</div>
        </div>
      </div>
    </div>
  </div>