HTML Part
<div class="container">
<div class="card">hi</div>
</div>
CSS Part
.container{
width: 500px;
aspect-ratio: 1/1;
margin: auto;
display: flex;
gap: 50px;
flex-wrap: wrap;
background: rgba(0, 1000, 0, 0.1);
justify-content: center;
}
.card{
aspect-ratio: 1/1;
width: 50px;
background: rgba(0, 1000, 0, 0.1);
}
With the above code I expect that the card should be a squre of 50px. But surprisingly its height becomes 500px. i.e. same as the parent.
Please explain why it is happning.
If I remove the display: flex; from the container then the card becomes perfect squre as expected.
Why it's happening: the default value of align-content and align-items is stretch. align-content: stretch makes the flex line fill the flex container's cross size (cross size is height in your example because it is a row flexbox). Then align-items: stretch makes .card's cross size fill the line's cross size, which was just stretched to be the container's cross size.
See https://drafts.csswg.org/css-flexbox/#valdef-align-items-stretch. It says "If the cross size property of the flex item computes to auto [then stretch]."
The purpose of that condition is so that stretching doesn't override a specified cross size on the item (item is .card in your example). E.g. If someone put height: 200px on an item inside a height:300px row flexbox, the browser shouldn't blow away that height: 200px with 300px.
But because your item has height:auto, the item stretches.
This part of the flex spec was written before aspect-ratio existed. Maybe it should expand the cases where the items aren't stretched to include items that have a specified aspect-ratio and a definite main size like your example, but... it doesn't. So this is what we got :(
So, if you don't want your aspect-ratio item to stretch, you can do any of these things:
specify a height on the item
put align-content: center (or start or end) on the container
put align-items: center (or start or end) on the container
put align-self: center (or start or end) on the item
Specifying the height will solve your code problem and will allow the display flex to still dictate where the card will be inside of the container. Take a look at this code.
.container{
width: 500px;
aspect-ratio: 1/1;
margin: auto;
display: flex;
gap: 50px;
flex-wrap: wrap;
background: rgba(0, 1000, 0, 0.1);
justify-content: center;
align-items: center; /*To center the card vertically inside of the container*/
}
.card{
height: 50px;
width: 50px;
background: rgba(0, 1000, 0, 0.1);
/*To center the text inside of the .card*/
display: flex;
justify-content: center;
align-items: center;
}
<div class="container">
<div class="card">hi</div>
</div>
Related
I am working with flex layouts and images. My goal is to stack the flex-items on top of each other on smaller screen widths, by setting flex-direction: column; but there is a strange behavior i can't understand. The flex item that wraps the image seems to take the full width of the image. I have created a CodePen that illustrates the problem. Thank you in advance
Let the width of the flex item be dictated by the flex container, then size the image to the size of the flex item.
When you set up a flex-direction: column flex container, the height of your flex items is controlled by the flex properties (grow, shrink, basis).
The width of a flex item in a flex-direction: column flex container can either be dictated by the flex container, or it can be left to the flex item to “decide” how big it wants to be.
In this case align-items: start controls the width of your flex items. start means that the items can size themselves however they want, and they will be positioned at the start side of your flex container.
The flex item that wraps your image doesn’t have its own size (it has the default width: auto), so your image’s width: 100% can’t be resolved. In that case the image behaves as though it had width: auto, and basically renders at its full size. Then, the flex item takes on that size, and that’s why it’s so big in your flex container.
You can force all your flex items to be the width of your column flex container by not setting align-items and letting it use the default normal value, with stretches the flex items to the width of the flex container. Then your flex items have a specific size, and your image’s width: 100% can be resolved against that size.
Here’s a working example:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
background-color: #ccc;
padding: 10px;
display: flex;
flex-direction: column;
}
.item {
background-color: #ff1b68;
padding: 40px;
margin: 3px;
color: #fff;
font-size: 40px;
}
.item--2 {
height: 200px;
}
.item--3 {
}
.item--3 img {
width: 100%;
height: 100%;
object-fit: cover;
}
<div class="container">
<div class="item item--1">1</div>
<div class="item item--2">2</div>
<div class="item item--3">
<img
src="https://images7.alphacoders.com/462/thumb-1920-462576.jpg"
alt=""
/>
</div>
</div>
By default, each flex item has align-self: auto, which means it will look at the flex container’s align-items value. So you set align-items once, and all flex items use that. But you can specify different align-self for each item, if you want to, for example, keep your text flex items align-self: start, and your image flex item align-self: stretch.
You can use a calculated width on your image element setting it to view width units => width: calc(100vw - padding - margin). So your image element will be 100% of the view width minus the padding and margin of the it and its parent element. Also set your container to min-width: 1000px;.
If the following is not what you are looking for, please let me know.
Resize the browser to test dynamic resizing of image to fit within viewable screen
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
background-color: #ccc;
padding: 10px;
min-height: 1000px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
.item {
background-color: #ff1b68;
padding: 40px;
margin: 3px;
color: #fff;
font-size: 40px;
/*flex-grow: 1;*/
}
.item--2 {
height: 200px;
}
.item--3 {
order: 1;
}
.item--3 img {
width: calc(100vw - 130px);
object-fit: cover;
}
<div class="container">
<div class="item item--1">1</div>
<div class="item item--2">2</div>
<div class="item item--3">
<img src="https://images7.alphacoders.com/462/thumb-1920-462576.jpg" alt="">
</div>
</div>
I've got a calendar div (that actually has height and width set to 100vh and 100vw to be fullscreen) containing a header and an actual calendar.
I use flex because I want the header to have a specific height, and the contained calendar to take all the vertical space it has left.
rbc-calendar is actually an external library I use (React Big Calendar) which uses flex on its own to scale the rows. I've put the main div css in case it comes in relevant.
I want my calendar container to have a background image. So only for the calendar itself, not the header. I want this image to be scaled down until the height (width) fits the calendar's height (weight), keeping the image's aspect ratio and letting it overflow for the same amount on right/left (top/bottom).
Background-image: cover seems to be what I'm looking for, but for some reasons the image does not get scaled down at all.
.calendar {
height: 333px;
width: 333px;
display: flex;
flex-direction: column;
}
.calendar-header {
height: 40px;
display: flex;
justify-content: center;
align-items: center;
background: lightblue;
}
.calendar-container {
flex: 1;
background-size: cover;
background: #000 url('https://www.chenhuijing.com/slides/29-constellation-2018/img/meme1.jpg') no-repeat center center;
}
.rbc-calendar {
height: 100%;
display: flex;
align-items: stretch;
}
<div class="calendar">
<div class="calendar-header">
<h1>Not working calendar</h1>
</div>
<div class="calendar-container">
<div class="rbc-calendar">
</div>
</div>
</div>
Answer in the question's comments by Temani-afif : setting background after background-size overrides the statement.
Given the following example, both will fill out the center to consume the remaining space in the page, given the page is using flex. I am leaning towards using the css property flex vs height in the body. Is there a difference that needs to be considered when applying one over the other?
CSS
.page {
display: flex;
flex-direction: column;
}
.header {
height: 100px;
}
.body {
flex: 1; // vs height: 100%;
}
.footer {
height: 40px;
}
HTML
<div class="page">
<div class="header">Sample Header</div>
<div class="body">Sample Body</div>
<div class="footer">Sample Footer</div>
</div>
When you set an element to flex: 1, that breaks down to:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
In a column-direction container (like you have), the flex properties above apply vertically. This means that flex-basis and height are equivalent properties.
flex-basis = height (in a column-direction container)
There is an obvious difference between flex-basis: 0 and height: 100%. It's the same difference as height: 0 and height: 100%.
In your situation, where there is a .header and a .footer consuming 140px of vertical space, setting the middle item (.body) to height: 100% would normally cause an overflow.
But since an initial value of a flex container is flex-shrink: 1, flex items are permitted to shrink, and this wouldn't happen. However, it's still sloppy and imprecise coding, in my view.
By setting .body to flex: 1, you're setting the height to 0, but also allowing it to consume free height with flex-grow: 1. I would say, in this case, that this solution is more efficient.
More details:
What are the differences between flex-basis and width?
§ 7.1.1. Basic Values of flex
There is a huge difference between flex and height.
First to answer your question.
Height 100% doesn't use the remaining space. It will use all the spaces of parent, in your case if page dom is height 200px; then body will also be height: 200px;.
Flex will be correct solution here to fill up the space (flex: 1).
Flex is more than filling the space, its more of a layout and it has influences on its child, how they position and align.
Try below code
.page {
display: flex;
flex-direction: column;
height: 100%;
}
.header {
height: 100px;
display: flex;
align-items: center;
justify-content: center;
}
.body {
display: flex;
flex-direction: column;
height: 80vh;
align-items: center;
justify-content: center;
}
.footer {
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
<div class="page">
<div class="header">Sample Header</div>
<div class="body">Sample Body</div>
<div class="footer">Sample Footer</div>
</div>
I'm getting some unexpected behavior with my margins using flex and I would like some help in understanding why.
I'v got some simple html like so:
<div className="dashboard">
<div className="dashboard__inner-container">Inner Container</div>
</div>
And my scss file looks like this:
.dashboard {
text-align: center;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
flex: 1 1 auto;
background-color: #f4f6f8;
}
.dashboard__inner-container {
display: flex;
flex-direction: column;
background-color: #ffffff;
flex: 1 1 auto;
width: 100%;
margin: 100px 50px;
}
What I am expecting is that the inner container will completely fill up the parent container, minus 100px on the top and bottom and 50px on the right and left. The vertical margin works as expected, but the horizontal margin actually extends out of the parent div, so that the inner container still appears to be taking up the entire width of the parent div.
I'm not sure if this is related to flexbox or not.
Here is an isolated CodePen https://codepen.io/MaxMillington2/pen/EQWZoj
When using align-items: center with column direction, the item will collapse to its content width, instead of with its default, stretch, which makes it fill its parent's width.
Additionally, when setting width: 100% to the inner, it will override the default stretch, which will make the item be 100% of parent's width + margin.
For the expected output, remove align-items: center on the outer and width: 100% on inner.
Stack snippet
html {
height: 100%;
overflow: auto;
}
.outer {
display: flex;
justify-content: center;
flex-direction: column;
background-color: #f4f6f8;
height: 100%;
}
.inner {
display: flex;
flex-direction: column;
background-color: #ffffff;
flex: 1 1 auto;
text-align: center;
margin: 100px 80px;
}
<div class='outer'>
outer
<div class='inner'>
inner
</div>
</div>
I have three elements I'm trying to align in my layout.
First, I have a div for feedback, and then a search input, and then a div element for suggestions.
I want the first and last element to have a width of 20%, and the search input to have a width of 60%. Using Flexbox I achieve what I want.
But there's a feature that grows all the divs to the highest element. This means that when search results pop up, the feedback and suggestion elements grow in height with the search div resulting in a messed up layout.
Is there a trick to not grow the divs with the highest element? Just make the divs (#feedback and #suggestions) have the height of the content in them?
#container_add_movies {
display: flex;
}
#container_add_movies #feedback {
width: 20%;
background-color: green;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#container_add_movies #suggestions {
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>
Feedback
</div>
<div id='search'>
Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>Search
<br>
</div>
<div id='suggestions'>
Suggestions
</div>
</div>
http://codepen.io/alucardu/pen/PPjRzY
You're encountering the flex equal height columns feature.
An initial setting of a flex container is align-items: stretch.
This means that flex items automatically expand the full length of the cross axis of the container. In a row-direction container, the cross axis is vertical (height).
The tallest item sets the height for all siblings. As the tallest item expands, its siblings follow along. Hence, equal height for all items.
To override this default setting, add align-items: flex-start to the flex container:
#container_add_movies {
display: flex;
align-items: flex-start;
}
#container_add_movies {
display: flex;
align-items: flex-start; /* NEW */
}
#container_add_movies #feedback {
width: 20%;
background-color: green;
display: block;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#container_add_movies #suggestions {
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>Feedback</div>
<div id='search'>
Search<br>Search<br>Search<br>Search<br>Search<br> Search
<br>Search<br>Search<br>Search<br>Search<br>
</div>
<div id='suggestions'>Suggestions</div>
</div>
... or align-self: flex-start to the flex items:
#feedback {
align-self: flex-start;
width: 20%;
background-color: green;
}
#suggestions {
align-self: flex-start;
width: 20%;
background-color: yellow;
}
#container_add_movies {
display: flex;
}
#container_add_movies #search {
width: 60%;
background-color: red;
}
#feedback {
align-self: flex-start; /* NEW */
width: 20%;
background-color: green;
}
#suggestions {
align-self: flex-start; /* NEW */
width: 20%;
background-color: yellow;
}
<div id='container_add_movies'>
<div id='feedback'>Feedback</div>
<div id='search'>
Search<br>Search<br>Search<br>Search<br>Search<br> Search
<br>Search<br>Search<br>Search<br>Search<br>
</div>
<div id='suggestions'>Suggestions</div>
</div>
align-items sets the default value of align-self. With align-self you can override the default on individual items.
More details in the spec:
8.3. Cross-axis Alignment: the align-items and align-self
properties
Flex items can be aligned in the cross axis of the current line of the
flex container, similar to justify-content but in the perpendicular
direction.
align-items sets the default alignment for all of the flex
container’s items, including anonymous flex items.
align-self allows this default alignment to be overridden for
individual flex items.
A bit of history
Since the beginnings of CSS, there have been two layout challenges that have regularly frustrated, perplexed, and annoyed front-end developers:
How to center things, especially vertically, and
How to create equal height columns (tables aside)
Today, with the advent of flexbox, these problems are over.
Centering things has never been easier:
#container {
display: flex;
justify-content: center; /* center flex items along the main axis */
align-items: center; /* center flex items along the cross axis */
}
Simple. Easy. Efficient. The craziness is over.
In terms of equal height columns, flexbox also excels: It does this by default.
#container {
display: flex;
flex-direction: row; /* not even necessary; default rule */
align-items: stretch; /* not even necessary; default rule */
}
The align-items: stretch rule tells flex items to expand along the cross-axis as much as possible. Hence, in a row-direction container all items can be equal height. More craziness tamed by flexbox.
From one popular answer for equal height columns:
Give overflow: hidden to the container and large (and equal)
negative margin and positive padding to columns. Note that this
method has some problems, e.g. anchor links won't work within your
layout.
Now that's a hack!
The pendulum is now beginning to swing the other way: Designers are asking how to TURN OFF equal height columns.
You can add align-items: flex-start to your #container_add_movies. Here's an example
to have the unequal columns in bootstrap 4, first of all it needs to know how it is making it equal heights of the columns,so the reason is the
align-items: stretch
to remove this property it need to add align-items: flex-start so for this I have added the class="align-items-start" and the issue is fixed,
Setting the child element that was causing the problem to flex:none did the trick for me.