I have a flex layout with two flex items, displayed as rows (flex-direction: column). The items should have a minimum height but they should maintain the same height it one of them needs to grow. See this JSFiddle and decrease the width of the result pane; this forces the second .component element to increase its height, but the height of the first .component element remains the same.
Is it possible to force the flex items to maintain the same height? Please note that the main thing in this is the stacking of the two .component elements, which I couldn't achieve without flex-direction: column; flex-direction: row would have made the same height possible but the stacking does not work.
Here is the result of what I have so far:
div {
border: 1px solid black;
box-sizing: border-box;
}
.container {
display: flex;
flex-direction: column;
align-content: stretch;
}
.component {
min-height: 300px;
}
.left {
margin-left: 50px;
margin-top: 50px;
margin-right: 100px;
background-color: lightyellow;
}
.right {
margin-left: 100px;
margin-top: -250px;
margin-right: 50px;
background-color: lightgreen;
}
<div class="container">
<div class="component left">
</div>
<div class="component right">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent sed orci scelerisque, scelerisque enim at, ullamcorper ipsum. Cras eget sapien mi. Aliquam ultrices, ligula ut mollis maximus, ligula massa imperdiet libero, at faucibus mauris ante non
magna. Sed ex lacus, efficitur sit amet neque ut, venenatis hendrerit libero. Suspendisse ornare orci mi. Nulla iaculis egestas libero, eu tincidunt urna tristique et. Quisque nec odio non elit molestie facilisis.
</p>
<p>
Vestibulum scelerisque justo urna, a semper nisi sollicitudin in. Cras congue enim eu euismod semper. Proin consequat gravida felis, quis tincidunt massa pulvinar quis. Morbi nec diam eget orci vestibulum malesuada. Sed volutpat metus eget mattis commodo.
Nulla facilisi. Praesent lectus mauris, consequat eu varius vitae, cursus vitae leo. Vivamus sagittis lacinia tortor eu ullamcorper. Integer eget velit magna. Duis vestibulum molestie posuere.
</p>
</div>
</div>
The flex equal height columns feature – which is the result of align-items: stretch, a default setting of a flex container – applies only to flex items on the same row.
It doesn't work for items in a multi-line flex container. This behavior is defined in the spec:
6. Flex Lines
In a multi-line flex container (even one with only a single line), the
cross size of each line is the minimum size necessary to contain the
flex items on the line (after alignment due to align-self), and the
lines are aligned within the flex container with the align-content
property.
In other words, when there are multiple lines in a row-based flex container, the height of each line (the "cross size") is the "minimum size necessary to contain the flex items on the line".
In addition, because align-items: stretch works along the cross-axis, the equal height columns feature is useless in flex-direction: column, where the cross-axis is horizontal.
To achieve equal height columns/rows across multiple lines consider a Javascript solution.
However, without knowing much about your overall objective, here's a simple way to achieve equal height rows in your current layout:
Add duplicate content in both divs. In the .component.left div, use visibility: hidden.
Revised Fiddle
You can just wrap those flexbox columns in another flexbox that's a row, there's no reason you can't have items be both flexboxes and flex items.
#container {
display: flex;
}
#container .col {
flex-grow: 1;
display: flex;
flex-direction: column;
background: grey;
}
<div id="container">
<div class="col">
asdf
asdf
asdf
</div>
<div class="col">
asdf
asdf
asdf
</div>
</div>
https://jsfiddle.net/1dp87bm2/1/
Related
I've spent way too long at work today thinking about this, so I figured I'd ask the internet hive-mind.
I've got a standard <ul> with a number of <li> elements (currently 12 but could vary). I'd like to arrange these into 2 columns of equal width WHILE also not making the <ul> span full block width. The solution also needs to support IE11 unfortunately (no earlier). Any solution needs to also be responsive, so no set non-percentage widths. I've tried a couple different scenarios (you will want to expand snippet to full screen):
Solution 1 (grid):
*{
box-sizing: border-box;
}
div{
display: flex;
justify-content: center;
}
ul{
list-style: none;
margin-top: 0;
margin-bottom: 0;
padding: 0;
display: inline-grid;
grid-template-columns: repeat(2, 1fr);
}
li{
padding: 15px;
}
<div>
<ul>
<li>In maximus viverra scelerisque. Vestibulum dignissim ex non</li>
<li>Sed suscipit, turpis in suscipit consectetur, ante sem.</li>
<li>Ut et mauris et dui gravida fringilla ut.</li>
<li>Nullam iaculis fermentum sodales. Proin commodo eleifend lacus.</li>
<li>Sed molestie, libero at hendrerit sollicitudin, enim nisi.</li>
<li>Mauris a facilisis dolor. Sed pharetra hendrerit dolor.</li>
<li>Sed vitae felis tellus. Quisque sagittis, felis vitae.</li>
<li>Integer et elit metus. Cras congue vestibulum hendrerit.</li>
<li>Fusce suscipit ante sed tristique euismod. Duis quis.</li>
<li>Vestibulum quam felis, fringilla in justo malesuada, tristique.</li>
<li>Integer volutpat quam sed urna iaculis mollis. Maecenas.</li>
<li>Nullam dignissim ipsum vitae finibus dignissim. Nam viverra.</li>
</ul>
</div>
This above solution essentially works perfectly - it arranges the <li>s in 2 columns, the UL is centered in the containing flex div. But of course IE has issues, and while I could use IE prefixes in the old spec, I would still need to manually assign a column/row position for each li which is not possible for a list that could potentially have any number of elements.
Solution 2 (flex):
*{
box-sizing: border-box;
}
div {
display: flex;
justify-content: center;
}
ul {
list-style: none;
margin-top: 0;
margin-bottom: 0;
padding: 0;
display: inline-flex;
flex-wrap: wrap;
}
li {
padding: 15px;
width: 50%;
}
<div>
<ul>
<li>In maximus viverra scelerisque. Vestibulum dignissim ex non</li>
<li>Sed suscipit, turpis in suscipit consectetur, ante sem.</li>
<li>Ut et mauris et dui gravida fringilla ut.</li>
<li>Nullam iaculis fermentum sodales. Proin commodo eleifend lacus.</li>
<li>Sed molestie, libero at hendrerit sollicitudin, enim nisi.</li>
<li>Mauris a facilisis dolor. Sed pharetra hendrerit dolor.</li>
<li>Sed vitae felis tellus. Quisque sagittis, felis vitae.</li>
<li>Integer et elit metus. Cras congue vestibulum hendrerit.</li>
<li>Fusce suscipit ante sed tristique euismod. Duis quis.</li>
<li>Vestibulum quam felis, fringilla in justo malesuada, tristique.</li>
<li>Integer volutpat quam sed urna iaculis mollis. Maecenas.</li>
<li>Nullam dignissim ipsum vitae finibus dignissim. Nam viverra.</li>
</ul>
</div>
While this above solution is technically acceptable (works well enough, including IE11), the issue here is visual appeal. Because the <ul> now spans full width, despite being centered in the containing flex div, the <li>s spaning the 50% with left aligned text leaves a large about of visual white space on the right side of each column (wide screen needed to see extra space).
Solution 3 (tables for IE11):
I'm not going to bother posting a snippet for this one, as it was the least appealing. Essentially it involved targeting IE11 specifically, setting the <ul> to display:table;, setting the <li>s to display:table-cell; float: left; width: 50%; ...long story short, it was a mess that still didn't work visually.
Should I just cut my losses and go with solution 2? I'd really like to get the visual layout of solution 1 if possible... Any ideas?
The display: flex; property will turn the element into a flex container that affects the layout of the direct child elements only, so if it is only on the outer div it is only affecting the layout of the ul that is the direct child. For this reason I added display: flex; to the ul element so the contained child li elements get the flexible layout. A great resource for more info on flexbox: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
In order to address the extra white space I added a max-width to the ul less than 100% so the width does not go all the way to the edges, adjust this value as needed. I also changed the padding on the li elements, only padding on the left and right, and added margin-bottom to space them vertically.
Lastly, I recommend you add a class to your div wrapper so you can target everything contextually, otherwise your CSS targeting div will hit every div in the site, can be very problematic.
* {
box-sizing: border-box;
}
.wrapper {
display: flex;
justify-content: center;
}
.wrapper ul {
list-style: none;
margin: 0;
padding: 0;
max-width: 90%; // adjust the width compared to the container
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.wrapper li {
padding: 0 15px; // padding right and left only
margin-bottom: 20px; // vertical spacing between li elements
width: 50%;
}
<div class="wrapper">
<ul>
<li>In maximus viverra scelerisque. Vestibulum dignissim ex non</li>
<li>Sed suscipit, turpis in suscipit consectetur, ante sem.</li>
<li>Ut et mauris et dui gravida fringilla ut.</li>
<li>Nullam iaculis fermentum sodales. Proin commodo eleifend lacus.</li>
<li>Sed molestie, libero at hendrerit sollicitudin, enim nisi.</li>
<li>Mauris a facilisis dolor. Sed pharetra hendrerit dolor.</li>
<li>Sed vitae felis tellus. Quisque sagittis, felis vitae.</li>
<li>Integer et elit metus. Cras congue vestibulum hendrerit.</li>
<li>Fusce suscipit ante sed tristique euismod. Duis quis.</li>
<li>Vestibulum quam felis, fringilla in justo malesuada, tristique.</li>
<li>Integer volutpat quam sed urna iaculis mollis. Maecenas.</li>
<li>Nullam dignissim ipsum vitae finibus dignissim. Nam viverra.</li>
</ul>
</div>
I am trying to make responsive one of my sites... :)
In standard view (pc), I have a div container called "article" containing more divs on 2 cols, all of these have width: 350px.
Resizing the screen, I want the divs into "article" are centered into it in a single col.
I have tried a lot of ways, including margin: 0 auto, display: inline-block, display: table, but does not works, and divs are always flotted to left of "article". :(
Using this method in media query:
left: 50%
margin-left: 175px;
It center the div when "article" has width: 707px (708 is just I need for divs on two cols including a few padding),
but reducing width under 707px value, the centering is losed because margin-left has a fixed value!
you only need to margin: 0 auto; your div, like so:
.container {background-color:red;}
.content {background-color:aqua;width: 350px;margin:10px auto;}
<div class="container">
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eleifend eu leo quis euismod. Phasellus blandit suscipit ipsum non pretium. In facilisis scelerisque sodales. Integer posuere nunc eget orci tincidunt, et dapibus dui porta. Duis pellentesque commodo mi, non congue erat imperdiet ac. Morbi facilisis accumsan dapibus. Quisque metus risus, ullamcorper ut faucibus ac, elementum in arcu. Aliquam vulputate sapien sed ullamcorper dignissim. Cras aliquet nisl nibh, a feugiat tortor pellentesque ac. Donec id mollis ante, sit amet ultricies velit.
</div>
</div>
I would start by using percents on your sub columns. Fixed widths will cause unwanted problems.
Then on your mobile layout, have your sub column go full width and remove the float. That will have the columns stack on top of each other.
.article .subColumn {
width:48%;
float:left;
}
#media screen only and (max-width:480px) {
.article subColumn {
float:none;
width:100%;
padding:0 25px;
}
}
I have two rows, with a heading in the top row, and 2 columns in the bottom row, all vertically centred within a fullscreen wrap. For some reason, I cannot get rid of the extra vertical space that the fullscreen wrap adds in between the two rows, despite adding:
align-content:centre
as well as display: flex to both parent divs (.wrap and .row)
What am I doing wrong?
jsfiddle: https://jsfiddle.net/ar4Ltoke/2/
.wrap {
width: 1280px;
min-height: 100vh;
border-style: solid;
}
.row {
width: 100%;
align-items: flex-start;
margin: auto;
border: 1;
border-style: solid;
}
.column_left {
flex-basis: 60%;
border: 1;
}
.column_right {
flex-basis: 30%;
}
#media (min-width:640px) {
.row {
display: flex;
justify-content: space-between;
}
.wrap {
display: flex;
align-content: center;
flex-direction: column;
}
}
<div class="wrap">
<div class="row">
<p class="blue">About me</p>
</div>
<div class="row">
<div class="column_left">
<p class="leadpara">Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec ullamcorper nulla non metus auctor fringilla. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Fusce dapibus, tellus ac cursus
commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Donec ullamcorper nulla non metus auctor fringilla. Duis mollis, est non commodo luctus, nisi
erat porttitor ligula, eget lacinia odio sem nec elit. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.
</p>
</div>
<div class="column_right">
<p class="leadpara">
Email
<br> Add me on Linkedin
<br> Tweet at #fsd
</p>
</div>
</div>
</div>
Two reasons:
You have margin: auto on .row. That causes both .row flex items to distribute space equally in the container, which forces them to separate.
The .wrap element is a column-direction flex container. That means that the main axis is vertical. As a result, you need justify-content to vertically center the rows.
revised demo
For a more detailed explanation see:
In CSS Flexbox, why are there no "justify-items" and "justify-self" properties?
Because you are using <br> to change the line due to which extra spaces are created using something else to change the line. You can use a list instead if you want to show them pointwise with list-style-type as none. Please let me know if my answer is not clear. I will send the code if required.
I have a situation where I want to display items on a web page vertically within columns. I want the number of columns to change based upon the available screen width. The items belong to groups. When there is enough screen size, I want display those in the same group in their own column. When the screen size is too narrow to display separate columns, I would like to combine the items into fewer columns. At the narrowest breakpoint, the items will be in one column. For now, a solution that supports two columns for wider screens and one column for narrow screens is sufficient.
There is another catch: the items have a global ordering, which must be preserved within columns.
Below is a snippet showing my current approach using float (based on this answer.) (I have included the global ordering (1-5) in the items to help illustrate.) This approach is close, but it has a problem where there is extra space between group items when they float below the last item in that group. (You might need to play with the media query breakpoint to see the behavior on your device.)
.items {
overflow: auto;
}
.item {
width: 50%;
}
.item.group-a {
float: left;
clear: left;
background-color: #FAF;
}
.item.group-b {
float: right;
clear: right;
background-color: #AAF;
}
#media only screen and (max-width: 400px) {
.item.group-a, .item.group-b {
float: none;
width: 100%;
}
}
<div class="items">
<div class="item group-a">
1. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla finibus ipsum quis nibh pretium commodo.
</div>
<div class="item group-b">
2. Quisque dolor ex, maximus non orci vel, luctus rhoncus lectus. Aliquam vulputate lacus et ipsum placerat commodo.
</div>
<div class="item group-a">
3. Cras gravida rhoncus elit, eu porttitor ipsum tempor at. Sed blandit pulvinar purus, eget pellentesque arcu rhoncus in.
</div>
<div class="item group-a">
4. Morbi accumsan, lectus a hendrerit congue, sapien dolor accumsan purus, eu iaculis nulla turpis ut sapien.
</div>
<div class="item group-b">
5. Aliquam elementum sapien ut dignissim lacinia. Etiam in nulla feugiat, porta massa at, tempor nulla. Suspendisse ullamcorper at ligula ut auctor.
</div>
</div>
In the production system, the number of items, group assignment, and ordering can change, so I cannot depend on the particular items or their ordering shown here. I will know the possible groups in advance.
Here are images of the behavior in case the snippet doesn't work for you. This first image shows the items combined into a single column for a narrow viewport. Note that the items are in order.
This second image shows the items split into two columns. Note that the the gap between items 2 and 5 is not intentional and is what I am trying to get rid of.
This is new development, so I'm not tied to any particular HTML or approach. I was attempting to accomplish this using only CSS for simplicity, but if the consensus is that JavaScript is necessary, that's okay. I saw some answers using flex order to re-order items, but I didn't see how I could design a system to support that generally when I don't know which items/groups/orders are coming out of the system.
At some point I would like to support more than two columns. Ideally, I would have a maximum of five groups/columns for the widest screens, then, as screens get narrower: three, two, and just one column. (There are business rules that dictate how groups can be combined.)
This answer offsetting the float doesn't work for me because the items are dynamic so I don't know in advance which floats might need offsetting. This answer about multi-col doesn't work because I must separate the items by their group. I am not just trying to layout a homogenous list of items in a columnar format.
Thanks!
If your container height can be set before hand, you have a solution using flex display.
Order is used to set the columns as you want, and a pseudo element is used as a spacer.
For a solution with more than 3 columns, since there are only 2 pseudos available, you would need extra elements to act as separators
.items {
overflow: auto;
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 90vh;
}
.item {
width: 50%;
}
.item.group-a {
background-color: #FAF;
order: 10;
}
.item.group-b {
background-color: #AAF;
order: 20;
}
.items:before {
content: "";
order: 15;
height: 100vh;
}
#media only screen and (max-width: 400px) {
.item.group-a, .item.group-b {
width: 100%;
}
.item.group-a {
order: 10;
}
.item.group-b {
order: 10;
}
}
<div class="items">
<div class="item group-a">
1. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla finibus ipsum quis nibh pretium commodo.
</div>
<div class="item group-b">
2. Quisque dolor ex, maximus non orci vel, luctus rhoncus lectus. Aliquam vulputate lacus et ipsum placerat commodo.
</div>
<div class="item group-a">
3. Cras gravida rhoncus elit, eu porttitor ipsum tempor at. Sed blandit pulvinar purus, eget pellentesque arcu rhoncus in.
</div>
<div class="item group-a">
4. Morbi accumsan, lectus a hendrerit congue, sapien dolor accumsan purus, eu iaculis nulla turpis ut sapien.
</div>
<div class="item group-b">
5. Aliquam elementum sapien ut dignissim lacinia. Etiam in nulla feugiat, porta massa at, tempor nulla. Suspendisse ullamcorper at ligula ut auctor.
</div>
</div>
I am learning CSS flexbox and was doing a simple layout where I wanted the first flex child to displayed with 100% width of the parent and rest flex items wrapping below. Also, the wrapped flex items should occupy width in a specific ratio (easy to set with 'flex' property).
To do this I set "flex-basis" property of first flex item to 100% and set flex property of next 2 to the ratio I want. Here is what the pertinent CSS looks like (link to complete fiddle is below):
.main{
max-width: 1000px;
margin: 100px auto;
display: flex;
flex-flow: row wrap;
}
/*using ususal shorthand notation*/
.flex-item:nth-child(1) {
flex:1 100%;
}
.flex-item:nth-child(2) {
flex:2;
}
.flex-item:nth-child(3) {
flex:3;
}
This should set the first item's width to 1000px and for the next two as 400px and 600px respectively; wrapped and displayed below the first child.
But for some reason the CSS breaks, and the 2nd and 3rd items are pushed outside main container.
What more strange is that adding margin to the flex items fixes the whole thing and I don't understand how this is happening (I must be doing something stupid). Even addding some border or padding to the '.flex-item' rule works.
.flex-item{
margin: 5px;
}
Here is the JS Fiddle. You can try un-commenting the '.flex-item' rule in CSS to see what is going on.
I was lazy not to add the any prefixes (since almost every new browser supports it) ,but the problem is same across latest FF, IE and chrome.
The second and third elements have 0 width, so they can fit in any place ..
That's way they stay in the first line.
just set 1px for basis, and they will be in the second row
*{
box-sizing: border-box;
padding: 0;
margin: 0;
}
body{
font-family: 'Raleway', Helvetica, sans-serif;
font-size: 14px;
font-weight: 300;
color: #555;
}
.main{
max-width: 1000px;
margin: 20px auto;
border: 1px dotted #999;
padding: 20px;
display: flex;
flex-flow: row wrap;
}
/* adding any border, margin, padding rules here fixes it */
.flex-item:nth-child(2) {
flex:2 1px;
background-color: lightyellow;
}
.flex-item:nth-child(3) {
flex:3 1px;
}
.flex-item:nth-child(1) {
flex:1 100%;
}
<div class="main">
<p class="flex-item">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin non consequat lorem. In dignissim mauris eu est commodo, ac ullamcorper dui facilisis. Sed feugiat eros quis facilisis feugiat. Pellentesque eu quam egestas, facilisis augue eu, aliquam mi. Nunc nunc metus, eleifend id finibus sit amet, imperdiet eget mi.
</p>
<p class="flex-item">
In dignissim mauris eu est commodo, ac ullamcorper dui facilisis. Sed feugiat eros quis facilisis feugiat. Pellentesque eu quam egestas, facilisis augue eu, aliquam mi. Nunc nunc metus, eleifend id finibus sit amet, imperdiet eget mi.
</p>
<p class="flex-item">
In dignissim mauris eu est commodo, ac ullamcorper dui facilisis. Sed feugiat eros quis facilisis feugiat. Pellentesque eu quam egestas, facilisis augue eu, aliquam mi. Nunc nunc metus, eleifend id finibus sit
.flex-item:nth-child(2) {
flex:2 1px;
}
.flex-item:nth-child(3) {
flex:3 1px;
}