How can I have partially centered, partially bottom aligned content? - html

I have a HTML div (parent) that contains 3 children. Each of these children contain an image and a text. The image can be either small/medium/large and its height reflect the size. My goal is to make the images align to the center while the texts are aligned on the bottom. This is the starting point I had created:
https://codepen.io/giorgi-tediashvili/pen/KKwjrzr
#parent {
display: flex;
flex-direction: row;
align-items: stretch;
}
.smallImage {
height: 30px;
}
.mediumImage {
height: 70px;
}
.largeImage {
height: 110px;
}
.child {
padding: 10px;
}
<div id="parent">
<div class="child child1">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" class="smallImage" />
<br/>
<text>Small</text>
</div>
<div class="child child2">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" class="mediumImage" />
<br/>
<text>Medium</text>
</div>
<div class="child child3">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" class="largeImage" />
<br/>
<text>Large</text>
</div>
</div>
Screenshot:
And the Desired outcome:

You can try like below using flexbox as nested container:
#parent {
display: flex;
flex-direction: row;
}
.smallImage {
height: 30px;
}
.mediumImage {
height: 70px;
}
.largeImage {
height: 110px;
}
.child {
padding: 10px;
display:flex;
flex-direction:column;
}
img {
margin:auto;
}
span {
text-align:center;
}
<div id="parent">
<div class="child child1">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" class="smallImage" >
<span>Small</span>
</div>
<div class="child child2">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" class="mediumImage" >
<span>Medium</span>
</div>
<div class="child child3">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" class="largeImage" >
<span>Large</span>
</div>
</div>

I messed with the padding a little, I think it seems closer:
.parent {
display: flex;
flex-direction: row;
align-items: stretch;
}
.smallImage{
height: 30px;
padding-bottom: 30px;
padding-right: 10px;
}
.mediumImage{
height: 70px;
padding-bottom: 10px;
padding-right: 10px;
}
.largeImage{
height: 110px;
padding-top: 10px;
padding-right: 10px;
}
.child {
padding: 10px;
}
.v-center {
align-items: center;
}

I'd put the images and text in separate rows inside each column. The text row will collapse to the text height and you can vertically center the images.
.flex-h {
display: flex;
flex-direction: row;
align-items: stretch;
}
.flex-v {
display: flex;
flex-direction: column;
flex-grow: 1;
}
.flex-v :first-child {
flex: auto;
display: flex;
justify-content: center;
align-self: center;
}
.flex-v :last-child {
flex: none;
}
.smallImage {
height: 30px;
}
.mediumImage {
height: 70px;
}
.largeImage {
height: 110px;
}
.child {
padding: 10px;
}
<div class="flex-h">
<div class="flex-v">
<div class="child child1">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" class="smallImage" />
</div>
<div class="child child1">
<text>Small</text>
</div>
</div>
<div class="flex-v">
<div class="child child2">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" class="mediumImage" />
</div>
<div class="child child1">
<text>Medium</text>
</div>
</div>
<div class="flex-v">
<div class="child child3">
<img src="https://www.w3schools.com/images/w3schools_green.jpg" class="largeImage" />
</div>
<div class="child child1">
<text>Large</text>
</div>
</div>
</div>

Related

How to make bottom-border of two parallel divs align

I would like the lines at the bottom of each div/bottom border to align. When text on one side is longer than the other, the bottom border looks disjointed.
.one {
display: flex;
flex-direction: row;
justify-content: space-evenly;
margin-top: 5%;
}
.inner {
padding: 5px;
width: 100%;
}
.two {
padding: 5px;
}
.innerTxt {
width: 90%;
border-bottom: 2px solid blue;
}
<div class="one">
<div class="inner">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Wings</h4>
<p>Lorem Ipsum. This text is shorter</p>
</div>
</div>
<div class="two">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Other</h4>
<p>Some other text on this page that happens to be longer than the previous</p>
</div>
</div>
</div>
A height style can be applied to the <p> element if the content inside the <p> element is not dynamic.
.one {
display: flex;
flex-direction: row;
justify-content: space-evenly;
margin-top: 5%;
}
.inner {
padding: 5px;
width: 100%;
}
.two {
padding: 5px;
}
.innerTxt {
width: 90%;
border-bottom: 2px solid blue;
}
p {
height: 50px;
}
<div class = "one">
<div class="inner">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Wings</h4>
<p>Lorem Ipsum. This text is shorter</p>
</div>
</div>
<div class="two">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Other</h4>
<p>Some other text on this page that happens to be longer than the previous</p>
</div>
</div>
</div>
You could use an absolutely-positioned pseudo element to draw the border while maintaining the 90% width of innerTxt.
Because the flex elements are stretched vertically they'll be aligned at the bottom.
.one {
display: flex;
flex-direction: row;
justify-content: space-evenly;
margin-top: 5%;
}
.inner {
padding: 5px;
width: 100%;
}
.two {
padding: 5px;
}
.innerTxt {
width: 90%;
}
.one>* {
position: relative;
}
.one>*::after {
content: '';
position: absolute;
bottom: 0;
border-bottom: 2px solid blue;
display: block;
width: 90%;
}
<div class="one">
<div class="inner">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Wings</h4>
<p>Lorem Ipsum. This text is shorter</p>
</div>
</div>
<div class="two">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Other</h4>
<p>Some other text on this page that happens to be longer than the previous</p>
</div>
</div>
</div>
try adding to the .inner div align-self: flex-end;
.inner{
align-self: flex-end;
}
or to the parent div :
.one {
align-items: flex-end;
}

How to get nested css flex to have the right width after wrap in this setup?

I have this mockup, there are some nested containers. some of the link-class have multiple elements (par and ref) and I want them to display next to each other if there's space, but responsively move them below each other when total width gets smaller.
It works somewhat, but I expect (want) the link-element containing two childs to return to the same width as the link-element with one single child as it wraps.
For some reason, it remains wider than the single-child ones.
Any hints appreciated!
Code:
let name = 'world';
:global(body) {
margin: 0;
padding: 0
}
.main {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
background-color: gray;
}
.Container {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: lightblue;
padding: 3px
}
.linkContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 3px;
background-color: salmon;
}
.par {
width: 80vw;
max-width: 300px;
background-color: red
}
.links {
display: flex;
flex-flow: row wrap;
padding: 3px;
background-color: orange
}
.ref {
background-color: olive;
width: 30vw;
max-width: 100px
}
.item {
width: 80vw;
max-width: 300px;
background-color: steelblue
}
<div class="main">
<div class="Container">
<div class="item">
header
</div>
<div class="linkContainer">
<div class="links">
<div class="par">
some text
</div>
</div>
<div class="links">
<div class="par">
some text
</div>
</div>
<div class="links">
<div class="par">
some text
</div>
</div>
<div class="Container">
<div class="item">
another header
</div>
<div class="linkContainer">
<div class="links">
<div class="par">
some text
</div>
<div class="ref">
a ref
</div>
</div>
<div class="links">
<div class="par">
some text
</div>
</div>
<div class="links">
<div class="par">
some text
</div>
<div class="ref">
a ref
</div>
</div>
</div>
</div>
</div>
</div>
</div>
you could simply add a max-width:300px; to .links and have the box in size but then you couldn't have the desired stacking effect you wanted so i went a bit further and with the help of css variables and media queries and adding a class .single to single .pars which didn't have a .ref after them, i came up with this:
:root {
--ref-size: 100px;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.main {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
background-color: gray;
}
.Container {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
background-color: lightblue;
padding: 3px
}
.links {
min-width: 300px;
display: flex;
flex-flow: row wrap;
padding: 3px;
background-color: orange;
}
.par {
width: calc(100% - var(--ref-size));
background-color: red;
}
.ref {
background-color: olive;
width: var(--ref-size);
}
.item {
width: 80vw;
max-width: 300px;
background-color: steelblue
}
#media all and (max-width:300px){
.par{
width: 100%;
}
}
#media all and (min-width: 300px){
.par.single{
width: 100%;
}
}
<div class="main">
<div class="Container">
<div class="item links">
header
</div>
<div class="links">
<div class="par single">
some text
</div>
</div>
<div class="links">
<div class="par single">
some text
</div>
</div>
<div class="links">
<div class="par single">
some text
</div>
</div>
<div class="item links">
another header
</div>
<div class="links">
<div class="par">
some text
</div>
<div class="ref">
a ref
</div>
</div>
<div class="links">
<div class="par single">
some text
</div>
</div>
<div class="links">
<div class="par">
some text
</div>
<div class="ref">
a ref
</div>
</div>
</div>
</div>

Why doesn't flex direction column with align-items=center center image properly

I stumbled upon an issue with image centering within a flexbox with direction:column.
Imagine you have two elements within a flexbox, where the first one contains an image:
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
.image-container {
flex: 1;
align-self: center;
.img {
height: 100%;
}
}
.another-flex-child {
flex: none;
background-color: red;
}
}
I would expect the image to be center horizontally within the div, but it appears the left border of the image is exactly at the center of the div.
When I replace the image with another div which contains some text it is placed as expected.
Can anybody explain to me whats happening there?
Checkout this fiddle
Because your <div> that contains the image (and has align-self: center on it) is by default a block-level element, and has a width of 100% by default. As such, it is constrained in relation to the parent.
In order to have your image centered correctly, you'll want to add display: contents with:
container .image-container {
display: inline;
}
This can be seen in the following:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.container .image-container {
flex: 1;
align-self: center;
display: contents;
}
.container .image-container .img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
The issue is that you are using an SVG with no intrinsic dimension and only an intrinsic ratio so it's like your image has a width equal to 0 which make its centred container with a width equal to 0, too.
Here is before using height:100%
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
}
.img {
/*height: 100%;*/
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
After setting height:100% the image will fill all the space and will keep its ratio but you will have an overflow because the browser will not go back to calculate the width of the container again:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" >
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
To avoid this give the image a width and make sure to add min-height:0 to the container to allow it to shrink
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" width="250">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
If you were initially using an image with intrinsic dimension you won't have this issue and you don't need to define a width. You will only need to add min-height:0 to avoid the overflow:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/400/400">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
Note that the above doesn't work the same way in Firefox and you will need to add text-aling:center to make sure it works the same everywhere:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
text-align:center;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/400/400">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
You will notice that the difference is related to the width calculation of the container which a bit complex due to the use of height:100%
Things may get worse if the size of the image is very small:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
text-align:center;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/50/50">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
In Firefox text-align:center will do nothing and you may need a nested flexbox container
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
justify-content:center;
border:2px solid blue;
display:flex;
min-height:0;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://picsum.photos/id/1/50/50">
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
The below is almost the same issue you were having with the initial SVG that can fixed with this same code but it won't remove the overflow:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
display:flex;
justify-content:center;
border:2px solid blue;
}
.img {
height: 100%;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" >
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
Another intresting thing to note is that your initial code may work fine if you add height:100% to the container making the calculation of the nested height easier:
.container {
height: 300px;
background-color: green;
display: flex;
flex-direction: column;
}
.image-container {
flex: 1;
align-self: center;
border:2px solid blue;
box-sizing:border-box;
height:100%;
}
.img {
height: 100%;
display:block;
}
.another-flex-child {
flex: none;
background-color: red;
}
.spacer {
height: 20px;
}
<div class="container">
<div class="image-container">
<img class="img" src="https://interactive-examples.mdn.mozilla.net/media/examples/firefox-logo.svg" >
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
<div class="spacer"></div>
<div class="container">
<div class="image-container">
<div>Properly centered content</div>
</div>
<div class="another-flex-child">
Random content here
</div>
</div>
Add the justify-content like below:
.image-container {
flex: 1;
align-self: center;
justify-content:center;
}
it should works

Nested flexbox height issue in IE

I have nested flexboxes with some images inside, it looks good in Chrome, but in IE you can see the borders on the flex-item-wrapper are not flush against the bottom of the image. By the way, in the layout I will sometimes have several flex-row with many pictures.
.flex-list {
display: flex;
flex-direction: column;
}
.flex-row {
display: flex;
}
.flex-item-wrapper {
width: 100%;
border: 1px solid green;
}
.flex-item {
height: 100%;
width: 100%;
border: 1px solid blue;
}
.picture {
width: 100%;
}
<div class="flex-list">
<div class="flex-row">
<div class="flex-item-wrapper">
<div class="flex-item">
<a href='#'>
<img class="picture" src="http://www.picgifs.com/clip-art/cartoons/super-mario/clip-art-super-mario-832109.jpg" alt="">
</a>
</div>
</div>
<div class="flex-item-wrapper"></div>
<div class="flex-item-wrapper"></div>
<div class="flex-item-wrapper"></div>
</div>
</div>
This seems to be working:
.flex-row {
display: flex;
flex: 0 0 auto; /*added*/
}
or
.flex-row {
display: flex;
height: 100%; /*added*/
}
See simplified demo:
.flex-list {
display: flex;
flex-direction: column;
}
.flex-row {
display: flex;
flex: 0 0 auto;
}
.flex-item {
flex: 1;
border: 1px solid blue;
}
.picture {
width: 100%;
height: auto;
}
<div class="flex-list">
<div class="flex-row">
<div class="flex-item">
<a href='#'>
<img class="picture" src="http://www.picgifs.com/clip-art/cartoons/super-mario/clip-art-super-mario-832109.jpg" alt="">
</a>
</div>
<div class="flex-item"></div>
<div class="flex-item"></div>
<div class="flex-item"></div>
</div>
</div>
The problem seems due to the nesting flexbox. This fixes it:
.flex-row {
width: 100%;
align-self: flex-start;
}
.flex-list {
display: flex;
flex-direction: column;
}
.flex-row {
display: flex;
width: 100%;
align-self: flex-start;
}
.flex-item-wrapper {
width: 100%;
border: 1px solid green;
}
.flex-item {
height: 100%;
width: 100%;
border: 1px solid blue;
}
.picture {
width: 100%;
}
<div>
<div class="flex-list">
<div class="flex-row">
<div class="flex-item-wrapper">
<div class="flex-item">
<a href='#'>
<img class="picture" src="http://www.picgifs.com/clip-art/cartoons/super-mario/clip-art-super-mario-832109.jpg" alt="">
</a>
</div>
</div>
<div class="flex-item-wrapper"></div>
<div class="flex-item-wrapper"></div>
<div class="flex-item-wrapper"></div>
</div>
</div>
<div></div>
</div>

Horizontal centering of 3 flexbox items of the same width

I have been trying to horizontally center these 3 items using flexbox, yet without success. They all need to be of the same width.
HTML:
<div id="contact_flex_container">
<div id="fb">
<img src="img/contact/fb.png" class="contact_img">
<h3>Title1</h3>
</div>
<div id="yt">
<img src="img/contact/yt.png" class="contact_img">
<h3>Title2</h3>
</div>
<div id="mail">
<img src="img/contact/mail.png" class="contact_img">
<h3>Title3</h3>
</div>
</div>
CSS:
#contact_flex_container {
display: flex;
flex-flow: row wrap;
text-align: center;
background-color: red;
width: auto;
justify-content: space-around;
}
.contact_img {
width: 40px;
height: 40px;
}
#fb {
flex-basis: 0;
flex-grow: 1;
}
#yt {
flex-basis: 0;
flex-grow: 1;
}
#mail {
flex-basis: 0;
flex-grow: 1;
}
I have also tried setting margin-left and right to auto for each child, justify-content to center for the container, even combined with fixed width of the container in pixels, yet nothing seems to work. To be more specific, justify-content does not seem to work at all here, whatever value I put there. What am I missing or doing wrong?
The flex properties you are assigning to the flex-items make them all as large as they can be (in this case 33% of the container).
Just remove them, then change the parent to justify-content:center.
#contact_flex_container {
display: flex;
flex-flow: row wrap;
text-align: center;
background-color: red;
width: auto;
justify-content: center
}
.contact_img {
width: 40px;
height: 40px;
}
#fb {} #yt {} #mail {}
<div id="contact_flex_container">
<div id="fb">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Title1</h3>
</div>
<div id="yt">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Title2</h3>
</div>
<div id="mail">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Title3</h3>
</div>
</div>
Alternative, based on the expanded requirement.
An extra wrapper is required which should be inline-flex.
#contact_flex_container {
display: flex;
flex-flow: row wrap;
text-align: center;
background-color: red;
width: auto;
justify-content: center
}
.wrap {
display: inline-flex;
}
.wrap > div {
flex: 1;
border: 1px solid grey;
}
.contact_img {
width: 40px;
height: 40px;
}
<div id="contact_flex_container">
<div class="wrap">
<div id="fb">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Lorem ipsum dolor sit.</h3>
</div>
<div id="yt">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Lorem ipsum.</h3>
</div>
<div id="mail">
<img src="http://lorempixel.com/image_output/abstract-q-c-50-50-5.jpg" class="contact_img">
<h3>Lorem</h3>
</div>
</div>