flexbox width inside horizontally scrollable container - html

I am trying to create a layout for a virtual table.
A virtual table will be placed inside .table-body element.
Each table cell has the same flex layout styles as cells in .table-header so with the same parent element with they would look the same.
The problem is that the .table-cell elements do not stretch .table-header width, and .table-header element does not stretch the .table-container width.
I'm trying to get the .table-cell's to give the width for the .table-header and .table-container. And the .table-body would take up the remaining space in the .table-container
Here is Codesandbox to play with.
.table-wrapper {
width: 500px;
height: 300px;
overflow-x: scroll;
background: rgba(255, 255, 0, 0.2);
}
.table-container {
display: flex;
flex-flow: column nowrap;
width: 100%;
height: 100%;
/* If you uncomment next line, you see what I'm trying to achieve */
/* min-width: 1100px; */
background: rgba(0, 255, 0, 0.3);
}
.table-header {
display: flex;
flex-flow: row nowrap;
width: 100%;
flex: 0 0 auto;
background: rgba(255, 100, 0, 0.3);
}
.table-cell {
min-width: 100px;
display: flex;
flex: 1 1 auto;
height: 30px;
line-height: 30px;
border: 1px solid blue;
}
.table-body {
display: flex;
flex: 1 1 auto;
border: 1px solid red;
background: rgba(255, 0, 0, 0.3);
}
<div class="table-wrapper">
<div class="table-container">
<div class="table-header">
<div class="table-cell" style="flex: 0 0 180px;">header-cell 1</div>
<div class="table-cell">header-cell 2</div>
<div class="table-cell">header-cell 3</div>
<div class="table-cell">header-cell 4</div>
<div class="table-cell" style="flex: 0 0 200px;">header-cell 5</div>
<div class="table-cell">header-cell 6</div>
<div class="table-cell">header-cell 7</div>
</div>
<div class="table-body">virtual table here</div>
</div>
</div>

Consider the use of inline-flex instead of flex and define the width using width and not flex-basis
.table-wrapper {
width: 500px;
height: 300px;
overflow-x: scroll;
background: rgba(255, 255, 0, 0.2);
}
.table-container {
display: inline-flex; /* UPDATED */
flex-flow: column nowrap;
min-width: 100%; /* UPDATED */
height: 100%;
background: rgba(0, 255, 0, 0.3);
}
.table-header {
display: flex;
flex-flow: row nowrap;
width: 100%;
flex: 0 0 auto;
background: rgba(255, 100, 0, 0.3);
}
.table-cell {
min-width: 100px;
display: flex;
flex: 1 1 auto;
height: 30px;
line-height: 30px;
border: 1px solid blue;
}
.table-body {
display: flex;
flex: 1 1 auto;
border: 1px solid red;
background: rgba(255, 0, 0, 0.3);
}
<div class="table-wrapper">
<div class="table-container">
<div class="table-header">
<div class="table-cell" style="flex: 0 0 180px;width:180px;">header-cell 1</div>
<div class="table-cell">header-cell 2</div>
<div class="table-cell">header-cell 3</div>
<div class="table-cell">header-cell 4</div>
<div class="table-cell" style="flex: 0 0 200px;width:200px;">header-cell 5</div>
<div class="table-cell">header-cell 6</div>
<div class="table-cell">header-cell 7</div>
</div>
<div class="table-body">virtual table here</div>
</div>
</div>

Here's a workaround I found, use width: min-content; for both table-header and table-container.
This only work when you get rid of the inline style in the table-cell.
.table-wrapper {
width: 500px;
height: 300px;
overflow-x: scroll;
background: rgba(255, 255, 0, 0.2);
}
.table-container {
display: flex;
flex-flow: column nowrap;
width: min-content;
height: 100%;
/* If you uncomment next line, you see what I'm trying to achieve */
/* min-width: 1100px; */
background: rgba(0, 255, 0, 0.3);
}
.table-header {
display: flex;
flex-flow: row nowrap;
width: min-content;
flex: 0 0 auto;
background: rgba(255, 100, 0, 0.3);
}
.table-cell {
min-width: 100px;
display: flex;
flex: 1 1 auto;
height: 30px;
line-height: 30px;
border: 1px solid blue;
}
.table-body {
display: flex;
flex: 1 1 auto;
border: 1px solid red;
background: rgba(255, 0, 0, 0.3);
}
<div class="table-wrapper">
<div class="table-container">
<div class="table-header">
<div class="table-cell">header-cell 1</div>
<div class="table-cell">header-cell 2</div>
<div class="table-cell">header-cell 3</div>
<div class="table-cell">header-cell 4</div>
<div class="table-cell" >header-cell 5</div>
<div class="table-cell">header-cell 6</div>
<div class="table-cell">header-cell 7</div>
</div>
<div class="table-body">virtual table here</div>
</div>
</div>

Related

CSS Flexbox align

I am currently learning HTML, CSS, how am I going to output this?
HTML Code
<body>
<div class="container">
<div id=“one"> 1</div>
<div id=“two"> 2</div>
<div id="three">3</div>
<div id=“four"> 4</div>
<div id=“five"> 5</div>
</div>
</body>
CSS Code
.container {
width: 240px;
height: 200px;
border: 1px solid gray;
}
.container > div {
width: 80px;
height: 50px;
border: 1px solid red;
}
I knew that I have to use flexbox to do that, but I have no idea how to change it, below is my modification of the CSS, but the result is wrong.
.container {
width: 240px;
height: 200px;
border: 1px solid gray;
display: inline-flex;
flex-direction: column-reverse;
flex-wrap: wrap;
align-content: flex-start;
}
.container > div {
width: 80px;
height: 50px;
border: 1px solid red;
}
You need flex-wrap: wrap-reverse; align-content: flex-start;
.container {
width: 240px;
height: 200px;
border: 1px solid gray;
display: flex;
flex-wrap: wrap-reverse;
align-content: flex-start;
}
.container>div {
width: 80px;
height: 50px;
border: 1px solid red;
box-sizing: border-box; /* don't forget this */
}
<div class="container">
<div id="one"> 1</div>
<div id="two"> 2</div>
<div id="three">3</div>
<div id="four"> 4</div>
<div id="five"> 5</div>
</div>

CSS flexbox fully collapse all empty children

Given an html structure that follows the schema in this snippet, how can I fully collapse the empty "col" divs, leaving the content divs equally sized (two columns in this case)?
* {
box-sizing: border-box;
}
.container {
border: 1px dashed rgba(255, 0, 0, .5);
background-color: beige;
padding: 20px 10px;
width: 500px;
}
.row {
border: 1px dashed rgba(0, 0, 255, .5);
display: flex;
}
.col {
flex: 1 1 auto;
min-width: 0;
}
.content {
border: 1px dashed rgba(0, 0, 0, .25);
padding: 0 10px;
width: 100%;
}
<section class="container">
<div class="row">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
<div class="col">
<p class="content">Foo</p>
</div>
<div class="col"></div>
<div class="col">
<p class="content">Bar</p>
</div>
<div class="col"></div>
</div>
</section>
You can select the empty elements with the .col class by using the :empty pseudo class.
I've chosen to change the flex attribute on the, so they will shrink, but you can also set display: none, or force max-width: 0, etc...
* {
box-sizing: border-box;
}
.container {
border: 1px dashed rgba(255, 0, 0, .5);
background-color: beige;
padding: 20px 10px;
width: 500px;
}
.row {
border: 1px dashed rgba(0, 0, 255, .5);
display: flex;
}
.col {
flex: 1 1 auto;
min-width: 0;
}
.col:empty {
flex: 0 1 0;
}
.content {
border: 1px dashed rgba(0, 0, 0, .25);
padding: 0 10px;
width: 100%;
}
<section class="container">
<div class="row">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
<div class="col">
<p class="content">Foo</p>
</div>
<div class="col"></div>
<div class="col">
<p class="content">Bar</p>
</div>
<div class="col"></div>
</div>
</section>
I was able to resolve the issue by setting the content to a nuclear width of 100vw with a max-width of 100%. The caveat is that this is not compatible with any version of IE.
* {
box-sizing: border-box;
}
.container {
border: 1px dashed rgba(255, 0, 0, .5);
background-color: beige;
padding: 20px 10px;
width: 500px;
}
.row {
border: 1px dashed rgba(0, 0, 255, .5);
display: flex;
}
.col {
flex: 1 1 auto;
min-width: 0;
}
.content {
border: 1px dashed rgba(0, 0, 0, .25);
padding: 0 10px;
width: 100vw;
max-width: 100%;
}
<section class="container">
<div class="row">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
<div class="col">
<p class="content">Foo</p>
</div>
<div class="col"></div>
<div class="col">
<p class="content">Bar</p>
</div>
<div class="col"></div>
</div>
</section>
Another solution is to use good-old table display props if IE support is needed.
* {
box-sizing: border-box;
}
.container {
border: 1px dashed rgba(255, 0, 0, .5);
background-color: beige;
padding: 20px 10px;
width: 500px;
display: table;
}
.row {
border: 1px dashed rgba(0, 0, 255, .5);
display: table-row;
}
.col {
display: table-cell;
min-width: 0;
}
.content {
border: 1px dashed rgba(0, 0, 0, .25);
padding: 0 10px;
width: 100%;
}
<section class="container">
<div class="row">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
<div class="col">
<div class="content">Foo</div>
</div>
<div class="col"></div>
<div class="col">
<div class="content">Bar</div>
</div>
<div class="col"></div>
</div>
</section>

How to display 2 columns per row using flexbox

I'm trying to display 2 columns every row but I can't seem to get it right at the moment.
What i'm trying to replicate is this:
but i'm not sure on how to handle this with using flexbox
.flex {
display: flex;
flex-direction: row;
flex-basis: 100%;
flex: 1;
}
.box {
padding: 20px;
border: 1px solid black;
width: 100px;
height: 100px;
margin: 10px;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
<div class="flex">
<div class="box green">positive 1</div>
<div class="box yellow">positive 2</div>
<div class="box blue">positive 3</div>
<div class="box red">negative 1</div>
</div>
https://jsfiddle.net/1a9qLx5w/
The best way to achieve this layout would be with Grid CSS:
.flex {
display: grid;
grid-auto-flow: column;
grid-gap: 20px;
grid-template-rows: 100px 100px;
grid-template-columns: 100px 100px;
padding: 10px;
}
.box {
padding: 20px;
border: 1px solid black;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
* {
box-sizing: border-box;
}
<div class="flex">
<div class="box green">positive 1</div>
<div class="box yellow">positive 2</div>
<div class="box blue">positive 3</div>
<div class="box red">negative 1</div>
</div>
But since you're asking for a flexbox solution, here you go:
.flex {
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 240px;
align-content: flex-start;
}
.box {
flex: 0 0 100px;
width: 100px;
padding: 20px;
border: 1px solid black;
margin: 10px;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
* {
box-sizing: border-box;
}
<div class="flex">
<div class="box green">positive 1</div>
<div class="box yellow">positive 2</div>
<div class="box blue">positive 3</div>
<div class="box red">negative 1</div>
</div>
Working demo :
.flex {
display: flex;
flex-direction: row;
flex-basis: 100%;
flex: 1;
}
.box {
padding: 20px;
border: 1px solid black;
width: 100px;
height: 100px;
margin: 10px;
}
.red {
background-color: red;
}
.yellow {
background-color: yellow;
}
.blue {
background-color: blue;
}
.green {
background-color: green;
}
.row {
display: flex;
flex-direction: row;
}
<div class="row">
<div class="box green">positive 1</div>
<div class="box yellow">positive 2</div>
</div>
<div class="row">
<div class="box blue">positive 3</div>
<div class="box red">negative 1</div>
</div>
I just copied your example:
.row{
display: flex;
flex-direction: row;
justify-content: center;
}
.green{
padding: 15px;
border: solid 1px green;
}
.red{
padding: 15px;
border: solid 1px red;
}
.col{
margin-right: 15px;
}
<div class="row">
<div class="col">
<p class="green">Positive 1</p>
<p class="green">Positive 2</p>
</div>
<div class="col">
<p class="red">No Thanks</p>
</div>
</div>

How to make CSS grid that stretches children and respects min-height: 0 on them?

I have simple css grid. I'd like it to stretch children to fill available content but also respect it if any of the children has height: 0. Right now it also "reserves" space for the child with height: 0.
Here's the fiddle showing my problem:
https://jsfiddle.net/f3r0b5e9/7/
.wrapper {
height: 300px;
width: 200px;
border: 1px solid red;
display: grid;
align-content: stretch;
grid-template-rows: auto;
}
.child {
width: 100%;
border: 1px solid blue;
background: #cad5e8;
}
.child.one {
height: 0;
min-height: 0;
max-height: 0;
}
<div class="wrapper">
<div class="child one">
</div>
<div class="child two">
</div>
<div class="child three">
</div>
</div>
Here's what I'm trying to accomplish:
http://prntscr.com/kqcry4
Note: I know how to do this with flexbox:)
Thanks!
Instead of auto, use min-content or max-content for the grid-template-rows's value:
.wrapper {
height: 300px;
width: 200px;
border: 1px solid red;
display: grid;
align-content: stretch;
grid-template-rows: min-content;
}
.child {
width: 100%;
border: 1px solid blue;
background: #cad5e8;
}
.child.one {
height: 0;
min-height: 0;
max-height: 0;
}
<div class="wrapper">
<div class="child one">
</div>
<div class="child two">
</div>
<div class="child three">
</div>
</div>

Flexbox Shrink Images within Div for Column Stacked images

I would like to have one image on the left and two on the right stacked on top of one another. As the footprint shrinks, horizontally, I would like the images to become small too, maintaining their aspect ratios. When I currently do it the images maintain their same size and are pushed off the left side of the page.
I am using bootstrap 3.* right now. But I would be curious to know how to do it with flexbox.
codepen
* {
box-sizing: border-box;
}
.content {
background-color: rgba(0, 0, 0, 0.3);
padding: 10px;
}
.row {
display: flex;
flex-flow: column wrap-reverse;
justify-content: center;
align-items: center;
max-width: 600px;
height: 40px;
background-color: rgba(0, 0, 0, .2);
}
.cell {
text-align: center;
display: flex;
align-items: center;
min-height: 50%;
padding-top: 5px;
padding-bottom: 5px;
}
.ordered3 {
order: 3;
flex: 2;
padding-right: 10px;
border-right: rgba(0, 0, 0, 0.3) solid 3px;
}
.ordered2 {
order: 2;
flex: 1;
}
.ordered1 {
order: 1;
flex: 1;
}
img {
margin: auto;
width: 100%;
max-width: 300px;
max-height: 100%
}
<div class="content">
<div class="row">
<div class="cell ordered3">
<img src="http://lorempixel.com/output/nature-q-c-260-44-8.jpg" />
</div>
<div class="cell ordered2">
<img src="http://lorempixel.com/output/city-q-c-260-24-3.jpg" />
</div>
<div class="cell ordered1">
<img src="http://lorempixel.com/output/abstract-q-c-310-37-1.jpg" />
</div>
</div>
</div>
Check my codeopen. If it's not what you want, please clarify your issue.
* {
box-sizing: border-box;
}
.content {
background-color: #f9f9f9;
border: 1px solid #ececec;
padding: 10px;
}
.row {
display: flex;
align-items: center;
}
.cell {
padding-top: 5px;
padding-bottom: 5px;
}
img {
width: 100%;
display: block;
max-width: 300px;
}
<div class="content">
<div class="row">
<div class="cell">
<img src="http://lorempixel.com/output/nature-q-c-260-44-8.jpg"/>
</div>
<div class="cell">
<img src="http://lorempixel.com/output/city-q-c-260-24-3.jpg"/>
<img src="http://lorempixel.com/output/abstract-q-c-310-37-1.jpg"/>
</div>
<div class="cell">
<img src="http://lorempixel.com/output/nature-q-c-260-44-8.jpg"/>
</div>
<div class="cell">
<img src="http://lorempixel.com/output/city-q-c-260-24-3.jpg"/>
<img src="http://lorempixel.com/output/abstract-q-c-310-37-1.jpg"/>
</div>
</div>
</div>