2x2 Grid equal height despite box content amount - html

I am trying to create a 2x2 grid where the height of the four individual boxes (red, blue, green, yellow) are all equal despite how much content they contain.
#rowTwo {
background-color: pink;
min-height: 25%;
display: flex;
flex-direction: column;
align-items: center;
}
#grid2x2 {
display: flex;
flex-direction: row;
flex-wrap: wrap;
background-color: orange;
width: 80%;
justify-content: center;
}
.box {
display: flex;
flex-basis: calc(50% - 20px);
margin: 5px;
justify-content: center;
padding-top: 5%;
overflow: hidden;
}
<div id={styles.rowTwo}>
<Heading title="My Title"/>
<div id={styles.grid2x2}>
<div id={styles.boxOne} className={styles.box}>
<DescriptionBoxItemWithHeading item={this.state.sectionTwoItems[0]}/>
</div>
<div id={styles.boxTwo} className={styles.box}>
<DescriptionBoxItemWithHeading item={this.state.sectionTwoItems[1]}/>
</div>
<div id={styles.boxThree} className={styles.box}>
<DescriptionBoxItemWithHeading item={this.state.sectionTwoItems[2]}/>
</div>
<div id={styles.boxFour} className={styles.box}>
<DescriptionBoxItemWithHeading item={this.state.sectionTwoItems[3]}/>
</div>
</div>
</div>
The issue I face is that a box expands to the height of the largest content in a row.
Here is an image outlining my problem:
Would anyone know how I could achieve this?

You can do this in CSS by using padding-top to add the height and then absolute positioning to draw your content on top of this padding.
Here is an example: https://codepen.io/anon/pen/xpwooz
#grid2x2 {
display: flex;
flex-wrap: wrap;
background-color: orange;
}
.box {
display: flex;
flex-basis: calc(50% - 20px);
margin: 5px;
justify-content: center;
overflow: hidden;
background: red;
padding-top: 100px;
position: relative;
}
.content {
position: absolute;
background: green;
top: 0;
width: 100%;
}
The problem is you can't change this height dynamically based on the content height. You can either set it to a fixed size or set it to a percentage and have it change size based on it's parents width. I think you'll need to use javascript if you want the height to change based on the largest content element.

Related

wrap a flexbox to allow maximum child scaling, while preserving aspect ratios

I'd like to display images in a row, using a flexbox container. In order to play nicely with the other elements onscreen, the container must have a height of exactly 30vh.
The images inside should be scaled as large as possible, while keeping their aspect ratio and not overflowing the row.
The problem is wrapping. On a very wide screen, the images should all be in one row.
But on a tall screen, the row should wrap automatically. This is something I can't manage to do. Either the elements in the flexbox shrink to fit, or they wrap around. But I can't get the to wrap and scale at the same time.
Is it possible to do this with flexbox?
Here's my approach so far. I'm using scss:
.App {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
background-color: yellow;
}
.row {
display: flex;
flex-direction: row;
justify-content: center;
flex-wrap: wrap;
background-color: blue;
height: 30vh;
}
.item {
// make items grow
flex-basis: 0;
flex: 1;
// only as large as necessary
width: max-content;
height: max-content;
// align image and text
display: flex;
flex-direction: column;
align-items: center;
// just a visual helper
background-color: red;
border-style: solid;
}
img {
// make image shrink to fit
min-width: 0;
min-height: 0;
// contain in parent
max-height: 100%;
max-width: 100%;
// keep aspect ratio
width: auto;
height: auto;
}
A minimal fiddle: https://jsfiddle.net/89jekw4p/8/
Here's a screenshot that illustrates the problem. These images could be much larger, if the row would wrap around:
I might have an idea what is the solution to your problem. First of all, I removed
// make image shrink to fit min-width: 0; , min-height: 0; // contain in parent max-height: 100%; max-width: 100%; // keep aspect ratio width: auto; height: auto;. Because when you have written repeatedly browser only sees what's written on the end of the line so the browser only seeing the width: auto; height: auto; so that is why images keep getting smaller and flex-wrap: wrap does not work. But right now it will work. I hope I could explain it.
<div class="App">
<div class="row">
<div class="item">
<img src="https://www.fillmurray.com/200/300"></img>
</div>
<div class="item">
<img src="https://www.fillmurray.com/200/300"></img>
</div>
<div class="item">
<img src="https://www.fillmurray.com/200/300"></img>
</div>
<div class="item">
<img src="https://www.fillmurray.com/200/300"></img>
</div>
<div class="item">
<img src="https://www.fillmurray.com/200/300"></img>
</div>
</div>
</div>
.App {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-height: 100vh;
background-color: yellow;
}
.row {
display: flex;
flex-direction: row;
justify-content: center;
flex-wrap: wrap;
flex: 0 0 100%;
background-color: blue;
height: 30vh;
}
.item {
height: 30vh;
width: auto;
}
img {
max-width: 100%;
height: 30vh;
}

Charts not using available space with Flex

I have a problem with Flex for Google Charts. Div with charts is not using available height. Am I missing something? (colors and blue borders are for development purpose so I'm sorry for that...)
CSS
.pc-metrics-chart {
display: flex;
flex-direction: column;
width: 100%;
height: 65%;
overflow: hidden;
background-color: var(--yellow);
}
.metric-ch{
height: auto;
flex : 1;
justify-content: stretch;
align-items: flex-end;
position: relative;
background-color: var(--success);
}
.ManagementCharts {
flex: 1;
overflow: hidden;
}
HTML
<div class="pc-metrics-chart" id="pc-metrics-chart-proj">
<div class="metric-ch">
<div id="totalProjectChart1" class="ManagementCharts">
</div>
</div>
</div>
I was trying to play with the position, alignments, height of the chart as well, but I'm using it's auto height and I thought that Flex will fill available space under the chart:
It is possible to use height property and set it to 100% to fill the remain space:
body {
margin: 0;
}
.pc-metrics-chart {
display: flex;
flex-direction: column;
width: 100%;
height: 100vh;
overflow: hidden;
background-color: yellow;
}
.metric-ch{
height: auto;
flex : 1;
justify-content: stretch;
align-items: flex-end;
position: relative;
background-color: lightgreen;
}
.ManagementCharts {
flex: 1;
overflow: hidden;
background-color: red;
height: 100%;
}
<div class="pc-metrics-chart" id="pc-metrics-chart-proj">
<div class="metric-ch">
<div id="totalProjectChart1" class="ManagementCharts">
Here should be chart placed
</div>
</div>
</div>

Display: flex element wont grow vertically within parent

I have a webpage where I want to center one of the pages both vertically and horizontally, like that:
<main>
<div>
This has to be centered both vertically and horizontally.
</div>
</main>
I can't change display of main as it's widely used for all the pages, and using flex there breaks way too much stuff.
I assumed this should work but it does not, because div does not grow in height:
main {
min-height: 1000px;
border: solid 1px red;
}
div {
display: flex;
align-items: center;
justify-content: center;
align-content: stretch;
flex-grow: 1;
}
I'd rather not do position: absolute; top: 0; right: 0; bottom: 0; left: 0;.
Any hints how can I stretch my div to fill main? Why wouldn't it work out of the box, can't flex simply grow within elements with block/inline-block displays?
https://jsfiddle.net/wcu6fnz5/
It might helps you.
/* I cannot edit main, there are 100s of pages based on it, cant change its display etc. */
main {
min-height: 200px;
border: solid 1px red;
}
div {
display: flex;
min-height: inherit;
justify-content: center;
align-items: center;
}
<main>
<div>
<span>This has to be centered both vertically and horizontally.</span>
</div>
</main>
The thing about flexbox is that you should focus on instructing the parent, not the child.
In your example, justify-content and display: flex should be in the parent. You could also use flex-direction: column to tell the browser you want the child to grow vertically.
You could also use flex: 1 as a shorthand for flex-grow. This way, the child doesn't even need display: flex.
main {
min-height: 1000px;
border: solid 1px red;
display: flex;
flex-direction: column;
justify-content: stretch;
}
div {
flex: 1;
}
Update
To achieve what you mentioned in the comments, why don't you try this:
main {
min-height: 1000px;
border: solid 1px red;
}
section {
height: 1000px;
width: 100px;
background: gainsboro;
/* important stuff */
display: flex;
flex-direction: column;
justify-content: stretch;
}
div {
flex: 1;
width: 40px;
background: aquamarine;
}
Those sizes and colors are only for you to see the results.

Center one flex item and bottom-align another [duplicate]

This question already has answers here:
Center and bottom-align flex items
(3 answers)
Closed 5 years ago.
I'm trying to get one flex item to be centered vertically and horizontally.
I'd like for some text to be fixed to the bottom of the flex container.
margin-top:auto on the text just shoves the inner box to the top. Ideas?
.container {
background: lightblue;
width: 300px;
height: 300px;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
padding: 10px;
}
.container .box {
background: goldenrod;
height: 30px;
width: 30px;
}
<div class="container">
<div class="box"></div>
<span>Text</span>
</div>
Here's the codepen.
Try the below instead:
.box {
background:goldenrod;
height: 30px;
width: 30px;
margin: auto;
}
Here is one way of doing it.
Add position: relative to your .container CSS rule, and then use absolute positioning on .box to position the span to the bottom of the parent container.
You can center the text by allowing .box to have 100% width and then using text-align: center.
.container {
background: lightblue;
width: 300px;
height: 300px;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
padding: 10px;
position: relative;
}
.box {
background: goldenrod;
height: 30px;
width: 30px;
}
span {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
text-align: center;
}
<div class="container">
<div class="box"></div>
<span>Text</span>
</div>
Since flexbox alignment involves the distribution of free space in the container, margin-top: auto won't work in this case because there's no counterweight on the other side.
Therefore, one method for centering the box and bottom-aligning the text involves creating a duplicate of the text element and placing it on the opposite side of the box. This will create a counterweight.
With equal balance on both ends, flex alignment properties (including auto margins) can work.
In this case, even justify-content: space-between would work.
Of course, you'll need to apply visibility: hidden to the duplicate element.
.container {
background: lightblue;
width: 300px;
height: 300px;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
padding: 10px;
}
.box {
background: goldenrod;
height: 30px;
width: 30px;
margin: auto 0; /* or instead use justify-content: space-between on .container */
}
span:first-child {
visibility: hidden;
}
<div class="container">
<span>Text</span>
<div class="box"></div>
<span>Text</span>
</div>
OR, instead of a duplicate element, use a pseudo-element.
A less intrusive and more semantically proper method would use a pseudo-element as the duplicate. However, for this method to work, you would need to know the height of the actual element, because you would need to match it precisely.
Something like this will work to create equal balance:
.container::before {
content: "";
height: 15px; /* must match actual element's height */
}
.container {
background: lightblue;
width: 300px;
height: 300px;
display: flex;
justify-content: space-between;
flex-direction: column;
align-items: center;
padding: 10px;
}
.box {
background: goldenrod;
height: 30px;
width: 30px;
}
span {
height: 15px;
}
.container::before {
content: "";
height: 15px;
}
<div class="container">
<div class="box"></div>
<span>Text</span>
</div>

Divs with fixed and dynamic width and vertically centered image

I have the following HTML
<div class="parent">
<div class="left-colum">Some paragraphs of text</div>
<div class="right-column"><img src="image.jpg"></div>
</div>
The right-column has the width of the image, but since it holds different size images its width is unknown. I want the left-column to take whatever is needed but with a max-width of 150px. I also want the image in the right-column centered vertically.
In the end it should look like the example below, but I have a hard time time getting this together. How would I do this?
edit: I have the following CSS, but the right-column isn't at 100% height so I can't start trying to vertically center the image yet:
.parent{
position: relative;
height: 100%;
}
.left-colum{
float: left;
max-width: 150px;
}
.right-column{
float: right;
height: 100%;
}
You could use nested flexbox see the comments inline.
body {
margin: 0;
}
.parent {
display: flex;
height: 100vh; /*viewport height*/
}
.left-column {
background: pink;
max-width: 150px;
}
.right-column {
background: gold;
flex: 1; /*expand*/
display: flex;
justify-content: center; /*center x*/
align-items: center; /*center y*/
}
<div class="parent">
<div class="left-column">Some paragraphs of text</div>
<div class="right-column">
<img src="//dummyimage.com/100">
</div>
</div>
Use flex display on columns and set display:flex; align-items:center; justify-content: center on right div and max-width: 150px; on left div. Also be aware of vendor prefixes for browsers in order to properly use flex property.
.parent {
display: flex;
align-items: center;
justify-content: space-between;
}
.left-column {
max-width: 150px;
display: flex;
}
.right-column {
display: flex;
justify-content: center;
align-items: center;
display:center;
}