CSS Flexbox - varying height of elements on wrap - css

I have a simple layout with varying size elements that I am trying to put together for a dashboard.
div {
padding: 5px 5px 5px 5px;
margin: 1px 1px 1px 1px;
display: flex;
}
div.first {
border: 1px dotted lightpink;
}
div.second {
border: 1px dotted orange;
}
div.third {
border: 1px dotted green;
}
div.fourth {
border: 1px dotted fuchsia;
}
<div style="display: flex; height: 500px">
<div class="first" style="flex: 0 60%;flex-wrap: wrap;align-items;stretch;align-content:stretch">
<div class="first" style="flex: 1 100%; align-self: flex-start">
Title text
</div>
<div class="second" style="flex: 2 auto">
Content A
</div>
<div class="third" style="flex: 1 auto">
Content B
</div>
<div class="fourth" style="flex: 1 auto">
<div style="height: 66px; align-self:flex-end">
<div style="align-self: flex-end">
Content C
</div>
</div>
</div>
</div>
<div class="second" style="flex: 1 auto; align-items: flex-end">
Content D
</div>
</div>
Codepen link:
http://codepen.io/korgmatose/pen/qqKzry?editors=1100
I want to fill the second row (Content A,B,C) so that it starts just beneath Title Text.
But making align-items flex-start will not allow the second row to fill the remaining space, and setting a height to 100% on one of the items in that row only sets the height to the parent container, thus rendering the div's outside the bottom border.

Like #kukkuz said I would also recommend doing it this way. Just put the content A, B, C in a separate container, in this case #content and add display: flex, flex-direction: column and flex: 1 to it and please do not use inline styling for styling your HTML since it makes your code muss less readable. Most recommended way is to put your CSS code into a separate file and link it to your HTML.
The following code is an example of how you could do the markup of your desired layout without any inline styles.
HTML
<div id="wrapper">
<div class="left">
<div class="title">Title text</div>
<div id="content">
<div class="second">Content A</div>
<div class="third">Content B</div>
<div class="fourth">Content C</div>
</div>
</div>
<div class="right">Content D</div>
</div>
CSS
div {
padding: 5px 5px 5px 5px;
margin: 1px 1px 1px 1px;
}
#wrapper {
display: flex;
height: 500px;
}
.left {
flex: 3;
display: flex;
flex-direction: column;
}
#content{
flex: 1;
display: flex;
padding: 0;
}
.second,
.third,
.fourth {
flex: 1;
}
.third {
border: 1px dotted green;
}
.fourth {
display: flex;
align-items: flex-end;
border: 1px dotted fuchsia;
}
.right {
flex: 2;
}
.left,
.title {
border: 1px dotted lightpink;
}
.right,
.second {
border: 1px dotted orange;
}
div {
padding: 5px 5px 5px 5px;
margin: 1px 1px 1px 1px;
}
#wrapper {
display: flex;
height: 500px;
}
.left {
flex: 3;
display: flex;
flex-direction: column;
}
#content {
flex: 1;
display: flex;
padding: 0;
}
.second,
.third,
.fourth {
flex: 1;
}
.third {
border: 1px dotted green;
}
.fourth {
display: flex;
align-items: flex-end;
border: 1px dotted fuchsia;
}
.right {
flex: 2;
}
.left,
.title {
border: 1px dotted lightpink;
}
.right,
.second {
border: 1px dotted orange;
}
<div id="wrapper">
<div class="left">
<div class="title">Title text</div>
<div id="content">
<div class="second">Content A</div>
<div class="third">Content B</div>
<div class="fourth">Content C</div>
</div>
</div>
<div class="right">Content D</div>
</div>

div {
padding: 5px 5px 5px 5px;
margin: 1px 1px 1px 1px;
display: flex;
}
div.first {
border: 1px dotted lightpink;
}
div.second {
border: 1px dotted orange;
}
div.third {
border: 1px dotted green;
}
div.fourth {
border: 1px dotted fuchsia;
}
<div style="display: flex;">
<div class="first" style="flex: 0 60%;flex-wrap: wrap;align-items;stretch;align-content:stretch">
<div class="first" style="flex: 1 100%; align-self: flex-start">
Title text
</div>
<div class="second" style="flex: 2 auto">
Content A
</div>
<div class="third" style="flex: 1 auto">
Content B
</div>
<div class="fourth" style="flex: 1 auto">
<div style="height: 66px; align-self:flex-end">
<div style="align-self: flex-end">
Content C
</div>
</div>
</div>
</div>
<div class="second" style="flex: 1 auto; align-items: flex-end">
Content D
</div>
</div>
Something like this?

Related

How to make div overflow instead of going on new line?

Want to create a slider containing 3 image containers and need all of them in the same row. All image containers are same size, but the size of slider is around 2.5 images, so the third one should overflow instead of going to new row. Example:
How it should look
What i have for now
html
<div class="image-slide-wrapper">
<div class="images-section">
<div class="image-slide">
<div class="slide-img">
</div>
</div>
<div class="image-slide">
<div class="slide-img">
</div>
</div>
<div class="image-slide">
<div class="slide-img">
</div>
</div>
</div>
</div>
scss
.image-slide-wrapper {
float: left;
height: 55%;
width: 100%;
.images-section {
float: left;
height: 85%;
width: 100%;
border: 1px solid grey;
border-radius: 8px;
overflow: hidden;
padding: 0.125rem;
}
.image-slide {
float: left;
height: 100%;
width: 100px;
margin-right: 0.25rem;
.slide-img {
float: left;
height: 100%;
width: 100%;
border-radius: 0.35rem;
background-color: #e9e9e9;
in the text slider is images-section class and image container is image-slide class. Forgot to mention that I have to go with float to make consistent with the rest of the code.
<div style="overflow: hidden; width: 250px;">
<div style="width: max-content">
<img style="width: 100px;height: 100px;border: 1px solid black;" src="...">
<img style="width: 100px;height: 100px;border: 1px solid black;" src="...">
<img style="width: 100px;height: 100px;border: 1px solid black;" src="...">
</div>
</div>
You could remove float from the thumb elements and use display: flex and flex-flow: row nowrap on the container
.container {
height: 100px;
width: 250px;
border: 1px solid grey;
border-radius: 8px;
overflow: hidden;
padding: 0.125rem;
display: flex;
flex-flow: row nowrap;
}
.image-slide {
height: calc(100% - .25rem);
flex: 1 0 100px;
margin-right: 0.25rem;
border: 1px #ccc solid;
}
<div class="container">
<div class="image-slide"></div>
<div class="image-slide"></div>
<div class="image-slide"></div>
<div class="image-slide"></div>
</div>
This works. You can add display:flex; and flex-wrap:nowrap; to .image-slide-wrapper class.
.main {
float: left;
height: 85%;
width: 100%;
border: 1px solid grey;
border-radius: 8px;
overflow: hidden;
padding: 0.125rem;
display:flex;
flex-wrap:nowrap;
}
.slider {
float: left;
height: 100%;
width: 300px;
margin-right: 0.25rem;
display: block;
}
<div class="main">
<div class="slider">
<img class="img" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTBYCs940TLL3tx_nyn7fVeidXWZyfOKV5QrQ&usqp=CAU">
</div>
<div class="slider">
<img class="img" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTBYCs940TLL3tx_nyn7fVeidXWZyfOKV5QrQ&usqp=CAU">
</div>
<div class="slider">
<img class="img" src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTBYCs940TLL3tx_nyn7fVeidXWZyfOKV5QrQ&usqp=CAU">
</div>
</div>

Flexbox flex-grow property not respected when flex item contains an input element

I am using flexbox to make a chat UI. First using the flex-grow property I divide the layout in 2 columns with a ratio 2/5 and then I divide those 2 columns in rows with a ratio 1/9 for the first column and 5/1 for the second one.
This is what I have when I haven't added the input elements to the HTML code:
https://codepen.io/thenr/pen/PoooyEN
#chat {
display: flex;
width: 100%;
height: calc(100vh - 2em);
overflow-y: hidden;
}
#friends {
flex-grow: 2;
display: flex;
flex-direction: column;
border: 1px solid black;
}
#messages {
flex-grow: 5;
display: flex;
flex-direction: column;
border: 1px solid black;
}
#searchfriend {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 120px;
border: 1px solid black;
background-color: blue;
}
#searchfriend input[type="text"] {
margin: 0;
padding: 1em;
border: 0;
border-radius: 0px;
background-color: #d1d1d1;
}
#friendslist {
flex-grow: 9;
border: 1px solid black;
overflow-y: auto;
}
.friend {
height: 100px;
border: 1px solid black;
}
#chatmessages {
flex-grow: 5;
border: 1px solid black;
}
#writemessage {
flex-grow: 1;
border: 1px solid black;
}
<div id="chat">
<!-- friends -->
<div id="friends">
<div id="searchfriend">
</div>
<div id="friendslist">
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
</div>
</div>
<!-- chat -->
<div id="messages">
<div id="chatmessages">
</div>
<div id="writemessage">
</div>
</div>
</div>
The problem is that when I add the input elements to the HTML code the ratios I had set are not respected and the flex items containing those input elements make bigger, and I don't want that to happen. Same HTML code but with the input elements added:
https://codepen.io/thenr/pen/RwwweQN
#chat {
display: flex;
width: 100%;
height: calc(100vh - 2em);
overflow-y: hidden;
}
#friends {
flex-grow: 2;
display: flex;
flex-direction: column;
border: 1px solid black;
}
#messages {
flex-grow: 5;
display: flex;
flex-direction: column;
border: 1px solid black;
}
#searchfriend {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 120px;
border: 1px solid black;
background-color: blue;
}
#searchfriend input[type="text"] {
margin: 0;
padding: 1em;
border: 0;
border-radius: 0px;
background-color: #d1d1d1;
}
#friendslist {
flex-grow: 9;
border: 1px solid black;
overflow-y: auto;
}
.friend {
height: 100px;
border: 1px solid black;
}
#chatmessages {
flex-grow: 5;
border: 1px solid black;
}
#writemessage {
flex-grow: 1;
border: 1px solid black;
}
<div id="chat">
<!-- friends -->
<div id="friends">
<div id="searchfriend">
<input type="text" name="" id="searchtext" placeholder="Search friend...">
</div>
<div id="friendslist">
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
<div class="friend"></div>
</div>
</div>
<!-- chat -->
<div id="messages">
<div id="chatmessages">
</div>
<div id="writemessage">
<form action="" id="formchat">
<input type="text" name="msgtext" id="msgtext" autocomplete="off">
<button id="msgsend">Send</button>
</form>
</div>
</div>
</div>
You may use the flex shorthand flex:2 / flex: 5 instead flex-grow:2 / flex-grow:5 .
It will avoid to have to set flex-shrink and flex-basis too.

How to set CSS to grow parent height only from one of two children?

I would like to have the parent (orange border) only grow to the size of the first child (grey background) and have the second child overflow vertically.
This is what I have:
This is what I want:
Codepen: https://codepen.io/gbucher/pen/wPGBpN
HTML:
<div class='parent'>
<div class='child1'>
</div>
<div class='child2'>
<div class='elem'>
A
</div>
<div class='elem'>
B
</div>
<div class='elem'>
C
</div>
<div class='elem'>
D
</div>
<div class='elem'>
E
</div>
</div>
</div>
CSS:
.parent {
border: 2px solid orange;
display: flex;
/* How to make it work without a fixed
height ?
height:60px;
*/
}
.child1 {
height: 60px;
width: 300px;
background: #888;
}
.child2 {
display: flex;
flex-direction: column;
overflow-y: auto;
}
.elem {
border: 1px solid black;
margin-top: -1px;
padding: 3px;
width: 10rem;
}
When computing the size of a parent, absolute positioned children are ignored.
The solution is thus to use a scroll wrapper around the second child. The wrapper should have position: relative and the scrolling child should have position: absolute.
.parent {
border: 2px solid orange;
display: flex;
}
.child1 {
height: 70px;
flex-grow: 1;
background: #888;
}
.child2 {
display: flex;
flex-direction: column;
position: absolute;
background: orange;
}
.scroll {
position: relative;
overflow-y: scroll;
overflow-x: hidden;
width: 323px;
background: green;
}
.elem {
border: 1px solid black;
margin-top: -1px;
padding: 3px;
width: 300px;
}
<div class='parent'>
<div class='child1'>
one
</div>
<div class='scroll'>
<div class='child2'>
<div class='elem'>
A
</div>
<div class='elem'>
B
</div>
<div class='elem'>
C
</div>
<div class='elem'>
D
</div>
<div class='elem'>
E
</div>
</div>
</div>
</div>

ie 11: flex grow parent issue

I have such code:
https://plnkr.co/edit/ZAEzfAOCO0ZcSq2OR4Lp?p=preview
but this isn't working in ie, until I add height:0 (it's a very bad idea on parent element)
<body>
<div class="container">
<div class="container-item container-item-1"></div>
<div class="container-item container-item-2"></div>
<div class="container-item container-item-3"></div>
</div>
</body>
body, html {
min-height: 100%;
height: 100%;
}
.container {
width: 100%;
min-height: calc(100% - 80px);
margin: 30px;
padding: 20px;
border: 1px solid gray;
border-radius: 16px;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
.container-item {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
content: "someText";
border-bottom: 1px solid #cecece;
}
.container-item-1 {
background-color: red;
}
.container-item-2 {
background-color: orange;
}
.container-item-3 {
background-color: green;
}
everything works fine in chrome and ff
(my parents should expand to fit parent)
Important!
I need a flexible solution, my code can have a lot of nested div's (not a constant value) between body and content divs.
for example:
<body>
<div>
<div>
<div class="container">
<div class="container-item container-item-1"></div>
<div class="container-item container-item-2"></div>
<div class="container-item container-item-3"></div>
</div>
</div>
</div>
</body>
or
<body>
<div>
<h3>text</h3>
<div class="container">
<div class="container-item container-item-1"></div>
<div class="container-item container-item-2"></div>
<div class="container-item container-item-3"></div>
</div>
</div>
</body>
If you have an unknown or nested markup before the container, you could add an extra wrapper within it (here inner), to overcome IE's min-height bug.
Fiddle sample 1 -- Fiddle sample 2
Stack snippet sample 1
html, body {
margin: 0;
}
.container {
display: flex;
}
.container .inner {
width: 100%;
min-height: calc(100vh - 100px);
margin: 30px;
padding: 20px;
border: 1px solid gray;
border-radius: 16px;
display: flex;
flex-direction: column;
}
.container-item {
flex-grow: 1;
border: 1px solid #cecece;
}
.container-item-1 {
background-color: red;
}
.container-item-2 {
background-color: orange;
}
.container-item-3 {
background-color: green;
}
<div>
<h3>text</h3>
<div class="container">
<div class="inner">
<div class="container-item container-item-1">
</div>
<div class="container-item container-item-2">
</div>
<div class="container-item container-item-3">
</div>
</div>
</div>
</div>
Stack snippet sample 2
html, body {
margin: 0;
}
.container {
display: flex;
}
.container .inner {
width: 100%;
min-height: calc(100vh - 100px);
margin: 30px;
padding: 20px;
border: 1px solid gray;
border-radius: 16px;
display: flex;
flex-direction: column;
}
.container-item {
flex-grow: 1;
border: 1px solid #cecece;
}
.container-item-1 {
background-color: red;
}
.container-item-2 {
background-color: orange;
}
.container-item-3 {
background-color: green;
}
<div>
<div>
<div class="container">
<div class="inner">
<div class="container-item container-item-1">
</div>
<div class="container-item container-item-2">
</div>
<div class="container-item container-item-3">
</div>
</div>
</div>
</div>
</div>

Flexbox align column to the right if there is only one column

I have a two column flexbox layout. However, sometimes there is only one column, in which case the column should be aligned to the right. Currently the column is aligned to the left.
https://codepen.io/sleepydada/pen/rzVRxL
HTML:
<div class="answers">
<div class="answer">first answer</div>
<div class="answer">second answer</div>
</div>
<div class="answers">
<div class="answer">first answer</div>
</div>
SCSS:
* {
box-sizing: border-box;
}
.answers {
border: 2px solid black;
margin-bottom: 20px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
&:first-of-type {
background: #ccc;
}
.answer {
background: crimson;
margin: 20px 0;
border: 1px solid blue;
flex: 0 0 33.3333%;
}
}
You can add this CSS:
.answer:only-of-type {
margin-left: auto;
}
From MDN
The :only-of-type CSS pseudo-class represents an element that has no
siblings of the same type.
codepen
* {
box-sizing: border-box;
}
.answers {
border: 2px solid black;
margin-bottom: 20px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.answers:first-of-type {
background: #ccc;
}
.answers .answer {
background: crimson;
margin: 20px 0;
border: 1px solid blue;
flex: 0 0 33.3333%;
}
.answers .answer:only-of-type {
margin-left: auto;
}
<div class="answers">
<div class="answer">first answer</div>
<div class="answer">second answer</div>
</div>
<div class="answers">
<div class="answer">first answer</div>
</div>
You can add an invisible div with height set to 0
* {
box-sizing: border-box;
}
.invisible {
height: 0;
border: none !important;
}
.answers {
border: 2px solid black;
margin-bottom: 20px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.answers:first-of-type {
background: #ccc;
}
.answers .answer {
background: crimson;
margin: 20px 0;
border: 1px solid blue;
flex: 0 0 33.3333%;
}
<div class="answers">
<div class="answer">first answer</div>
<div class="answer invisible"><!--invisible div--></div>
<div class="answer">second answer</div>
</div>
<div class="answers">
<div class="answer invisible"><!--invisible div--></div>
<div class="answer">first answer</div>
</div>

Resources