I have a layout that is a sidebar and a grid both wrapped in a flexbox. I'd like to put a div underneath the grid so it can have prev/next buttons, like in this image, but I can't figure out how to do that. The grid resizes itself with the window so the grid can take as many rows as necessary and then the div should go below that, and be as wide as the grid.
This is what I have, but the div is on the right of the grid:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Boardgame Database</title>
<style>
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
aside {
background-color: red;
flex: 1;
min-width: 250px;
}
.grid-container {
flex: 4;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
.grid-item {
border: 1px solid black;
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
}
#flex-container {
display: flex;
flex-direction: row;
min-height: 100vh;
}
</style>
</head>
<body>
<div id="flex-container">
<aside class="sidebar">
</aside>
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
<div class="grid-item">7</div>
<div class="grid-item">8</div>
<div class="grid-item">9</div>
<div class="grid-item">10</div>
<div class="grid-item">11</div>
<div class="grid-item">12</div>
<div class="grid-item">13</div>
<div class="grid-item">14</div>
<div class="grid-item">15</div>
<div class="grid-item">16</div>
<div class="grid-item">17</div>
<div class="grid-item">18</div>
</section>
<div id="page-buttons">
prev
next
</div>
</div>
Checkout the following Code.
#main{
display :flex;
}
#sidebar{
width:70px;
height: 300px;
border: solid black 1px;
}
#grid-area{
width:200px;
height: 300px;
border: solid black 1px;
display: block;
}
#grid{
width:200px;
height: 250px;
border: solid black 1px;
display: block;
}
<div id="main">
<div id="sidebar"></div>
<div id="grid-area">
<div id="grid"></div>
<div id="button">next / prev</div>
</div>
</div>
You should use nested flex containers. Section and bottom div should be wrapped inside another flex container with flex direction to column.
So outer flex will make sidebar & inner flex container to be side by side.
Or just use a normal div container instead of flex.
here is another example only with grid keeping the pre/next button at the bottom of the viewport:
body {
margin: 0;
}
#grid-container {
display: grid;
height: 100vh;
grid-template-columns: minmax(250px, 1fr) 4fr;
grid-template-rows: 1fr auto;
}
aside {
background-color: red;
border: 1px solid;
margin: 0.25em;
grid-row: span 2;
grid-column: 1;
}
section,
#page-buttons {
grid-column: 2;
border: solid 1px;
margin: 0.25em;
}
section {
overflow: auto;
}
#page-buttons {
display: flex;
gap: 1em;
padding: 0.5em;
background: lightgray;
justify-content: center;
}
.grid-item {
border: 1px solid black;
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
}
<div id="grid-container">
<aside class="sidebar">
</aside>
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
<div class="grid-item">7</div>
<div class="grid-item">8</div>
<div class="grid-item">9</div>
<div class="grid-item">10</div>
<div class="grid-item">11</div>
<div class="grid-item">12</div>
<div class="grid-item">13</div>
<div class="grid-item">14</div>
<div class="grid-item">15</div>
<div class="grid-item">16</div>
<div class="grid-item">17</div>
<div class="grid-item">18</div>
</section>
<div id="page-buttons">
prev
next
</div>
</div>
Related
I want div.line with border black like below code to have full height in container scroll.
When there is an element that is too long, for example, line number 4 the borders will be shortened, with no height until the end.
Is there a way for the elements inside the scroll container to always be the same height as the tallest element?
Thanks, everyone!
.container {
display: flex;
align-items: stretch;
height: 300px;
overflow: auto;
}
.line {
width: calc(100% / 4);
border-left: 1px solid #000;
padding: 0 16px;
}
.item {
height: 100px;
background: blue;
color: white;
padding: 16px;
}
.line:nth-child(2) .item {
height: 200px;
}
.line:nth-child(4) .item {
height: 600px;
}
<div class="container">
<div class="line">
<div class="item">1</div>
</div>
<div class="line">
<div class="item">2</div>
</div>
<div class="line">
<div class="item">3</div>
</div>
<div class="line">
<div class="item">4</div>
</div>
</div>
If I get you right, then
<!DOCTYPE html>
<html lang="en">
<head>
<title>Scroll flex</title>
<style>
.another-container {
height: 300px;
overflow-y: scroll;
}
.container {
display: flex;
}
.line {
width: calc(100% / 4);
border-left: 1px solid #000;
padding: 0 16px;
}
.item {
height: 100px;
background: blue;
color: white;
padding: 16px;
}
.line:nth-child(2) .item {
height: 200px;
}
.line:nth-child(4) .item {
height: 600px;
}
</style>
</head>
<body>
<div class="another-container">
<div class="container">
<div class="line">
<div class="item">1</div>
</div>
<div class="line">
<div class="item">2</div>
</div>
<div class="line">
<div class="item">3</div>
</div>
<div class="line">
<div class="item">4</div>
</div>
</div>
</div>
</body>
</html>
Your solution does not work as intended because you set the height of your flex container explicitly, as #XiaoGuang pointed out. None of flex items could be greater than the container itself. So first step is to remove the height property and let the flex container to become as tall as the tallest flex item. After that, if you still need scrolling, just add another container for that.
You should use grid in this case instead of flex. Take a look at comments in code for more details.
.container {
display: grid; /* change to grid */
grid-template-columns: repeat(4, 1fr); /* create 4 columns */
height: 300px;
overflow: auto;
}
.line {
width: calc(100% - 16px * 2); /* full width column */
border-left: 1px solid #000;
padding: 0 16px;
}
.item {
height: 100px;
background: blue;
color: white;
padding: 16px;
}
.line:nth-child(2) .item {
height: 200px;
}
.line:nth-child(4) .item {
height: 600px;
}
<div class="container">
<div class="line">
<div class="item">1</div>
</div>
<div class="line">
<div class="item">2</div>
</div>
<div class="line">
<div class="item">3</div>
</div>
<div class="line">
<div class="item">4</div>
</div>
</div>
Since your .line divs also contain an item, you need to make them flexboxs as well, and then make the item grow to the full height. Something like this:
.container {
display: flex;
align-items: stretch;
height: 300px;
overflow: auto;
}
.line {
width: calc(100% / 4);
border-left: 1px solid #000;
padding: 0 16px;
display: flex;
flex-direction: column;
}
.item {
background: blue;
color: white;
padding: 16px;
flex-grow: 1;
}
.line:nth-child(2) .item {
height: 200px;
}
.line:nth-child(4) .item {
height: 600px;
}
<div class="container">
<div class="line">
<div class="item">1</div>
</div>
<div class="line">
<div class="item">2</div>
</div>
<div class="line">
<div class="item">3</div>
</div>
<div class="line">
<div class="item">4</div>
</div>
</div>
And that's basically it.
Currently facing some problems with the layout I want to accomplish.
How can I divide my page in such a way that the header row gets the height it needs ( for it's content ) and all the rest is given to the images row? A bit like auto, 100% if that is possible? For testing I've given it a fixed height.
The text in the header row should be bottom alligned vertically but somehow this is not working?
And lastly, how can I get the images row scrollable in such a way that the header row stays fixed? So not sticky for the header, because then the header will also partially scroll. The complete content of the header should stay fixed and only the images content should scroll on Y value. ( so no horizontal scroll )
body {
font-size: 18px;
max-width: 820px;
margin: 0 auto;
}
.table {
display:table;
width:100%;
}
.row {
display:table-row;
}
.row.header {
height:80px;
vertical-align: bottom;
}
.row.images {
overflow: scroll;
}
.column {
display: table-cell;
width: 50%
}
.column.left {
padding-left: 10px;
}
.column.right {
text-align: right;
padding-right: 10px;
}
<body>
<div class="table">
<div class="row header">
<div class="column left">Portfolio</div>
<div class="column right">Artist</div>
</div>
<div class="row images">
<div class="grid">
<div class='grid__col-sizer'></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/orange-tree.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/submerged.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/look-out.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/one-world-trade.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/drizzle.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/cat-nose.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/contrail.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/golden-hour.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/flight-formation.jpg"></div>
</div>
</div>
</div>
</body>
Solved my own problems, using CSS grid. The complete codepen is available here: https://codepen.io/depechie/pen/jOBGrRP
body {
font-family: "Helvetica Neue", Arial, sans-serif;
font-size: 0.8rem;
margin: 0;
}
.page {
display: grid;
grid-template-rows: auto;
grid-template-columns: 1fr;
height: 100vh;
}
.panel {
display: grid;
/* grid-template-rows: var(--bar-height) 1fr; */
grid-template-rows: auto 1fr;
height: 100vh;
}
.panel-body {
overflow-y: auto;
display: grid;
justify-content: center;
}
.tabs {
display: grid;
grid-template-columns: repeat(2, 1fr);
height: 100%;
padding: 20px;
}
.tab-item.left {
text-align: left;
}
.tab-item.right {
text-align: right;
}
You can Use height: fit-content; To make the height of the div fit the height of the elements it has
code:
body {
font-size: 18px;
max-width: 820px;
margin: 0 auto;
}
.table {
display:table;
width:100%;
}
.row {
display:table-row;
}
.row.header {
/* here you can replace fixed hight with : fit-height */
height:fit-height;
display: flex;
vertical-align: bottom;
}
.row.images {
overflow: scroll;
}
.column {
display: table-cell;
width: 50%
}
.column.left {
padding-left: 10px;
}
.column.right {
text-align: right;
padding-right: 10px;
}
<body>
<div class="table">
<div class="row header">
<div class="column left">Portfolio</div>
<div class="column right">Artist</div>
</div>
<div class="row images">
<div class="grid">
<div class='grid__col-sizer'></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/orange-tree.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/submerged.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/look-out.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/one-world-trade.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/drizzle.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/cat-nose.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/contrail.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/golden-hour.jpg"></div>
<div class="grid__item"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/82/flight-formation.jpg"></div>
</div>
</div>
</div>
</body>
Can I achieve this layout with flexbox with the below document structure?
I want the big <img> on the left with two smaller images on the right and wrapping.
This is what I did, with display: flex on gallery-container and flex-wrap.
.container {
height: 100%;
}
.container .gallery-container {
background-color: #f6f6f6;
display: flex;
flex-wrap: wrap;
width: 300px;
align-items: flex-start;
}
.container .gallery-container .gallery-big-image {
display: block;
width: 200px;
height: 200px;
background: lavender;
}
.container .gallery-container .gallery-small-img {
display: block;
width: 100px;
height: 100px;
background-color: purple;
}
<div class="container">
<div class="gallery-container">
<div class="gallery-big-image">big</div>
<div class="gallery-small-img">small</div>
<div class="gallery-small-img">small</div>
<div class="gallery-small-img">small</div>
<div class="gallery-small-img">small</div>
<div class="gallery-small-img">small</div>
</div>
</div>
(codepen)
The layout is clunky and inefficient with flexbox, for reasons explained here: CSS-only masonry layout
However, the layout is relatively simple and easy with CSS Grid.
No changes to HTML.
.gallery-container {
display: grid;
grid-template-columns: repeat(auto-fill, 100px);
grid-auto-rows: 100px;
width: 300px;
background-color: #f6f6f6;
}
.gallery-big-image {
grid-column: span 2;
grid-row: span 2;
background: lavender;
}
.gallery-small-img {
background-color: purple;
color: white;
}
<div class="container">
<div class="gallery-container">
<div class="gallery-big-image">big</div>
<div class="gallery-small-img">small 1</div>
<div class="gallery-small-img">small 2</div>
<div class="gallery-small-img">small 3</div>
<div class="gallery-small-img">small 4</div>
<div class="gallery-small-img">small 5</div>
<div class="gallery-small-img">small 6 (continues wrapping)</div>
<div class="gallery-small-img">small 7 (continues wrapping)</div>
</div>
</div>
How about using grid layout instead?
.container {
height: 100%;
}
.gallery-container {
background-color: #f6f6f6;
width: 300px;
height: 100px;
display: grid;
grid-template-rows: repeat(3, 1fr);
grid-template-columns: repeat(3, 1fr);
}
.gallery-img {
background: purple;
width: 100px;
height: 100px;
}
.gallery-img-large {
background: lavender;
width: 200px;
height: 200px;
grid-column-start: 0;
grid-column-end: span 2;
grid-row-start: 0;
grid-row-end: span 2;
}
<div class="container">
<div class="gallery-container">
<div class="gallery-img-large">big</div>
<div class="gallery-img">small</div>
<div class="gallery-img">small</div>
<div class="gallery-img">small</div>
<div class="gallery-img">small</div>
<div class="gallery-img">small</div>
</div>
</div>
OK, I edited my question and code to easily show what I mean. I need to have:
"menu" - positioned-left, min-height=500px, width=250px - at all times.
"content" - positioned on the right side of "menu", dynamic width to take all remaining space.
Same height for "menu" and "content" at all times. No matter there will be 1 box or 100 inside "content".
"Boxes" should be lined up from left to right and if there are more, they should stretch height of "content" and "menu" should follow the same height.
<div class="header" style="height:150px; background-color:black;" >
</div>
<div class="navbar" style="height:40px; background-color:yellow;" >
</div>
<div class="menu" style="min-height:500px; width:250px; background-color:orange; float:left;" >
</div>
<div class="content" style="height:auto; background-color:blue; float: left; " >
<?php for ($col = 0; $col < 50; $col++)
{
?><div class="box" style="width:80px; height:80px; background-color:white; margin:10px;" ></div><?php
}
?>
</div>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
div {
border: 1px solid black
}
body {
display: grid;
grid-template-columns: 250px 1fr;
grid-template-rows: 150px 40px minmax(500px , 1fr)
}
.header, .navbar {
grid-column: 1 / -1
}
.content {
display: grid;
grid-gap: 20px;
padding: 20px;
grid-template-columns: repeat(auto-fill, 80px);
align-content: start;
justify-content: space-evenly;
}
.box {
width: 80px;
height: 80px;
}
<body>
<div class='header'>
Header
</div>
<div class='navbar'>
Navbar
</div>
<div class='menu'>
Menu
</div>
<div class='content'>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
<div class='box'>box</div>
</div>
</body>
Your goal is easier to achieve with flexbox, as shown in the solution below.
.header {
height: 150px;
background-color: black;
}
.navbar {
height: 40px;
background-color: yellow;
}
.container {
min-height: 500px;
display: flex;
align-items: flex-start;
}
.menu {
min-height: 500px;
height: 100%;
width: 250px;
background-color: orange;
}
.content {
min-height: 500px;
background-color: blue;
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
.box {
width: 80px;
height: 80px;
background-color: white;
margin: 10px;
}
<div class="header">
</div>
<div class="navbar">
</div>
<div class="container">
<div class="menu">
</div>
<div class="content">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
What I thought would be a simple layout turned out to be something I'm not able to accomplish yet.
I need the grid to be responsive and spread from one side to another (it has to be aligned with the text and box above).
I tried a few options, I commented them out for easier checking:
.big-container {
padding: 0 20%;
}
.header {
width: 100%;
height: 50px;
background-color: blue;
}
.container {
border: 1px solid black;
/* display: flex;
flex-wrap: wrap;
*/
/* display: flex;
flex-wrap: wrap;
justify-content: space-between;
*/
}
.box {
border: 1px solid black;
width: 100px;
height: 30px;
background-color: yellow;
/* float: left;
margin-left: 10px; */
}
<div class="big-container">
<div class="header"></div>
<p>Text</p>
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>
I tried with flex but it doesn't sort nicely the last row, flex-wrap: wrap and float:left with some margin doesn't align correctly to the left.
If you use flexbox and set justify-content: space-between then last row will also have the same spacing instead of left align. Instead you can use grid-layout for this.
.big-container {
padding: 0 20%;
}
.header {
width: 100%;
height: 50px;
background-color: blue;
}
.container {
border: 1px solid black;
display: grid;
justify-content: space-between;
grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
grid-gap: 10px;
}
.box {
border: 1px solid black;
height: 30px;
background-color: yellow;
}
<div class="big-container">
<div class="header"></div>
<p>Text</p>
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
</div>