Nested Flex container not growing with padding - css

I've built a row layout with Flexbox and within each row (.card), there are three columns, the last (.card-links) of which is also a Flex container. When these three columns stack as rows on mobile, the last doesn't grow with its content + padding and its height is only its padding.
I've found two workarounds where I can set it as margin instead, or display it as a block on mobile, but I'd really like to keep using padding as I have everywhere else and understand why this is happening.
HTML structure:
<div class="card">
<div class="card-img four-three-img">
<img src="" alt="">
</div>
<div class="card-info">
<div class="event-headings">
<h1>Heading</h1>
<h2>Subheading</h2>
</div>
<p>
</p>
<p>Text</p>
</div>
<div class="card-links">
<div class="button-cont">
<a class="pass-button button" href="" target="_blank" role="button">Button Text</a>
</div>
</div>
</div>
Relevant CSS:
.card {
display: flex;
flex-direction: column;
}
.card-img,
.card-info,
.card-links {
flex-basis: 33.3%;
position: relative;
padding: 15px;
}
.card-info {
flex-basis: 40%;
}
.card-links {
display: flex;
justify-content: center;
align-items: center;
flex-basis: 26.7%
}
#media screen and (max-width: 768px) {
.card-links {
padding: 15px 15px 45px;
}
}

Related

CSS image as large as possible within square with caption no gap

I'm 99% sure about this but thought i'd ask to see if anyone knew of any clever solutions.
Basically I wish to place an image in a 1/1 aspect containing element, and then for that image to be as as as it possibly can be, eg, landscape images always touch the left and right sides and portrait ones touch the top and bottom.
I then want a line of caption text underneath the image.
My question is, is there any way to get that size of image but without (for landscape images) the large gap between the photo and the caption?
My example image below shows the problem (please note the image is not full left to right edge here like I want).
Anyone know of any clever options to achieve this?
<figure class="photo-1 landscape">
<div class="image-wrapper gallery">
<a href="https://farm66.staticflickr.com/65535/48808899778_bb1d4d1272_b.jpg" data-pswp-width="4032" data-pswp-height="3024" target="_blank">
<img src="https://farm66.staticflickr.com/65535/48808899778_bb1d4d1272_m.jpg">
</a>
</div>
<figcaption>Hersheypark</figcaption>
</figure>
figure {
display: flex;
flex-direction: column;
gap: 0.5rem;
.image-wrapper {
aspect-ratio: 1/1;
}
a {
display: block;
}
img {
display: block;
max-width: 100%;
max-height: 100%;
}
&.landscape {
a {
min-width: 100%;
}
img {
width: 100%;
}
}
&.portrait {
a {
min-height: 100%;
}
img {
height: 100%;
}
}
figcaption {
text-align: center;
color: hsl(var(--color-secondary));
font-size: var(--fs--1);
}
}
This is what I got so far.
body {
background-color: #F8F9F9;
}
.container {
display: flex;
gap: 20px;
}
.card {
display: flex;
flex-direction: column;
flex-basis: 0;
flex-grow: 1;
gap: 10px;
}
.image {
display: flex;
align-items: center;
background-color: #ffffff;
overflow: hidden;
}
.image.hor {
flex-direction: row;
}
.image.ver {
flex-direction: column;
aspect-ratio: 1/1;
}
.image img {
flex-grow: 1;
max-width: 100%;
max-height: 100%;
}
.caption {
padding: 5px 10px;
font-size: 14px;
text-align: center;
background-color: #ffffff;
}
<div class="container">
<div class="card">
<div class="image hor">
<img src="https://dummyimage.com/100x50/000/fff" />
</div>
<div class="caption">
Landscape image (small)
</div>
</div>
<div class="card">
<div class="image hor">
<img src="https://dummyimage.com/1000x500/000/fff" />
</div>
<div class="caption">
Landscape image (large)
</div>
</div>
<div class="card">
<div class="image ver">
<img src="https://dummyimage.com/50x100/000/fff" />
</div>
<div class="caption">
Portrait image (small)
</div>
</div>
<div class="card">
<div class="image ver">
<img src="https://dummyimage.com/500x1000/000/fff" />
</div>
<div class="caption">
Portrait image (large)
</div>
</div>
</div>

Flexbox - image columns with fixed margins: how to get even image widths

I have a design with images in columns with a fixed margin (or gap) between them.
Right now the columns have margins, and because the total margin is different for each column (since there is no left margin on the first column and no right margin on the last), the width of each column image becomes different, causing the height to be different on the middle images.
I tried to divide the margin so that each column uses the same total amount of margin (which seems instinctively over complicated) . I can get that to work, but it doesn't work for 3 columns. You can't make three columns use the same amount of margin I think.
I know there is some "gap" property in css grid, but how do I solve it in flexbox?
See my example code here: example
<template>
<div id="app">
<div class="row">
<div class="col-3">
<div>
<img
src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
/>
</div>
</div>
<div class="col-3">
<div>
<img
src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
/>
</div>
</div>
<div class="col-3">
<div>
<img
src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
/>
</div>
</div>
<div class="col-3">
<div>
<img
src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
/>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "App",
components: {},
};
</script>
<style lang="scss">
#app {
margin: 0 auto;
width: 800px;
border: 3px solid orange;
}
.row {
display: flex;
box-sizing: border-box;
display: flex;
flex-grow: 0;
flex-shrink: 1;
flex-direction: row;
flex-wrap: wrap;
img {
width: 100%;
object-fit: cover;
}
}
.col-3 {
flex: 0 1 25%;
max-width: 25%;
/* width:25%; */
> div {
/* margin-right:25px; */
}
&:first-child > div {
margin-right: 12.5px;
}
&:nth-child(2) > div {
margin-right: 12.5px;
margin-left: 12.5px;
}
&:nth-child(3) > div {
margin-right: 12.5px;
margin-left: 12.5px;
}
&:last-child > div {
margin-left: 12.5px;
}
}
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Update: I realise now that you're looking for a solution using flex rather than css grid. The other answer provides some options there. If you do want to use grid though this approach is handy as your widths will be automatically calculated with whatever gap you choose.
Use display:grid, and set your container to have four columns with one fractional unit for each column, and a column-gap of the gap you want.
The gap below the image is caused because by default images are inline elements, so they sit with the baseline of text. If you set your images to display:block the gap will disappear.
.row {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-column-gap: 12px;
column-gap: 12px;
border:3px solid yellow;
}
.col-3 {
width: 100%;
}
.col-3 img {
display: block;
width: 100%;
object-fit: cover;
}
<div class="row">
<div class="col-3">
<img src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80" />
</div>
<div class="col-3">
<img src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80" />
</div>
<div class="col-3">
<img src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80" />
</div>
<div class="col-3">
<img src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80" />
</div>
</div>
I have written the code using flexbox and made a little change to your HTML code
<template>
<div id="app">
<div class="row">
<div>
<img
src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
/>
</div>
<div>
<img
src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
/>
</div>
<div>
<img
src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
/>
</div>
<div>
<img
src="https://images.unsplash.com/photo-1633357337538-83612701c7a9?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1470&q=80"
/>
</div>
</div>
</div>
</template>
<style lang="scss">
body {
margin: 0;
.row {
display: flex;
width: 100%;
justify-content: space-between;
div {
padding: 0 10px;
&:nth-child(1) {
padding-left: 0;
}
&:nth-last-child(1) {
padding-right: 0;
}
img {
width: 100%;
}
}
}
}
</style>
Flexbox does have a gap property that will space your items evenly and won't create empty spaces on the right or left. But, based on the code sample you shared, I think your issue is a combination of a couple of things:
Your middle two containers are smaller than your outer two containers because of their extra margin
Your images are set to take the full width of their containers
Because the middle two containers are smaller—and the images are preserving their aspect ratio—you get images that are both narrower and shorter.
If you strip everything down to just using gap, I think you'll be a lot closer to what you're trying to accomplish:
.flexbox {
background-color: #ace;
border: 3px solid orange;
box-sizing: border-box;
display: flex;
flex-flow: row nowrap;
gap: 8px;
width: 800px;
}
.container {
flex: 0 1 25%;
margin: 0;
max-width: 25%;
}
img.full-width {
width: 100%
}
<div class="flexbox">
<div class="container">
<img class="full-width" src="https://picsum.photos/300/200" />
</div>
<div class="container">
<img class="full-width" src="https://picsum.photos/300/200" />
</div>
<div class="container">
<img class="full-width" src="https://picsum.photos/300/200" />
</div>
<div class="container">
<img class="full-width" src="https://picsum.photos/300/200" />
</div>
</div>

flexbox height adjust to content

I use a "full design" flexbox.
I have a weird issue : I have a container that takes all the remaining space and I want in this container that the child, which is also flexbox, to have their height adjust to their content.
Here is the issue:
body, html {
width:100%;
height:100%;
display:flex;
}
.container {
display:flex;
flex:1;
flex-wrap:wrap;
}
.icon {
width:10vh;
margin:10px;
display:flex;
flex-direction:column;
}
.img {
width:10vh;
height:10vh;
display:flex;
align-items:center;
justify-content:center;
background-color:red;
}
.text {
text-align:center;
}
<div class="container">
<div class="icon">
<div class="img">
</div>
<div class="text">
action 1
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 2
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 3
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 4
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 5
</div>
</div>
</div>
As you can see, the icon takes the full height of the container : in fact, I don't want to specify a height because I don't know the text length and really want that, if the content is huge, the icon takes the height of its content ( don't want to cut the text). Moreover, if the page is resized, I really want the icon to be aligned (like on smartphone).
Also, I don't understand why the icon takes the height of its parent and not its content because I didn't specify "flex:1" on it. I assume that the default behaviour it's to fit the content size, but this seems not to be working.
image of the issue
.icon's are flex-column which makes .img's stretch by default unless .icon's have align-items. The reason why I didn't apply align-items to .icon's is because other nested flex-containers/flex-items started collapsing. Instead of adjusting down through the hierarchy, I went up and adjusted .container instead.
The relevant CSS:
.container {
display: flex;
flex: 1; /* If you remove this .container will shrink to wrap around .icon's */
flex-wrap: wrap;
justify-content: center; /* This centers .icon's along a horizontal axis. */
align-items: baseline; /* This aligns .icon's along a common baseline vertically. */
outline: 3px dashed blue; /* To show the size of .container */
}
.icon {
width: 10vh;
margin: 10px;
display: flex;
flex-direction: column;
outline: 1px dashed red; /* To show the size of .icon */
}
body,
html {
width: 100%;
height: 100%;
display: flex;
}
.container {
display: flex;
flex: 1;
flex-wrap: wrap;
justify-content: space-between;
align-items: baseline;
align-content: flex-start;
outline: 3px dashed blue;
}
.icon {
width: 10vh;
margin: 10px;
display: flex;
flex-direction: column;
outline: 1px dashed red;
}
.img {
width: 10vh;
height: 10vh;
display: flex;
align-items: center;
justify-content: center;
background-color: red;
}
.text {
text-align: center;
}
<div class="container">
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 1
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 2
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 3
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 4
</div>
</div>
<div class="icon">
<div class="img">
</div>
<div class="text">
Action 5
</div>
</div>
</div>

flexbox vertical align child top, center another

I've got the following markup:
.row {
display: flex;
align-items: stretch;
margin: -16px;
background: #ddd;
}
.row .col {
display: flex;
flex-direction: column;
justify-content: center;
flex: 1;
margin: 16px;
background: #fff;
}
.header, .content, .footer {
padding: 16px;
background: red;
}
<div class="row">
<div class="col">
<div class="header">Header #1</div>
<div class="content">Lorem Ipsum<br />Dolor<br />Sit Amet</div>
<div class="footer">Footer</div>
</div>
<div class="col">
<div class="header">Header #2</div>
<div class="content">Lorem Ipsum<br />Dolor</div>
</div>
</div>
Unfortunatly the second header isn't align vertically to the top. Is there a way to archive this with flexbox? I need the ".header" to be aligned the the top and the ".content" to be centered within the rest of the box.
Greetings!
No, not really, not without another wrapper which is a flex-container.
As flexbox is, to a certain extent based on manipulting margins, there is no method (AFAIK, although I'd be interested to find out if there is) to justify-content: center and then align-self a child element to somewhere else other than center.
I'd go with something like this: Add a wrapper to the "content" div, give it flex:1 to fill the remaining space below the header, then make that wrapper display:flex with justify-content:center.
This seems to be the most logical method
.col {
height: 150px;
width: 80%;
margin: 1em auto;
border: 1px solid grey;
display: flex;
flex-direction: column;
}
.header {
background: lightblue;
}
.content {
background: orange;
}
.flexy {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
background: plum;
}
<div class="col">
<div class="header">Header #2</div>
<div class="flexy">
<div class="content">Lorem Ipsum
<br />Dolor</div>
</div>
</div>
Codepen Demo
Flexbox opens up all sorts of opportunities with margin: auto; this is one of them. Setting margin to auto along the flex axis (vertical in this case) will absorb any extra space before dividing it up between the flex items. Finally it's possible to vertically center stuff without creating a div soup.
.row {
display: flex;
align-items: stretch;
margin: -16px;
background: #ddd;
}
.row .col {
display: flex;
flex-direction: column;
flex: 1;
margin: 16px;
background: #fff;
}
.header, .content, .footer {
padding: 16px;
background: red;
}
.content {
margin-top: auto;
margin-bottom: auto;
}
<div class="row">
<div class="col">
<div class="header">Header #1</div>
<div class="content">Lorem Ipsum<br />Dolor<br />Sit Amet</div>
<div class="footer">Footer</div>
</div>
<div class="col">
<div class="header">Header #2</div>
<div class="content">Lorem Ipsum<br />Dolor</div>
</div>
</div>

Reorder columns in reverse order

I have a list of flex items within a flexbox. The order of the items matter, and for accessibility purposes, the items need to show up in the correct order in the dom.
[[itema][itemb][itemc]]
When the flexbox shrinks I would like to have the items wrap in reverse order, e.g. itema wraps first, etc. Is there any way to have the itema wrap first? Thanks!
Edit:
Here is the code
<div class="flex">
<div class="container">
<div class="item">item1</div>
<div class="item orange">item2</div>
<div class="item blue">item3</div>
</div>
<div class="last-item green">menu</div>
</div>
.flex {
display: flex;
background-color: yellow;
height: 80px;
overflow: hidden;
color: #fff;
}
.container {
display: flex;
flex: 1 1 auto;
flex-wrap: wrap;
}
.item {
flex: 0 0 auto;
background-color: red;
height: 80px;
padding: 0 40px;
}
.last-item {
width: 40px;
flex: 0 0 auto;
height: 80px;
}
JSFiddle
All the behavior is as desired except I want the first item to wrap first. Any ideas? Thanks!
You can use the flex-direction: column-reverse to get your solution.
#media (max-width: 768px) {
.flex-box {
display: flex;
flex-direction: column-reverse;
}
}
.first,
.second,
.third {
display: inline-block;
}
<div class="flex-box">
<div class="first">
<p>First Box</p>
<img src="http://placehold.it/300x300" />
</div>
<div class="second">
<p>Second Box</p>
<img src="http://placehold.it/300x300" />
</div>
<div class="third">
<p>Third Box</p>
<img src="http://placehold.it/300x300" />
</div>
</div>
JSfiddle Demo
To make item1 wrap first, you can use flex-wrap: wrap-reverse on your flex container.
Try this simplified version of you code:
<div class="container">
<div class="item">item1</div>
<div class="item orange">item2</div>
<div class="item blue">item3</div>
</div>
.container {
display: flex;
flex: 0 1 auto;
flex-wrap: wrap-reverse;
}
.item {
background-color: red;
height: 80px;
padding: 0 40px;
}
.orange {
background-color: orange;
}
.blue {
background-color: blue
}
See the MDN reference for browser support.

Resources