Reputation: 484
I'm trying to create a flexbox that is both horizontally as vertically scrollable in case its needed. It's kind of a table layout in flexbox. In the picture below you can see the concept that I'm trying to achieve. This works correctly when the viewport is not too small or too short.
We can then resize the viewport. This works correctly for the vertical overflow. A scrollbar appears and we can scroll downwards. This sadly doesn't work correctly horizontally. We also get a scrollbar for the horizontal part. But the yellow rows (with test) are not the full width I need it to be.
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>
In the fiddle click the yellow bars to expand a row with more content.
How can I make the yellow bars the full-width instead of partially?
Upvotes: 9
Views: 1035
Reputation: 18398
Couple of issues:
vw
) for min-width
. Change min-width: 100vh;
to min-width: 100vw;
. This alone doesn't resolve the issue..header
is overflowing. You can check this by adding a fat border to it and .container
element. We can fix this using two changes: .container {
...
width: max-content;
}
.header .col {
...
width: 100px;
}
Demo:
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>
Upvotes: 1
Reputation: 1239
Every red and blue cells have a minimal width (with flex-basis
and flex-shrink: 0
) but not the yellow.
The yellow are using the largest width possible for them, but the others are going out their container.
In this situation, the simplest way to "fix" it is to set a minimal width to the yellow bars too.
A small example (with variables to simplify maintainability)
Diff:
: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));
}
Full test
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>
Upvotes: 2