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>
Related
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%;
}
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>
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>
I want to create a simple layout for my SPA where I have a header component, which should be shown all the time. A footer component, which should be either at the bottom of the screen or if the main content component is bigger than the screen, it should be below the content component. And a main content component which should get the rest of the space if the screen is bigger than the content, so the footer component gets rendered at the bottom.
Currently I've reproduced my layout in this codepen. But if you shrink the result window of the codepen enough, you'll get to a point where I can't see the Test2 text because the footer component is on top of it. The behaviour I would expect is, that I can see the Test2 text and I'm able to scroll down to the footer component.
It works if the content component is not a flex box with flex-direction: row. Any ideas why this doesn't work?
In my SPA I'm using React, so I don't want to use any JavaScript for this.
* {
padding: 0;
margin: 0;
font-size: 2rem;
}
.page {
display: flex;
flex-direction: column;
height: 100vh;
width: 100%;
background: yellow;
}
.container {
display: flex;
flex-direction: column;
flex: 1;
overflow: scroll;
}
.main {
flex: 1;
background: red;
display: flex;
flex-direction: row;
min-height: 30px;
}
.test {
display: block;
}
.footer {
background: green;
}
<div class="page">
<div class="header">Header</div>
<div class="container">
<div class="main">
Main
<div class="test">Test1<br />Test2<br/></div>
</div>
<div class="footer">Footer</div>
</div>
</div>
Just add flex: 1 0 auto to .main class. Flex properties are flex-grow, flex-shrink, and the flex-basis. So with 0 it is told to not shrink.
* {
padding: 0;
margin: 0;
font-size: 2rem;
}
.page {
display: flex;
flex-direction: column;
height: 100vh;
width: 100%;
background: yellow;
}
.container {
display: flex;
flex-direction: column;
flex: 1;
overflow: scroll;
}
.main {
flex: 1 0 auto;
background: red;
display: flex;
flex-direction: row;
min-height: 30px;
}
.test {
display: block;
}
.footer {
background: green;
}
<div class="page">
<div class="header">Header</div>
<div class="container">
<div class="main">
Main
<div class="test">Test1<br />Test2<br/></div>
</div>
<div class="footer">Footer</div>
</div>
</div>
I got it working. I needed to add a div with display: block; around my content and I added justify-content: space-between; to my container component. Little hacky but it works...
That's my final code:
* {
padding: 0;
margin: 0;
font-size: 2rem;
}
.page {
display: flex;
flex-direction: column;
height: 100vh;
width: 100%;
background: yellow;
}
.container {
display: flex;
flex-direction: column;
flex: 1;
justify-content: space-between;
overflow: scroll;
}
.block {
display: block;
}
.main {
background: red;
display: flex;
flex-direction: row;
}
.test {
display: block;
}
.footer {
background: green;
}
<div class="page">
<div class="header">Header</div>
<div class="container">
<div class="block">
<div class="main">
Main
<div class="test">Test1<br />Test2<br/></div>
</div>
</div>
<div class="footer">Footer</div>
</div>
</div>
In the example below, what I want is to have .inner-flexbox have flex-direction: row; when its child elements can fit on a single row, but switch to flex-direction: column; when they cannot. I don't think media queries are what I want here because I would be basing them on whether the viewport width is greater than or less than the width of all the <div>s in .inner-flexbox in a row plus the width of the <aside>. Basically, I don't want the items inside .inner-flexbox wrapping—I want them either all in one row, or all in one column.
(distilled example): I have a flexbox that contains two items. One is a "normal" element, the other is another flexbox.
.outer-wrapper
{
display:flex;
width: 100%;
height: auto;
background-color: gray;
flex-wrap: nowrap;
}
.inner-flexbox
{
display: flex;
flex-wrap: wrap;
flex-direction: row;
}
.inner-flexbox > div
{
width: 10rem;
height: 10rem;
background-color: salmon;
margin: 10px;
}
aside
{
background-color: blue;
width: 15rem;
height: 15rem;
}
<div class="outer-wrapper">
<div class="inner-flexbox">
<div>Block 1</div>
<div>Block 2</div>
<div>Block 3</div>
</div>
<aside><!-- Other content here --></aside>
</div>
Try This Code
.outer-wrapper {
display: flex;
width: 100%;
height: auto;
background-color: gray;
flex-wrap: nowrap;
}
.inner-flexbox {
width: 75%;
display: flex;
flex-wrap: wrap;
flex-direction: row;
flex-flow: row wrap;
justify-content: space-between;
}
.inner-flexbox>div {
width: 10rem;
height: 10rem;
background-color: salmon;
margin: 10px;
}
aside {
width: 25%;
background-color: blue;
width: 15rem;
height: 15rem;
float: right;
display: block;
}
<div class="outer-wrapper">
<div class="inner-flexbox">
<div>Block 1</div>
<div>Block 2</div>
<div>Block 3</div>
</div>
<aside>
<!-- Other content here -->
</aside>
</div>
In the end I resorted to scripting, as #LGSon suggested. I used jQuery to compare the total width of the inner flexbox to the width of the container minus the width of the item next to it.