As i understand flex-basis is responsible for deciding the size of an element.
In the example below, I am trying to size all boxes equally to 100px.
Just using flex-basis is not achieving the effect.
.each_box {
-webkit-flex-grow: 0;
-webkit-flex-shrink: 0;
-webkit-flex-basis: 100px;
flex-grow: 0;
flex-shrink: 0;
flex-basis: 100px;
background-color: yellow;
height: 50px;
border: 1px solid black;
}
Plnkr here: http://plnkr.co/edit/LvrrzHWIw1tPGwK05bCU
I found I had to use min-width as well as flex-basis in Chrome. I'm not sure if I had another problem that caused this.
.flex-container {
display: flex;
width: 100%;
}
.flex-child {
flex-basis: 50%;
min-width: 50%;
}
Be sure to also add: flex-wrap: wrap; because the default value nowrap in order to fit everything in one line can affect the size of the elements (eg: width, flex-basis, etc..).
The flex-grow, flex-shrink, flex-basis properties only have an effect on elements in a flex container -- i.e. elements whose parent has display:flex.
You need to put your each_box divs directly inside of a display:flex element for them to honor their flex-related properties.
Specifically, your markup looks like this (from right clicking one of the yellow divs + hitting "inspect" in Firefox):
<div class="container">
<!-- ngRepeat: stock in stockList -->
<div class="ng-scope" ng-repeat="stock in stockList">
<div class="each_box ng-binding">
0-FB/100
You've got container styled as display:flex, but that does no good for your each_box elements, because they're grandchildren, separated from the flex container by the display:block ng-scope.
So you either need to get rid of the ng-scope wrapper, or make it also have display:flex.
Add a width: width:100px;
flex-basis gives a default proportion, which will then grow or shrink.
All works for me:
.flex-child { width:0; }
AND
.flex-child { min-width:0; }
AND
.flex-child { flex-shrink:0; } /* no scrollbars inside */
Related
I have simple structure of element container of dynamic height and fixed width (Markup below). On one hand the element's background should span the whole window width, on the other the children's size must be limited by the container (Desired layout below). The number of children and their sizes (which are equal on the image only for simplicity) are dynamic.
Is that possible without adding extra container? I want to avoid achieving the desired element content width by setting width on the children, because their number is dynamic and the size relationships become complicated to write unless their total width is already limited by container's width.
Here's a pen to experiment;
Markup
<div class="container">
<div class="child">
<div class="child">
...
</div>
.container {
width: <fixed-width>px;
}
Desired layout (the whitespace between children and container is irrelevant)
One route we can take to solve this is by using viewport width on the parent container padding, to force the children into a box that is only 500px wide (as per your codepen).
The important thing to remember when doing this is that box-sizing:border-box; will need to be set on the container, otherwise the padding goes ballistic.
We do this by using calc, vw and padding.
padding: 20px calc(50vw - /*half of container width*/);
Here's the full expanded code of your container on the linked codepen:
.container {
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin-left: auto;
margin-right: auto;
height: 300px;
width: 100%;
padding: 20px calc(50vw - 250px);
background-color: #acffac;
background-size: 100vw auto;
background-position: center top;
box-sizing: border-box;
}
html {
overflow-y:scroll; /* fixes potential calculation errors caused by scroll bar - thanks to Roberts comment */
}
Here's a working version of the codepen, and for the sake of keeping all my eggs in one basket, here's an expandable code snippet:
.container {
display: flex;
flex-flow: row nowrap;
justify-content: center;
margin-left: auto;
margin-right: auto;
height: 300px;
width: 100%;
padding: 20px calc(50vw - 250px);
background-color: #acffac;
background-size: 100vw auto;
background-position: center top;
box-sizing: border-box;
}
.child {
flex: 1 0 auto;
width: 100px;
height: 100%;
background-color: #ff4444;
}
.child+.child {
margin-left: 20px;
}
<div class="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
I will finish off by pointing out that if someone else has a better solution, you may want to look at that for time being instead as there is some issues with using vw inside calc on older versions of Chrome and Safari.
EDIT:
As noted in the comments by Vadim and Robert there are a few things that can cause some snags.
Firstly, assuming you are working with a bare minimum template (i.e. no normalize/reset.css), your body will most probably still have the inherent margins that would mess with this kind of layout. You can fix this with:
body {
margin:0;
}
Secondly, depending on your OS (Yes I'm looking at you Microsoft!) your scrollbars can push your content to the side whilst simultaneously still being included in the calculation for vw.
We can fix this one of two way. The first being an adjustment on the padding calculation to include the scrollbar side, but you would have to write a script to ensure that scrollbar is actually present, and scrollbars differ in sizes (I.E -> 17px, Edge -> 12px).
The other alternative would be to use a custom content scroller, which would do a full overflow:hidden; over the content, thereby removing the scroll bar, before implementing it's own version of a scrollbar (which generally lies on top of the content with a position:fixed;) it.
Using vw and flex we can center the child elements and achieve exactly what you require. I have written a JSfiddle where you can check it out.
Basically what I have done is created a container with display set to flex. Using margin property of the first child element, I have centered all of the other child divs and then the regular properties were added to other divs.
Here's the code
body{
margin: 0;
padding: 0;
}
#container{
display: flex;
width: 100vw;
height: 40vw;
background-color: #333333;
align-items: center;
}
.child{
width: 4vw;
height: 80%;
background-color: red;
margin-right: 10vw;
}
.child:first-child{
margin-left: 28vw;
}
<div id="container">
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
<div class="child"></div>
</div>
To center items with display: block people use margins: auto. If I set max-width to child that needs to be centered and there's enough space around it will fluid as much to max-width as it needs to (depending on its content). But if I change display property of parent element to flex it doesn't take all free space anymore. I really need to use max-width since I want element to shrink on small screens.
Here's the jsfiddle . Clicking on the button swaps display: flex to display: block on parent. I want the green space on flex to fluid as much as it's possible for max-width as it's done with display:block
EDIT:
I also would like to use flex-direction: column
$('input').click(function() {
var curDisplay = $('#parent').css('display');
if (curDisplay == 'block') {
$('#parent').css('display', 'flex');
$('input').val('flex');
} else {
$('#parent').css('display', 'block');
$('input').val('block');
}
})
#parent {
display: flex;
flex-direction: column;
width: 100%;
background-color: red;
height: 50px;
}
#child {
max-width: 300px;
background-color: green;
height: 50px;
margin: auto;
}
input {
width: 100%:
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">
<div id="child">
<input type="button" value="Click Me!" />
</div>
</div>
I think you're looking for flex-basis. By using a % you can get very close. You can use px to set the initial width, it will still be "responsive" until you hit the minimum width if you have it set.
on the child element:
div {
flex-basis:40%;
}
Here is the W3
Why not just set the width of the child to 100%? If you need to center the button in the child you can simply add:
display: flex;
justify-content: center;
Also remove width: 100% from the input.
The question is about .text-wrapper, which has display:flex; flex-wrap:wrap applied to it. The reason for using flex-wrap:wrap is that otherwise .text-wrapper and .tabs-wrapper wouldn't stop being on one line, next to each other, like inline elements (though I have no idea why, because divs should be block level elements, no? I'll appreciate if someone can enlighten me on this one as well)
The problem is that I want the children of .text-container to its bottom, and not have more than 20px space between them.
But right now, there is a lot of space between .text-wrapper and .tabs-wrapper. How do I fix this?
JSFiddle here.
OR
html,
body {
height: 100%;
box-sizing:border-box;
}
.the-page {
height:100%;
width:100%;
position:relative;
}
.first-bottom {
height: 100%;
}
.image-container img {
position: fixed;
width: 100%;
height: 100%;
left: 0px;
top: 0px;
display: block;
}
.text-container {
height:100%;
width:100%;
top:0px;
position:relative;
display:flex;
align-items:flex-end;
flex-wrap:wrap;
}
.text-wrapper span {
text-align:center;
color:yellow;
}
.tabs-wrapper {
height:50px;
width:100%;
background-color:pink;
opacity:0.5;
}
.tabs-wrapper-inner {
height:100%;
display:flex;
align-items:center;
justify-content:center;
width:60%;
margin:auto;
}
.tabs-wrapper-inner a {
text-decoration:none;
font:sans-serif;
font-weight:bold;
color:red;
padding:10px;
}
.other-content {
background-color: purple;
opacity: 0.5;
width: 100%;
height: 500px;
}
<div class="the-page">
<div class="first-bottom">
<div class="image-container">
<img src="http://photostry.com/wp-content/uploads/2011/09/highway-arizona-to-utah.jpg" />
</div>
<div class="text-container">
<div class="text-wrapper">
<span>SUN BEACH WARM</span>
</div>
<div class="tabs-wrapper">
<div class="tabs-wrapper-inner">
AMY
BAMY
CAMY
DAMY
EAMY
</div>
</div>
</div>
</div>
<div class="other-content">.</div>
</div><!-- #the-page -->
The question is about .text-wrapper, which has display: flex; flex-wrap: wrap applied to it.
I think you mean .text-container, because there is no .text-wrapper rule in your CSS.
The reason for using flex-wrap: wrap is that otherwise .text-wrapper and .tabs-wrapper wouldn't stop being on one line, next to each other, like inline elements (though I have no idea why, because divs should be block level elements, no? I'll appreciate if someone can enlighten me on this one as well)
When you create a flex container – like you have by declaring display: flex on .text-container – you establish a flex formatting context. In this context, the children of the container become flex items and adhere to a flex layout, not a block layout. By default, flex items are aligned in a single, non-wrapping row (any block or inline display values are overridden by flex rules).
The problem is that I want the children of .text-container to its bottom, and not have more than 20px space between them.
But right now, there is a lot of space between .text-wrapper and .tabs-wrapper. How do I fix this?
To control the alignment of multiple lines in the cross axis, you can use the align-content property.
The reason there is wide space between both lines is because the default value of align-content is stretch, which tells flex lines to distribute free space in the cross axis equally among themselves.
To better understand how this property works I would suggest you add a border (or background, or both) to .text-wrapper and .tabs-wrapper. Then try out the different align-content values: flex-start, flex-end, center, space-between, space-around and stretch.
Also, an important note to keep in mind, align-content only works when there are multiple lines in the cross axis of the flex container. If there is only one line it will have no effect, and you should use align-items instead.
Add this to your CSS:
.text-container {
height:100%;
width:100%;
top:0px;
position:relative;
display:flex;
align-items:flex-end;
align-content: flex-end; /* new */
flex-wrap:wrap;
}
To create a 20px gap between .text-wrapper and .tabs-wrapper simply add a bottom margin to .text-wrapper.
.text-wrapper {
margin-bottom: 20px;
}
Revised Demo
To learn more about flexbox visit:
Methods for Aligning Flex Items
Using CSS flexible boxes ~ MDN
A Complete Guide to Flexbox ~ CSS-Tricks
What the Flexbox?! ~ YouTube video tutorial
You should use flex-direction:column; instead of flex-wrap.
For more information on flex and how to use it, there is this excellent article at CSS Tricks
I'm in the process of updating an old inline-block-based grid model I have to a newer Flexbox one I created. Everything has worked fine, apart from one little snag, which has become a bit of a dealbreaker:
I have a bunch of CSS-controlled sliders; so there's a containing wrapper with 100% width, and inside is another div: its width is also 100%, but its white-space is set to nowrap. Using inline-block, this meant that the internal divs (which were also set to 100% width) wouldn't be bound by their parents' constraints and wrap onto the next line - they'd just carry on flowing out of the box. This is exactly what I wanted. However, I cannot get this to work at all with flexbox. For reference, here's an image:
And for reference, here's a jsFiddle of the thing working with inline-block: http://jsfiddle.net/5zzvqx4b/
...and not working with Flexbox: http://jsfiddle.net/5zzvqx4b/1/
I've tried all kinds of variations with flex, flex-basis, flex-wrap, flex-grow, etc. but for the life of me I can't get this to work.
Note that I can force it to do what I want in a hacky, inflexible way by setting the .boxcontainer width to 200%. That works for this single example, but in some cases I won't know beforehand how many child boxes there will be, and I'd rather not resort to inline styling on each element if possible.
To prevent the flex items from shrinking, set the flex shrink factor to 0:
The flex shrink factor determines how much the flex item will
shrink relative to the rest of the flex items in the flex
container when negative free space is distributed. When omitted, it is
set to 1.
.boxcontainer .box {
flex-shrink: 0;
}
* {
box-sizing: border-box;
}
.wrapper {
width: 200px;
background-color: #EEEEEE;
border: 2px solid #DDDDDD;
padding: 1rem;
}
.boxcontainer {
position: relative;
left: 0;
border: 2px solid #BDC3C7;
transition: all 0.4s ease;
display: flex;
}
.boxcontainer .box {
width: 100%;
padding: 1rem;
flex-shrink: 0;
}
.boxcontainer .box:first-child {
background-color: #F47983;
}
.boxcontainer .box:nth-child(2) {
background-color: #FABCC1;
}
#slidetrigger:checked ~ .wrapper .boxcontainer {
left: -100%;
}
#overflowtrigger:checked ~ .wrapper {
overflow: hidden;
}
<input type="checkbox" id="overflowtrigger" />
<label for="overflowtrigger">Hide overflow</label><br />
<input type="checkbox" id="slidetrigger" />
<label for="slidetrigger">Slide!</label>
<div class="wrapper">
<div class="boxcontainer">
<div class="box">
First bunch of content.
</div>
<div class="box">
Second load of content.
</div>
</div>
</div>
You can use the shorthand flex property and set it to
flex: 0 0 100%;
That's flex-grow, flex-shrink, and flex-basis in one line. Flex shrink was described above, flex grow is the opposite, and flex basis is the size of the container.
In my case, just using flex-shrink: 0 didn't work. But adding flex-grow: 1 to it worked.
.item {
flex-shrink: 0;
flex-grow: 1;
}
Set the flex-direction: column
You're trying to stack the items in a column rather than a row.
{
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
I'm not sure I understand how css column layout is supposed to work.
I have a straightforward html
<div class="container">
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
</div>
and css
.block {
background-color: blue;
width: 50em;
height: 10px;
margin: 2px;
display: inline-block;
}
.container {
border: 1px solid black;
display: inline-block;
column-count: 2;
-moz-column-count: 2;
-webkit-column-count: 2;
}
This works as expected with the elements flowing downwards and then over into a second column.
Now what if I change the width value of .block to a percentage width? All my widths are tiny. They still are clearly relative to something since shrinking and growing the percentages changes the width proportionately but I have no idea what 100% corresponds to.
What is the percentage width relative to?
The width is relative to the column pseudo-element inserted by the browser:
http://www.w3.org/TR/css3-multicol/
In the traditional CSS box model, the content of an element is flowed into the content box of the corresponding element. Multi-column layout introduces a new type of container between the content box and the content, namely the column box (or column for short). The content of a multicol element is flowed into its column boxes.
(Emphasis mine.)
So, the percentage width you're asking for is relative to the implicit column boxes.
Browser Support
As I noted in my comment support for column-count etc is poor today. Except where you really need a specific feature of CSS multicolumn, I find it easier to just use the old inline-block approach. Works in every browser in use today, easy to figure out.
http://jsfiddle.net/b9chris/nt83M/
.block {
background-color: blue;
width: 45%;
height: 10px;
margin: 2px;
display: inline-block;
vertical-align: top;
}
.container {
border: 1px solid black;
width: 200px;
display: inline-block;
}
<span class=container>
<span class=block></span>
<span class=block></span>
<span class=block></span>
<span class=block></span>
<span class=block></span>
</span>
Two important caveats:
For old IE support to work properly you need to use tags that are inline by default, like span. Using a tag that's block by default, like div, will look great in Chrome etc but fail in IE8.
You need to set vertical-align: top in the inner tags to get things to work the way you'd expect them (otherwise everything acts like vertical-align: bottom).
Essentially how column layouts work is you have a container that a width and you split that container into columns. When you decide how many columns you want for your design you assign each of those columns a percentage. Then you float those columns next to each other.
So if you have a 12 column layout the column classes would be as follows:
.col-1 { width: 4.8076923077% }
.col-2 { width: 13.4615384615% }
.col-3 { width: 22.1153846154% }
.col-4 { width: 30.7692307692% }
.col-5 { width: 39.4230769231% }
.col-6 { width: 48.0769230769% }
.col-7 { width: 56.7307692308% }
.col-8 { width: 65.3846153846% }
.col-9 { width: 74.0384615385% }
.col-10 { width: 82.6923076923% }
.col-11 { width: 91.3461538462% }
.col-12 { width: 100%; margin: 0 }
The above columns take into account margins and padding, but here's a fiddle that lays it out.
Parent element width within a content column refers to the column width, a property that defaults to auto. A columnar element is either defined by column-width or column-count (but not both, column-count overrides any column-width value if they are both non-auto). So in your example, providing column-count is causing an automatically generated width to be presented as container width.
source - right above example IX here: http://www.w3.org/TR/2011/CR-css3-multicol-20110412/
Column boxes act as the containing block for their content. That is,
column boxes behave like block-level, table cell, and inline-block
boxes as per CSS 2.1, section 10.1, item 2 [CSS21]. However, column
boxes do not establish containing blocks for elements with ‘position:
fixed’ or ‘position: absolute’.