flexbox grid under centered flex item - html

I would like an intro section on the left side of a .container and a side bar on the right.
On the left side underneath the .intro section I want there to be four divs equally spaced like a grid.
I'm having problems with getting the "grid set up". I think part of the problem is that the parent has some flexbox attribute effecting the children.
Requirement : The intro section should be centered in the .left-side and the "grid" should not be centered the boxes should take up as much space as necessary to fit 2 on a row with margins in between. The .intro should be 80 percent of the width of the leftside.
I don't want to do any major changes to the structure this is just a small sample of how my project is set up.
.container{
width: 80%;
margin: 0 auto;
display: flex;
}
.left-side{
flex:8;
display: flex;
justify-content:center;
flex-wrap: wrap;
}
.side-bar{
flex: 2;
height: 100vh;
background: powderblue;
}
.intro{
flex:3;
width:80%;
height: 300px;
background: skyblue;
}
.box{
background: red;
width: 45%;
height: 100px;
flex:4;
border:1px solid orange;
}
<div class="container">
<div class="left-side">
<div class="intro">
intro
</div>
<div class="recent">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
</div>
</div>
<div class="side-bar">
sidebar
</div>

Flex items can also be flex containers. This enables you to nest multiple containers, with flex-direction: row or column, in a larger container.
For your layout, you can build a column consisting of two flex items. The first item (.intro) has 80% width and can be centered horizontally. The second item (.recent) can be a flex container with four items arranged in a 2x2 grid.
.container {
width: 80%;
margin: 0 auto;
display: flex;
justify-content: center;
height: 100vh;
}
.left-side {
flex: 4;
display: flex;
flex-direction: column;
}
.side-bar {
flex: 1;
background: powderblue;
}
.intro {
flex: 3;
height: 300px;
width: 80%;
margin: 0 auto;
background: skyblue;
}
.recent {
display: flex;
flex-wrap: wrap;
background-image: url("http://i.imgur.com/60PVLis.png");
background-size: contain;
}
.box {
margin: 5px;
flex-basis: calc(50% - 10px);
height: 100px;
box-sizing: border-box;
background: red;
}
body { margin: 0; }
<div class="container">
<div class="left-side">
<div class="intro">intro</div>
<div class="recent">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
</div>
</div>
<div class="side-bar">
sidebar
</div>
</div>

Related

Position: sticky for sidebar when parent container has fixed height

I want to have a container that doesn't exceed a certain height, with a 2 column layout: a large main section which sticks at the top while the user scrolls through the items in the sidebar. I tried setting a fixed height and overflow onto the container but this has broken the position: sticky. Is this possible without having lots of space at the bottom, when there's lots of items in the sidebar? I would like for these items to not overflow the height of the container (i.e. the height of the column 1 section).
.container {
padding: 10px;
}
.header,
.footer {
display: flex;
align-items: center;
justify-content: center;
height: 120px;
background: #e1e1e1;
}
.wrapper {
display: flex;
padding: 15px 0;
max-height:400px;
overflow:scroll;
}
.col-1 {
flex: 1 0 auto;
}
.col-inner {
background: purple;
color: #fff;
height: 300px;
margin-right: 10px;
display: flex;
align-items: center;
justify-content: center;
}
.col-inner {
position: sticky;
position: -webkit-sticky;
top: 0;
}
.item {
display: flex;
align-items: center;
justify-content: center;
width: 200px;
height: 200px;
color: #fff;
background: blue;
margin-bottom:10px
}
<div class="container">
<header class="header">Header</header>
<div class="wrapper">
<div class="col-1">
<div class='col-inner'>Column 1</div>
</div>
<div class="col-2">
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
<div class="item">Item</div>
</div>
</div>
<footer class="footer">Footer</footer>
</div>
I think I understand what you're trying to accomplish. Hopefully this helps: I took your code as you listed above and added:
.col-2{
overflow-y: scroll;
height: 300px;
}
This allowed me to scroll on your col-2 element while maintaining a fixed height.

Create a circle that fills up the remaining space in a flexbox cell

I have a 2-cell flexbox with a fixed-height (mobile screen), and one cell stacked on top of the other. I need all of the content of the top-cell to be displayed.. the bottom-cell should yield as much space as possible to allow this. This part was easy.
.main-container {
height: 400px;
width: 200px;
display: flex;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background-color: lightgrey;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
... with that the content-container will grow as needed (in this example it's 100px) and the rest is taken up by the remaining-space cell.
What I need to do is fill the remaining-space cell with a circle that is as big as it can be, but doesn't force the remaining-space cell to grow in height/width... and I need to do it with just html/css.
The only way I've seen to enforce a 1:1 ratio (square/circle) is by using the padding-bottom trick where the padding is calculated using the element's width. This doesn't work for me because remaining-space cell might have a larger width than it's height.. which will cause the cell to grow in height. This is especially difficult in that the container is responsive so the actual width in pixels is never known.
A simple gradient can do it:
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background:
radial-gradient(circle closest-side, red 98%, transparent)
lightgrey;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space"></div>
</div>
Clip-path can also do it:
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background: lightgrey;
}
.remaining-space>div {
height: 100%;
background: red;
clip-path: circle(closest-side)
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div></div>
</div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div></div>
</div>
</div>
Where you can also have content inside
.main-container {
height: 400px;
width: 200px;
display: inline-flex;
vertical-align: top;
flex-direction: column;
}
.content-container {
flex-grow: 1;
flex-shrink: 0;
background-color: green;
}
.content {
height: 100px;
}
.remaining-space {
flex-grow: 0;
flex-shrink: 1;
height: 100%;
background: lightgrey;
}
.remaining-space>div {
height: 100%;
background: red;
clip-path: circle(closest-side);
display:flex;
align-items:center;
justify-content:center;
font-size:30px;
}
<div class="main-container">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div> text </div>
</div>
</div>
<div class="main-container" style="height:200px;">
<div class="content-container">
<div class="content"></div>
</div>
<div class="remaining-space">
<div> text </div>
</div>
</div>

Flex column, column exceeding container width

I can't get the flex: column working so that child elements don't exeed the parent. The left block is an image, it has to be 100% of containers height:
.container {
width: 500px;
height: 300px;
border: solid blue 1px;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
.tall {
height: 100%;
width: 300px;
background: yellow;
}
.row {
margin: 10px 0;
background: red;
min-height: 10px;
}
<div class="container">
<div class="tall"></div>
<div class="row">This is a text that should be multiline, with automatic width depending on the left block width.</div>
<div class="row"></div>
<div class="row"></div>
</div>
The right rows no matter what I try are always exceeding the container, their width is always container width, not the remaining space widht. How can I achieve it?
I would change the direction of your flex so it is row and remove the flex wrap, then I would wrap your rows in a div with flex-grow:1 and remove the height from tall:
.container {
width: 500px;
height: 300px;
border: solid blue 1px;
display: flex;
flex-direction: row;
}
.tall {
width: 300px;
background: yellow;
}
.row-holder {
flex-grow:1;
}
.row {
margin: 10px 0;
background: red;
min-height: 10px;
}
<div class="container">
<div class="tall"></div>
<div class="row-holder">
<div class="row">This is a text that should be multiline, with automatic width depending on the left block width.</div>
<div class="row"></div>
<div class="row"></div>
</div>
</div>

Flexbox and Flex Wrap issues on different devices

I am trying to get the following layout to work using flexbox, I have two div containers next to each other. In the first div there are 6 boxes they must be 3, then wrap on to the next line. The second div contains text. I have tried a number of different approaches as I would like them all stacked on mobile and tablet and then laid out above on desktop.
Code I have so far:
<div class="container">
<div class="child">Test</div>
<div class="child">Test</div>
<div class="child">Test</div>
<div class="child">Test</div>
<div class="child">Test</div>
<div class="child">Test</div>
</div>
<div class="box-container">
<h1>hello</h1>
</div>
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 800px;
border: 1px solid red;
}
.child {
flex: 0 0 calc(33.3% - 20px);
border: 1px solid blue;
}
.box-container{
display:flex;
}
The two containers are made to be next to each other by setting flex-basis: 50% so that they each take up 50% of the row and by making their container (body) a flex container.
A media query is used to change the style when the maximum width of the screen is 768px or lower. It changes the the flex-direction of the containers to column so that elements are stack vertically. Then, flex-basis is set to 100% so each element takes up an entire column.
.container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
flex-basis: 50%;
border: 1px solid red;
}
.child {
flex: 0 0 calc(33.3% - 20px);
border: 1px solid blue;
}
.box-container {
display: flex;
flex-basis: 50%;
}
body {
display: flex;
}
#media only screen and (max-width: 768px) {
.container {
flex-direction: column;
flex-basis: 100%;
}
.child {
flex-basis: 100%;
}
body {
display: flex;
flex-direction: column;
}
.box-container {
flex-basis: 100%;
}
}
<body>
<div class="container">
<div class="child">
Test
</div>
<div class="child">
Test
</div>
<div class="child">
Test
</div>
<div class="child">
Test
</div>
<div class="child">
Test
</div>
<div class="child">
Test
</div>
</div>
<div class="box-container">
<h1>
hello
</h1>
</div>
</body>

When rows added to a flexbox, box's height increases

When I add more inbox1 class divs into the div with class box1, the height of box1 increases. You can observe this in jsfiddle with red background never disappearing, however many inbox1's are added. What is the reason of this?
.outer {
position: relative;
width: 400px;
height: 600px;
background-color: black;
display: flex;
flex-flow: row wrap;
}
.container {
position: relative;
flex: 1;
display: flex;
flex-direction: column;
}
d1 {
flex: 1;
background-color: yellow;
}
.d2 {
flex: 1;
background-color: green;
}
.box1 {
display: flex;
flex-flow: row wrap;
align-content: flex-start;
color: white;
flex: 1;
background-color: red;
overflow: scroll;
}
.box2 {
color: white;
flex: 12;
background-color: blue;
}
.inbox1 {
flex: 1 100%;
background-color: purple;
}
<div class="outer">
<div class="container">
<div class="box1">
<div class="inbox1">inbox1</div>
<div class="inbox1">inbox1</div>
<div class="inbox1">inbox1</div>
<div class="inbox1">inbox1</div>
<div class="inbox1">inbox1</div>
</div>
<div class="box2"></div>
</div>
<div class="d1"></div>
<div class="d2"></div>
</div>
Edit :
The purpose of this structure is that, container div is the content of a website, and d1 and d2 divs represent sidebars. However their order is not set in the example because they are needed for the sake of the result.
Container div has two parts, upper(red background) and lower. In my structure this upper and lower are set as flex boxes in container which is display flex with column direction. Upper is also display flex with row direction. However in this set up, as new items are added into the upper, the height of the upper increases. I dont want it enlarge with added childrens.
Note that, if I remove d1 and d2 divs and remove display:flex and related css attributes from outer div, and add container in it as a classic relative element, and change NOTHING else, this problem magically disappears.
Edit 2:
Thanks to oriol, i confirmed this only occurs with chrome.
If I understand you right, here is 3 ways to accomplish that
By giving flex: 0 to your box1, you tell it to only be as big as its content, and by adding max-height: 80px you say "start scroll" when content gets higher than 80px
.outer {
position:relative;
width:400px;
height:600px;
background-color:black;
display: flex;
flex-flow: row wrap;
}
.container {
position:relative;
flex: 1;
display: flex;
flex-direction: column;
}
.d1 {
flex: 1;
background-color: yellow;
}
.d2 {
flex: 1;
background-color: green;
}
.box1 {
display: flex;
flex-flow: row wrap;
align-content: flex-start;
color: white;
flex: 0; /* changed from 1 to 0 */
background-color: red;
overflow: scroll;
max-height: 80px; /* added */
}
.box2 {
color: white;
flex: 12;
background-color: blue;
}
.inbox1 {
flex: 1 100%;
background-color: purple;
}
<div class="outer">
<div class="container">
<div class="box1">
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
</div>
<div class="box2">
</div>
</div>
<div class="d1">
</div>
<div class="d2">
</div>
</div>
Set the flex-basis to 8% (box1 has flex 1 and box2 has flex 12, 100 / 12+1 = 7.69) and when content grow beyond that, it starts to scroll.
Note that the container needs height:100%, so flex-basis: 8% have where to get its value.
.outer {
position:relative;
width:400px;
height:600px;
background-color:black;
display: flex;
flex-flow: row wrap;
}
.container {
position:relative;
height: 100%; /* added */
flex: 1;
display: flex;
flex-direction: column;
}
.d1 {
flex: 1;
background-color: yellow;
}
.d2 {
flex: 1;
background-color: green;
}
.box1 {
display: flex;
flex-flow: row wrap;
align-content: flex-start;
color: white;
flex: 1;
flex-basis: 8%; /* added */
background-color: red;
overflow: scroll;
}
.box2 {
color: white;
flex: 12;
background-color: blue;
}
.inbox1 {
flex: 1 100%;
background-color: purple;
}
<div class="outer">
<div class="container">
<div class="box1">
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
</div>
<div class="box2">
</div>
</div>
<div class="d1">
</div>
<div class="d2">
</div>
</div>
Use an inner div with position: absolute (since flex has some issues to force scroll, this one make it happen)
.outer {
position:relative;
width:400px;
height:600px;
background-color:black;
display: flex;
flex-flow: row wrap;
}
.container {
position:relative;
flex: 1;
display: flex;
flex-direction: column;
}
.d1 {
flex: 1;
background-color: yellow;
}
.d2 {
flex: 1;
background-color: green;
}
.box1 {
display: flex;
flex-flow: row wrap;
align-content: flex-start;
flex: 2; /* temp. adjusted to make it slightly bigger */
position: relative; /* added to make position: absolute relate to this */
}
.box1 .inner { /* added rule to make box1 content scroll */
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: scroll;
color: white;
background-color: red;
}
.box2 {
color: white;
flex: 12;
background-color: blue;
}
.inbox1 {
flex: 1 100%;
background-color: purple;
}
<div class="outer">
<div class="container">
<div class="box1">
<div class="inner">
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
<div class="inbox1">
inbox1
</div>
</div>
</div>
<div class="box2">
</div>
</div>
<div class="d1">
</div>
<div class="d2">
</div>
</div>