Horizontal Margins going outside of parent div in flexbox - html

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>

Related

Why is the container for h1 is a lot bigger than it needs to be?

I've started learning flexbox recently and tried doing some exercises to practice but I got stuck because the container for h1 is a lot bigger than it needs to be, even if margin and padding are 0, and it makes the whole other page uncentered.
main {
display: flex;
justify-content: center;
background-color: #cacaca;
height: 100vh;
flex-flow: row wrap;
}
h1 {
margin: 0;
padding: 0;
}
#container {
margin-top: 100px;
}
<main>
<h1>Here are some nice pics</h1>
<div id="container"> ... </div>
</main>
It's because default value of align-items is stretch which makes all flex items to stretch to full height of their parent. if you give align-item: flex-start to use only required height.
main {
height: 100vh;
display: flex;
justify-content: center;
align-items: flex-start;
}
h1 {
background: red;
}
<main>
<h1>Here are some nice pics</h1>
<div id="container">Container</div>
</main>

What is the difference between the flex and height properties?

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>

Css flex - one item on the right, the other centered on the left space

I'm new to css and even newer to flex.
I couldn't find an answer, so I started a new one..
I have the following container and item:
.container {
display: flex;
justify-content: space-between;
align-items: center;
}
.item {
color: rgb(51, 51, 51);
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
This way I get 2 items on both sides (one left and one right).
I would like to know how to do the following:
The left item, will be on the left as before. From the point it ends, to the point the container ends - I with the right element to be centered.
The left item, will be on the left as before. The right item will be 10px left from the right end of the container.
Thanks!
The solution to this problem is using nested flexboxes. Get rid of the display: block; on .item - you can't mix flex and block display rules like that.
What you want to do is set up series of containers:
one top level flex container
two equally sized flex containers inside of the the top level container
Markup will look like this:
<main class="container">
<section class="left-container">
<div class="item"></div>
</section>
<section class="right-container">
<div class="item"></div>
</section>
</main>
In the CSS layer, you give the top-level .container flex and then justify-content: space-between which pushes the containers to the sides.
.container {
display: flex;
justify-content: space-between;
}
In the two nested containers, you need to make them both display: flex; as well. Now you can control the positioning of your .item elements like you want. align-items: center controls the vertical axis so .left-container gets only that positioning while the right container gets justify-content: center; to control the vertical alignment.
.left-container {
background-color: darkgray;
display: flex;
align-items: center;
height: 200px;
width: 50%;
}
.right-container {
background-color: lightgray;
display: flex;
align-items: center;
justify-content: center;
height: 200px;
width: 50%;
}
Styling on the item is pretty simple - I just gave height and width for demo purposes. They aren't necessary. If you want to do precise tweaks, use margin on .item to push slightly from these standards.
.item {
background-color: red;
height: 100px;
width: 100px;
}
Codepen:
https://codepen.io/staypuftman/pen/PmLyNM

Vertically centering with flexbox

I'm trying to center a div on a webpage using flexbox. I'm setting the following CSS properties. I see that it's being centered horizontally, but not vertically.
.flex-container {
display: flex;
align-items: center;
justify-content: center;
}
Here's the fiddle: JSFIDDLE
Can you explain what I'm doing wrong?
A <div> element without an explicit height defaults to the height of it's contents, as all block elements do. You'd probably want to set it to 100% of it's parent, the <body>, but that's not enough, since that is also a block element. So again, you need to set that to 100% height, to match it's parent, the <html>. And yet again, 100% is still required.
But once all that is done, you get that annoying vertical scroll bar. That's a result of the default margin the body has, and the way the box model is defined. You have several ways you can combat that, but the easiest is to set your margins to 0.
See corrected fiddle.
html, body {
height: 100%;
margin: 0px;
}
.flex-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.item {
background-color: blue;
height: 50px;
width: 50px;
}
<div class="flex-container">
<div class="item">
</div>
</div>
You just need to set html, body, and your flex container to height: 100%. The reason it wasn't working is that your flex container didn't have an explicit height set, so it defaulted to the height of its contents.
Live Demo:
html, body {
height: 100%;
}
.flex-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.item {
background-color: blue;
height: 50px;
width: 50px;
}
<div class="flex-container">
<div class="item">
</div>
</div>
JSFiddle Version: http://jsfiddle.net/d4vkq3s7/3/

Flexbox wrap - different alignment for last row

I'm using flex box to align two items to left and right of the container, while vertically centre-aligning them. Here's a very simple example of what I'm trying to achieve.
HTML:
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
CSS:
.container {
width:100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
}
Here's the jsfiddle of the example.
This works perfectly well if the screen is wide enough to fit both internal divs on one row. However when the screen size is small (e.g. a mobile phone) and the divs wrap onto the second line, the second one also becomes aligned to the left side (i.e. flex-start). How can I force the second div to always be aligned against the right border, regardless of whether it's on the first row or wrapped onto the second one?
EDIT: In the example, I assigned fixed width to the two child elements - this is for simplicity only. In the real life application, all widths are dynamically changing based on the content read from the database at run-time. Hence, any solution that's based on fixed sizes will not work.
You can try adding some left margin to push your .second element to the right:
.second {
margin-left: auto;
}
.container {
width:100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
margin-left: auto;
}
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
Or, similarly, justify all elements to the right but push .first element to the left:
.container {
justify-content: flex-end;
}
.first {
margin-right: auto;
}
.container {
width:100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: flex-end;
align-items: center;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
margin-right: auto;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
}
<div class="container">
<div class="first"></div>
<div class="second"></div>
</div>
I found a solution but it is rather "hacky" in nature (see demo here, explanation later), in the sense that it requires you to explicitly know the width of the parent container which will trigger a layout change based on #media.
The reason why your code is not working is because of the confusion over how align-self works. In the flexbox model, "align" refers to alignment along the cross-axis (i.e. in a conventional sense of a "row" layout direction, that will refer to vertical alignment), while "justify" refers to alignment along the main axis (i.e. the row). To better explain my point, I hereby attach an image made by Chris Coyier from his flexbox guide:
Therefore, align-self: flex-start means telling the .first to align to the top of the container, and align-self: flex-end means telling .second to align to the bottom of the container. In this case, since you have not declared an explicit height for the parent, the parent will take on the height of its tallest child. Since both .first and .second are 100px tall, the parent will also have a computed height of 100px, therefore making no difference in the alignment (because both with be flush with the start and end of the cross axis).
A hack would be switching the flex-direction to row, with the following restrictions: You know how wide your container will be, or the explicit widths of its children. In this case the breakpoint will be at 400px, where .first and .second will intersect each other.
.container {
width:100%;
display: flex;
flex-direction: column;
flex-wrap: wrap;
justify-content: space-between;
height: 100px;
}
.first {
background-color: yellow;
width: 200px;
height: 100px;
align-self: flex-start;
}
.second {
background-color: blue;
width: 200px;
height: 100px;
align-self: flex-end;
}
#media screen and (max-width: 400px) {
.container {
height: 200px;
}
}
Then again, here is a proof-of-concept fiddle, modified from your original one: http://jsfiddle.net/teddyrised/cncozfem/2/