I am trying to use flexbox to vertically center two elements along the blue line shown in the picture below.
The problem is that the second box and the text are part of one div and flexbox wants to align them like this:
By making the div position: relative
and the text position: absolute
I am able to accomplish my goal, except that this causes the entire container to exclude the text in calculating the height of the container:
How can I center these elements correctly while still allowing the container to have the height of all content in the container?
Desired Result:
Example of Problem: (While the boxes are centered, the container does not include the text, as shown by a blue border.)
.container {
display: flex;
align-items: center;
padding: 10px;
border: 4px solid #00aaff;
}
.big-box {
width: 200px;
height: 100px;
margin-right: 20px;
padding: 10px;
border: 4px solid black;
}
.small-box {
width: 150px;
height: 50px;
padding: 10px;
border: 4px solid black;
}
.group {
position: relative;
}
.group p {
position: absolute;
margin-top: 20px;
}
<div class="container">
<div class="big-box">
Lots of content...
</div>
<div class="group">
<div class="small-box">
Some content...
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
By using align-items: center we can vertically center all flex items to the parent container along the cross axis of the flex container. The nice aspect of flexbox is the styles apply to all children of our flex container. If we add two more elements they all stay centered within the parent select.
How to center a <div> using Flexbox property of CSS ? 1 We use the property of display set to flex i.e. display: flex; 2 Align items to center using align-items: center; 3 The last step is to set justify-content to center i.e. justify-content: center;
If you just want specific flex items to be centered vertically, you can set align-self on the items instead: arrr! yeehaw! If you want to put an element at the dead center of a page, it can be a little bit more tricky because flex items will only center vertically according to the height of their container.
With the layout superpowers of flexbox, you can align and justify your HTML elements perfectly within the center of its parent element. Centering elements vertically has always been a challenge in web design, until flexbox arrived on the scene. With flexbox it’s easy to center elements vertically in their parent element.
I only found a solution which uses JavaScript and grid. In principle The JS should work with flex, too, but I started with grid, because I thought it wouldn't be possible with flex to begin with.
{
// define some vars local to this block
// CSS selectors for the containers
const containerSelector = '.container';
const leftSelector = '.left-box';
const rightSelector = '.right-box';
// this function will recalculate the height of two grid boxes
const recalc = () => {
const containers = document.querySelectorAll(containerSelector);
for (let container of containers) {
const l = container.querySelector(`:scope > ${leftSelector} > *`).offsetHeight
const r = container.querySelector(`:scope > ${rightSelector} > *`).offsetHeight
const gap = parseInt(window.getComputedStyle(container).gridRowGap)
// +-----+ +-----+
// | | | c |
// | | +-----+ ------.
// | | }-- gap
// | | +-----+ ------´
// | l | | r |
// | | +-----+ ------.
// | | }-- gap
// | | +-----+ --.---´
// | | | c | }
// +-----+ +- - -| }------ text
// | | }
// +-----+ --´
// l = c + gap + r + gap + c
// l = 2 * c + 2 * gap + r
// l - r - 2 * gap = 2 * c
const c = (l - r - 2 * gap) / 2
container.style.gridTemplateRows = `${c}px auto ${c}px auto`
}
}
window.addEventListener('resize', recalc);
window.addEventListener('load', recalc);
recalc();
}
.container {
align-content: left;
border: 1px solid gold;
width: 50%;
margin: auto;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr auto 1fr auto;
grid-auto-rows: auto;
grid-gap: 1rem 50px;
padding: 25px;
grid-template-areas: "leftbox b" "leftbox rightbox" "leftbox mytextbox" "a mytextbox";
}
.container .left-box {
grid-area: leftbox;
background-color: green;
}
.container .right-box {
grid-area: rightbox;
background-color: orange;
}
.container .text-box {
grid-area: mytextbox;
background-color: yellow;
}
.container figure {
border: 1px solid;
margin: 0;
}
.container figure img {
display: block;
width: 100%;
max-width: 100%;
height: auto;
}
<div class="container">
<div class="left-box">
<figure>
<img src="http://picsum.photos/225/300?image=990" alt="">
<figcaption>Figure 1</figcaption>
</figure>
</div>
<div class="right-box">
<figure>
<img src="http://picsum.photos/225/100?image=991" alt="">
<figcaption>Figure 2</figcaption>
</figure>
</div>
<div class="text-box">Lorem ipsum dolor sit amet consectetur adipisicing elit. Est, cum porro quod unde neque doloribus excepturi odio nobis necessitatibus, nostrum labore id. Dolorem facere, quia nihil similique quis consectetur earum repudiandae non ut aperiam, dolore
cum, corporis ratione quaerat temporibus.<br> Lorem ipsum dolor sit, amet consectetur adipisicing elit. Corrupti quam impedit perspiciatis sit nulla officiis in, delectus adipisci aliquam dolores, ratione voluptates dolorem odio ab ducimus praesentium
omnis! Unde, at?<br>
</div>
</div>
Without the JS part, the left-box would be too big, because the 1fr
unit is too greedy (or the auto
rows are too relutant).
.container {
align-content: left;
border: 1px solid gold;
width: 50%;
margin: auto;
display: grid;
grid-template-columns: 1fr 1fr;
grid-template-rows: 1fr auto 1fr auto;
grid-auto-rows: auto;
grid-gap: 1rem 50px;
padding: 25px;
grid-template-areas: "leftbox b" "leftbox rightbox" "leftbox mytextbox" "a mytextbox";
}
.container .left-box {
grid-area: leftbox;
background-color: green;
}
.container .right-box {
grid-area: rightbox;
background-color: orange;
}
.container .text-box {
grid-area: mytextbox;
background-color: yellow;
}
.container figure {
border: 1px solid;
margin: 0;
}
.container figure img {
display: block;
width: 100%;
max-width: 100%;
height: auto;
}
<div class="container">
<div class="left-box">
<figure>
<img src="http://picsum.photos/225/300?image=990" alt="">
<figcaption>Figure 1</figcaption>
</figure>
</div>
<div class="right-box">
<figure>
<img src="http://picsum.photos/225/100?image=991" alt="">
<figcaption>Figure 2</figcaption>
</figure>
</div>
<div class="text-box">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Est, cum porro quod unde neque doloribus excepturi odio nobis necessitatibus, nostrum labore id. Dolorem facere, quia nihil similique quis consectetur earum repudiandae non ut aperiam, dolore cum, corporis ratione quaerat temporibus.<br> Lorem ipsum dolor sit, amet consectetur adipisicing elit. Corrupti quam impedit perspiciatis sit nulla officiis in, delectus adipisci aliquam dolores, ratione voluptates dolorem odio ab ducimus praesentium omnis! Unde, at?<br>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Est, cum porro quod unde neque doloribus excepturi odio nobis necessitatibus, nostrum labore id. Dolorem facere, quia nihil similique quis consectetur earum repudiandae non ut aperiam, dolore cum, corporis ratione quaerat temporibus.<br> Lorem ipsum dolor sit, amet consectetur adipisicing elit. Corrupti quam impedit perspiciatis sit nulla officiis in, delectus adipisci aliquam dolores, ratione voluptates dolorem odio ab ducimus praesentium omnis! Unde, at?<br>
</div>
</div>
I've created a flex
version as well
console.clear()
{
const containerSelector = '.container';
const leftColSelector = '.left-col';
const rightColSelector = '.right-col';
const leftSelector = '.left-box';
const rightSelector = '.right-box';
const rightSpacerSelector = '.right-spacer';
const recalc = () => {
const containers = document.querySelectorAll(containerSelector);
for (let container of containers) {
const l = container.querySelector(`:scope > ${leftColSelector} > ${leftSelector} > *`).offsetHeight;
const r = container.querySelector(`:scope > ${rightColSelector} > ${rightSelector} > *`).offsetHeight;
const s = container.querySelector(`:scope > ${rightColSelector} > ${rightSpacerSelector}`)
const c = (l - r) / 2
s.style.height = `${c}px`;
// container.style.gridTemplateRows = `${c}px auto ${c}px auto`
}
}
window.addEventListener('resize', recalc);
window.addEventListener('load', recalc);
recalc();
}
.container {
border: 1px solid gold;
width: 50%;
margin: auto;
display: flex;
flex-wrap: flex;
padding: 25px;
}
.container .left-col,
.container .right-col {
width: calc(50% - 25px);
}
.container .left-col {
margin-right: 25px;
}
.container .right-col {
margin-left: 25px;
}
.container .left-box {
background-color: green;
}
.container .right-box {
background-color: orange;
}
.container .text-box {
background-color: yellow;
}
.container figure {
border: 1px solid;
margin: 0;
}
.container figure img {
display: block;
width: 100%;
max-width: 100%;
height: auto;
}
<div class="container">
<div class="left-col">
<div class="left-box">
<figure>
<img src="http://picsum.photos/225/300?image=990" alt="">
<figcaption>Figure 1</figcaption>
</figure>
</div>
</div>
<div class="right-col">
<div class="right-spacer"></div>
<div class="right-box">
<figure>
<img src="http://picsum.photos/225/100?image=991" alt="">
<figcaption>Figure 2</figcaption>
</figure>
</div>
<div class="text-box">Lorem ipsum dolor sit amet consectetur adipisicing elit. Est, cum porro quod unde neque doloribus excepturi odio nobis necessitatibus, nostrum labore id. Dolorem facere, quia nihil similique quis consectetur earum repudiandae non ut aperiam, dolore
cum, corporis ratione quaerat temporibus.<br> Lorem ipsum dolor sit, amet consectetur adipisicing elit. Corrupti quam impedit perspiciatis sit nulla officiis in, delectus adipisci aliquam dolores, ratione voluptates dolorem odio ab ducimus praesentium
omnis! Unde, at?<br>
</div>
</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With