I have a flexbox with a grid and a div in it, and I'd like to collapse the grid container's height to the height of the rows, so that the buttons below it are just below the grid items. The number of rows is also dynamic, because I'm using grid-template-columns: repeat(auto-fit, minmax(250px, 1fr). I can set a max-height of the grid items, like in this image, but that only makes the items smaller and doesn't make the grid container any shorter.
I've tried changing the flexbox they're in so the flex-direction is row, and set flex-wrap to wrap, but that causes other problems and overlapping text when the window size changes. Setting the height or max-height of the grid container to fit-content seems to do nothing as well.
Here is what I have:
<!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 rgba(0, 0, 0, 0.8);
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
min-height: 100px;
}
#main-container {
display: flex;
flex-direction: row;
min-height: 100vh;
}
#section-container {
display: flex;
flex-direction: column;
width: 100%;
}
#page-buttons {
height: 50px;
text-align: center;
font-size: 20px;
}
</style>
</head>
<body>
<div id="main-container">
<aside class="sidebar">
</aside>
<div id="section-container">
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
</section>
<div id="page-buttons">
first
prev
page
next
last
</div>
</div>
</div>
</body>
</html>
The style
.grid-container {
flex: 4;
}
is equivalent to flex-grow: 4;
so it makes the container grow. Just remove it and it will keep its dimension
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 rgba(0, 0, 0, 0.8);
padding: 20px;
font-size: 24px;
text-align: center;
overflow: hidden;
min-height: 100px;
}
#main-container {
display: flex;
flex-direction: row;
min-height: 100vh;
}
#section-container {
display: flex;
flex-direction: column;
width: 100%;
}
#page-buttons {
height: 50px;
text-align: center;
font-size: 20px;
}
<body>
<div id="main-container">
<aside class="sidebar">
</aside>
<div id="section-container">
<section class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
</section>
<div id="page-buttons">
first
prev
page
next
last
</div>
</div>
</div>
</body>
Related
I have two inputs on form in one row. First one should be stretching on form resize, second is of fixed width. But when form is narrowed to a particular breakpont, second input should wrap to second line and stretch as well as first one.
Is it possible to achieve using CSS?
Tried using grid, but it won't wrap at all.
When using flexbox the result is better, but still have to set flex-grow for second input and it's width is not fixed, while inputs are in one row
.box {
background: grey;
padding: 20px 20px 20px 20px;
}
.wrapper {
display: grid;
grid-column-gap: 6px;
grid-row-gap: 6px;
grid-template-columns: minmax(320px, 1fr) 200px;
}
.flexWrapper {
display: flex;
flex-wrap: wrap;
}
.flex1 {
flex-basis: 320px;
flex-grow: 10;
flex-shrink: 0;
}
.flex2 {
flex-basis: 200px;
flex-shrink: 0;
flex-grow: 1;
}
<div class="wrapper">
<div class="box">One</div>
<div class="box">Two</div>
</div>
<div class="flexWrapper">
<div class="flex1 box">One</div>
<div class="flex2 box">Two</div>
</div>
https://codepen.io/C4off/pen/WNKjJaK
The easiest way to do this is to use a media query. At 600px I've reset the wrapper to be display: block with the children at 100% width which forces them to stack on top of each other. I've set the width of flex2 to 200px to fix it at that.
.box {
background: grey;
padding: 20px 20px 20px 20px;
}
.flexWrapper {
display: flex;
padding-top: 12px;
column-gap: 6px;
row-gap:6px;
}
.flex1 {
flex: 1;
}
.flex2 {
width: 200px;
}
#media only screen and (max-width: 600px) {
.flexWrapper {
display: block;
}
.flex1, .flex2 {
width: 100%;
}
}
<div class="container">
<div class="flexWrapper">
<div class="flex1 box">One</div>
<div class="flex2 box">Two</div>
</div>
</div>
Using flexbox only and the min-width proprty. Note .flex2 will overflow at container widths less than 200px
.container {
width: 60%;
outline: 1px solid red;
}
.box {
background: grey;
padding: 20px 20px 20px 20px;
}
.flex-wrapper {
display: flex;
padding-top: 12px;
column-gap: 6px;
row-gap:6px;
flex-wrap: wrap;
}
.flex1 {
flex: 2 0;
}
.flex2 {
min-width: 200px;
flex-grow: 1;
}
<div class="container">
<div class="flex-wrapper">
<div class="flex1 box">One</div>
<div class="flex2 box">Two</div>
</div>
</div>
The final way this can be done is using container queries which are quite well supported now. The max size is applied to the container and not the screen as the example below
* {
box-sizing:border-box;
}
.container {
container-type: inline-size;
container-name: my-container;
width: 60%;
}
.box {
background: grey;
padding: 20px 20px 20px 20px;
}
.flex-wrapper {
display: flex;
padding-top: 12px;
column-gap: 6px;
row-gap:6px;
}
.flex1 {
flex: 1;
}
.flex2 {
width: 200px;
}
#container my-container (max-width: 600px) {
.container {outline: 1px solid red;}
.flex-wrapper {
display: block;
}
.flex1, .flex2 {
width: 100%;
}
}
<div class="container">
<div class="flex-wrapper">
<div class="flex1 box">One</div>
<div class="flex2 box">Two</div>
</div>
</div>
I am building a grid layout based on 3 rows and I would like the middle row to take as much space as possible.
The first row should be at the start of the screen (blue bar in the code example) and the third row should be at the end of the screen(red bar in the code example)
How can I achieve this? :S
https://jsfiddle.net/xmghkLvs/31/
.grid {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto auto auto;
row-gap: 1%;
}
.top-bar{
background-color: blue;
border-radius: 5px;
}
.main-menu{
justify-self: center;
display: flex;
flex-direction: column;
background-color: green;
}
.bottom-bar{
background-color: red;
border-radius: 5px;
}
<div class="grid">
<div class="top-bar">
<h1>
Title
</h1>
</div>
<div class="main-menu">
<button>
One Button
</button>
<button>
Other Button
</button>
</div>
<div class="bottom-bar">
<p>
I'm a text
</p>
</div>
</div>
1st: Give the grid a min-height like 100vh (.grid { min-height: 100vh; }). This will make consume at least the viewports height.
2nd: Give the the first and last row a height of min-content. That will make it only consume as much height as needed. auto will then consume all remaining space by default.
.grid {
min-height: 100vh;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: min-content auto min-content;
row-gap: 1%;
}
.top-bar{
background-color: blue;
border-radius: 5px;
}
.main-menu{
justify-self: center;
display: flex;
flex-direction: column;
background-color: green;
}
.bottom-bar{
background-color: red;
border-radius: 5px;
}
<div class="grid">
<div class="top-bar">
<h1>
Title
</h1>
</div>
<div class="main-menu">
<button>
One Button
</button>
<button>
Other Button
</button>
</div>
<div class="bottom-bar">
<p>
I'm a text
</p>
</div>
</div>
Try using 100vh
.grid {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto auto auto;
row-gap: 1%;
height: 100vh;
}
and add specific height for the .top-bar abd .bottom-bar
You could approach this using Flexbox and 100vh as show below.
.grid {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
.top-bar{
display: flex;
height: 20%;
}
.main-menu{
display: flex;
align-items: center;
justify-content: center;
height: 60%;
}
.main-menu button {
height: 60px;
width: 120px;
}
.bottom-bar{
display: flex;
align-items: center;
justify-content: center;
height: 20%;
}
How to reduce the width of the flexbox container with the wrap option so it takes only the width taken by its items ?
The objective is not to see any green at the right of the yellow boxes (except for the margin set on the box item)
NOTE: The flexbox with wrap can accept more than 2 items per row, in function of the window's size.
main {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 900px; /* This width changes with the window's size */
background-color: red;
}
.list {
display: flex;
flex-wrap: wrap;
background-color: green;
justify-content: flex-start;
}
.list .box {
width: 300px; /* This will never change */
height: 300px;
margin: 0 32px 32px 0;
display: flex;
align-items: center;
justify-content: center;
background-color: yellow;
}
<main>
<h1>Titre ici</h1>
<div class="list">
<div class="box">box</div>
<div class="box">box</div>
<div class="box">box</div>
<div class="box">box</div>
</div>
</main>
Link to Codepen
I want to show you an alternative with css-grid and using the attribute minmax. I believe that will be closer to that what you want.
It will give every box a width of at least 300px and will fit as many boxes as possible. If space is left, then box size will improve to fit the space unless another box would fit.
To do that we have to add: grid-template-columns: repeat(auto-fit, minmax(300px, 1fr) );
That css line will add the columns amount. repeat means, that the the adding of a column is repeated according to the following rules:
auto-fit: It has to fit the screen width without leaving an empty space. it will resize the 1fr to make it possible.
minmax(300px, 1fr) means that every fraction needs to be at least 300px. If the screen is larger, then the first rule will apply again and the 1fr will be resized accordingly.
body {
margin: 0;
padding: 0;
width: 900px;
}
h1 {
background-color: red;
height: auto;
margin: 0;
}
.list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr) );
grid-auto-rows: auto;
grid-gap: 32px;
background-color: green;
}
.box {
min-height: 300px;
background-color: yellow;
}
<main>
<h1>Titre ici</h1>
<div class="list">
<div class="box">box</div>
<div class="box">box</div>
<div class="box">box</div>
<div class="box">box</div>
</div>
</main>
The answers given are correct,
You can try this as a different alternative.
* {
box-sizing: border-box;
}
main {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 900px;
/* emulate high width */
background-color: red;
}
.list {
background-color: green;
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.list .box-wrapper {
width: 300px;
height: 300px;
display: flex;
}
.list .box {
width: 100%;
margin: 0 16px 16px 0;
display: flex;
align-items: center;
justify-content: center;
background-color: yellow;
}
<main>
<h1>Titre ici</h1>
<div class="list">
<div class="box-wrapper">
<div class="box">
box
</div>
</div>
<div class="box-wrapper">
<div class="box">
box
</div>
</div>
<div class="box-wrapper">
<div class="box">
box
</div>
</div>
<div class="box-wrapper">
<div class="box">
box
</div>
</div>
</div>
</main>
I just commented out the margin on the .box and .list and replace flex-start with space-between on justify-content property and thereafter just added two smaller lines to format it well which are column-gap and row-gap to enerlarge the space between them
Example
main {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 900px;
/* emulate high width */
background-color: red;
}
.list {
display: flex;
flex-wrap: wrap;
background-color: green;
justify-content: space-between;
column-gap: 1px;
row-gap: 25px;
}
.list .box {
width: 300px;
height: 300px;
/*margin: 0 150px 32px 0;*/
display: flex;
align-items: center;
justify-content: center;
background-color: yellow;
}
<main>
<h1>Titre ici</h1>
<div class="list">
<div class="box">box</div>
<div class="box">box</div>
<div class="box">box</div>
<div class="box">box</div>
</div>
</main>
I'm currently trying to build a flex layout which should have 3 possible childs:
If the wrapper has just one button, it should have the full width of the wrapper.
If the wrapper has two childs, the last one should have a max width of 75px and the first one must fill the available space.
If the wrapper has at all three childs, the first row should be like at the example before but the last child should be in the next row with 100% width.
I've build this grid layout but I need change it to flex because of the compatibility of some browsers. How can I do this? I've tried a lot but the result is always bad.
.wrapper {
width: 60%;
display: grid;
display: -ms-grid;
grid-template-columns: 1fr 75px;
text-align: center;
position: relative;
margin-bottom: 20px;
}
.wrapper div+div {
margin-left: 6px;
}
.wrapper div {
background-color: yellow;
padding: .6em 1em;
text-align: center;
}
.wrapper div.show.single-button {
grid-column: 1/span 2;
}
.wrapper div.cancel {
grid-column: 1/span 2;
-ms-grid-row: 2;
-ms-grid-column-span: 2;
margin-top: 6px;
margin-left: 0;
}
<div class="wrapper">
<div class="show single-button">Show</div>
</div>
<div class="wrapper">
<div class="show">Show</div>
<div class="invoice">Invoice</div>
</div>
<div class="wrapper">
<div class="show">Show</div>
<div class="invoice">Invoice</div>
<div class="cancel">Cancel</div>
</div>
Judicious use of flex:1 and flex-wrap seems to work.
* {
box-sizing: border-box;
}
.wrapper {
width: 60%;
margin: auto;
display: flex;
flex-wrap: wrap;
margin-bottom: 20px;
justify-content: space-between;
border: 1px solid green;
}
.wrapper div {
background-color: lightblue;
padding: .6em 1em;
text-align: center;
margin: 6px;
}
.wrapper div.show {
flex: 1;
}
.wrapper div.invoice {
flex: 1;
max-width: 75px;
}
.wrapper div.cancel {
flex: 1 1 100%;
}
<div class="wrapper">
<div class="show single-button">Show</div>
</div>
<div class="wrapper">
<div class="show">Show</div>
<div class="invoice">Invoice</div>
</div>
<div class="wrapper">
<div class="show">Show</div>
<div class="invoice">Invoice</div>
<div class="cancel">Cancel</div>
</div>
Flexbox offers everything you need for this. No need to hack around by mixing flexbox with box-model or width properties:
.wrapper {
height: 100px;
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
}
.wrapper > div {
flex: 1;
border: 1px dotted #999;
background-color: aliceblue;
}
.wrapper > div:nth-child(2) {
flex-shrink: 0;
flex-grow: 0;
flex-basis: 75px;
-webkit-flex-basis: 75px;
}
.wrapper > div:nth-child(3) {
flex-shrink: 0;
flex-grow: 0;
flex-basis: 100%;
-webkit-flex-basis: 100%;
}
<div class="wrapper">
<div>1</div>
</div>
<div class="wrapper">
<div>1</div>
<div>2</div>
</div>
<div class="wrapper">
<div>1</div>
<div>2</div>
<div>3</div>
</div>
You can use flex-basis to tell the initial width of the elements and flex-grow to tell if they should take more space, and flex-wrap so it does not force them to fit in one line, something like:
.wrapper {
display: flex;
flex-wrap: wrap; // make it multiline
margin-bottom: 1rem;
}
.wrapper div {
background: yellow;
margin: .2rem;
padding: .2rem;
text-align: center;
}
.invoice {
flex-basis: 75px; // make it have 75px
flex-grow: 0; // can't grow
flex-shrink: 0; // can't shrink
}
.show {
flex-grow: 1; // no basis width, just grow and take the space left from .invoice
}
.cancel {
flex-basis: 100%; // takes the whole width so it must go on a single row
}
https://codepen.io/anon/pen/KJLqVj
I'm trying to create a sidebar that is a fixed percentage of the view port. Inside the sidebar, I'd like an element that is fixed to the top while the rest of content scrolls if it take up more vertical space than the sidebar height.
In this example, the h1 element remains at the top of the parent element while the rest of the content, .inner can be scrolled. The content and scroll bar inside .inner is cut off by the height of the h1 element.
How can I display the all the content and scroll bar?
* { box-sizing: border-box; margin: 0; padding: 0; }
body: {
height: 100vh;
}
.grid-container {
display: grid;
grid-template-columns: 1fr 5fr;
grid-template-areas: 'left right';
justify-content: space-around;
grid-gap: 12px;
width: 90vw;
height: 100vh;
margin: auto;
}
.left {
grid-area: left;
}
.right {
gird-area: right
}
.side {
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
}
.outer {
height: 90vh;
margin: auto;
position: relative;
border: 1px solid blue;
overflow:hidden;
}
.inner {
height: 100%;
overflow: auto;
}
h1 {
height: 100px;
background: lightgrey;
}
p {
height: 100px;
}
<div class="grid-container">
<div class="left">
<div class="side">
<div class="outer">
<h1>other content</h1>
<div class="inner">
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>5</p>
</div>
</div>
</div>
</div>
<div class="right"></div>
</div>
You want to avoid setting explicit heights on things whenever possible. That tends to bite you. Set the rules for your flex layout and let it do its thing. If you need whitespace somewhere, keep things simple and add it to the box's contents, not the box itself. By separating the concerns of layout and content, you make it easier to pluck out one bit of content and replace it without getting into the CSS for your layout.
Scroll into the CSS for hints.
* { box-sizing: border-box; margin: 0; padding: 0; }
body: {
height: 100vh;
}
.grid-container {
display: grid;
grid-template-columns: 1fr 5fr;
grid-template-areas: 'left right';
justify-content: space-around;
grid-gap: 12px;
width: 90vw;
height: 100vh;
margin: auto;
}
.left {
grid-area: left;
}
.right {
gird-area: right
}
.side {
display: flex;
flex-direction: column;
justify-content: center;
height: 100%;
}
.outer {
height: 90vh;
margin: auto;
position: relative;
border: 1px solid blue;
display: flex; /* <--------------- change */
flex-direction: column; /* <--------------- add */
}
.inner {
/* height: 100%; <--------------- remove */
overflow: auto;
}
h1 {
flex: 0 0; /* <--------------- change */
background: lightgrey;
}
p {
height: 100px;
}
<div class="grid-container">
<div class="left">
<div class="side">
<div class="outer">
<h1>other content</h1>
<div class="inner">
<p>1</p>
<p>2</p>
<p>3</p>
<p>4</p>
<p>5</p>
</div>
</div>
</div>
</div>
<div class="right"></div>
</div>