CSS Flex Box Layout: full-width row and columns - css

Hello fellow programmers!
I've got a simple box-layout which I would love to achieve using flexbox, but I simply can't figure it out. It should look like this image.
So basically a row and two columns, with the row being fixed at lets say 100px in height, but all in one container. My code so far is:
#productShowcaseContainer {
display: inline-flex;
flex-flow: row wrap;
height: 600px;
width: 580px;
background-color: rgb(240, 240, 240);
}
#productShowcaseTitle {
display: inline-block;
height: 100px;
width: 100%;
background-color: rgb(200, 200, 200);
}
#productShowcaseDetail {
flex: 3;
background-color: red;
}
#productShowcaseThumbnailContainer {
flex: 2;
background-color: blue;
}
<div id="productShowcaseContainer">
<div id="productShowcaseTitle"></div>
<div id="productShowcaseDetail"></div>
<div id="productShowcaseThumbnailContainer"></div>
</div>
I know this can be achieved in many ways, but I would really prefer to use CSS Flex.

You've almost done it. However setting flex: 0 0 <basis> declaration to the columns would prevent them from growing/shrinking; And the <basis> parameter would define the width of columns.
In addition, you could use CSS3 calc() expression to specify the height of columns with the respect to the height of the header.
#productShowcaseTitle {
flex: 0 0 100%; /* Let it fill the entire space horizontally */
height: 100px;
}
#productShowcaseDetail,
#productShowcaseThumbnailContainer {
height: calc(100% - 100px); /* excluding the height of the header */
}
#productShowcaseContainer {
display: flex;
flex-flow: row wrap;
height: 600px;
width: 580px;
}
#productShowcaseTitle {
flex: 0 0 100%; /* Let it fill the entire space horizontally */
height: 100px;
background-color: silver;
}
#productShowcaseDetail {
flex: 0 0 66%; /* ~ 2 * 33.33% */
height: calc(100% - 100px); /* excluding the height of the header */
background-color: lightgray;
}
#productShowcaseThumbnailContainer {
flex: 0 0 34%; /* ~ 33.33% */
height: calc(100% - 100px); /* excluding the height of the header */
background-color: black;
}
<div id="productShowcaseContainer">
<div id="productShowcaseTitle"></div>
<div id="productShowcaseDetail"></div>
<div id="productShowcaseThumbnailContainer"></div>
</div>
(Vendor prefixes omitted due to brevity)
Alternatively, if you could change your markup e.g. wrapping the columns by an additional <div> element, it would be achieved without using calc() as follows:
<div class="contentContainer"> <!-- Added wrapper -->
<div id="productShowcaseDetail"></div>
<div id="productShowcaseThumbnailContainer"></div>
</div>
#productShowcaseContainer {
display: flex;
flex-direction: column;
height: 600px; width: 580px;
}
.contentContainer { display: flex; flex: 1; }
#productShowcaseDetail { flex: 3; }
#productShowcaseThumbnailContainer { flex: 2; }
#productShowcaseContainer {
display: flex;
flex-direction: column;
height: 600px;
width: 580px;
}
.contentContainer {
display: flex;
flex: 1;
}
#productShowcaseTitle {
height: 100px;
background-color: silver;
}
#productShowcaseDetail {
flex: 3;
background-color: lightgray;
}
#productShowcaseThumbnailContainer {
flex: 2;
background-color: black;
}
<div id="productShowcaseContainer">
<div id="productShowcaseTitle"></div>
<div class="contentContainer"> <!-- Added wrapper -->
<div id="productShowcaseDetail"></div>
<div id="productShowcaseThumbnailContainer"></div>
</div>
</div>
(Vendor prefixes omitted due to brevity)

Just use another container to wrap last two divs.
Don't forget to use CSS prefixes.
#productShowcaseContainer {
display: flex;
flex-direction: column;
height: 600px;
width: 580px;
background-color: rgb(240, 240, 240);
}
#productShowcaseTitle {
height: 100px;
background-color: rgb(200, 200, 200);
}
#anotherContainer{
display: flex;
height: 100%;
}
#productShowcaseDetail {
background-color: red;
flex: 4;
}
#productShowcaseThumbnailContainer {
background-color: blue;
flex: 1;
}
<div id="productShowcaseContainer">
<div id="productShowcaseTitle">1</div>
<div id="anotherContainer">
<div id="productShowcaseDetail">2</div>
<div id="productShowcaseThumbnailContainer">3</div>
</div>
</div>

This is copied from above, but condensed slightly and re-written in semantic terms. Note: #Container has display: flex; and flex-direction: column;, while the columns have flex: 3; and flex: 2; (where "One value, unitless number" determines the flex-grow property) per MDN flex docs.
#Container {
display: flex;
flex-direction: column;
height: 600px;
width: 580px;
}
.Content {
display: flex;
flex: 1;
}
#Detail {
flex: 3;
background-color: lime;
}
#ThumbnailContainer {
flex: 2;
background-color: black;
}
<div id="Container">
<div class="Content">
<div id="Detail"></div>
<div id="ThumbnailContainer"></div>
</div>
</div>

Related

How can I fix column spanning issue in css flex box

check image for better understanding
I want box three(blue) to come right below box one(red) currently white space inbetween them.
Here, the content height of the box two(gree) is greater than box one hence stretching that extra space. I need to cover up that empty white space .
I can not use GRID here, as I already used react-bootstrap Row/Col on my entier react site.
https://codesandbox.io/s/suspicious-david-i2vnht?file=/src/index.js:23-322
I used flexbox and tried using
aligh-items:flex-start/flex-end
does not work.
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: sans-serif;
}
#app {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
}
.one,
.two,
.three,
.four {
flex-grow: 1;
}
/* .one,.two,.three,.four, .five,.six{
flex-grow:1;
width:33%;
} */
.one {
background: red;
padding: 50px;
order: 0;
width: 67%;
}
.two {
background: green;
order: 1;
padding: 1rem;
width: 33%;
height: 30vh;
}
.three {
background: blue;
order: 2;
width: 67%;
height: 50vh;
}
.four {
background: tomato;
order: 3;
width: 33%;
}
.five {
background: goldenrod;
order: 1;
}
.six {
background: orange;
order: 0;
}
<div id="app">
<div class="one">ONE</div>
<div class="three">THREE</div>
<div class="two">Two</div>
<div class="four">FOUR</div>
<!-- <div class="five">Five</div> -->
<!-- <div class="six">Six</div> -->
</div>

How to fit 2 elements to page height?

I'm developing an app with the interface that is supposed to fit the page (only some internal elements may have scrolling). The basic layout consists of a header and the main section:
<div class="page">
<Navigation/> <!-- a Vue component -->
<main class="page__main">
...
</main>
</div>
currently, CSS has hardcoded height of the header (Navigation):
.page {
height: 100vh;
}
.page__main {
height: calc(100vh - 80px); /* 80px is the height of the header */
}
I'd like to get rid of this hardcoded bit but make sure .page__main's height gets no larger than 100vh - height of Navigation. Is there a way to do this without JS? I suspect that there are some options that can be used with
.page {
height: 100vh;
display: flex;
flex-direction: column;
}
but just using that with
.page__main {
flex-shrink: 1;
}
doesn't work: .page__main has children which use height in percents and once I set flex-shrink: 1; instead of height: calc(100vh - 80px); those grow and the interface is broken.
To illustrate the problem better, here's the current state:
body { padding: 0; margin: 0; }
.page {
height: 100vh;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
height: calc(100vh - 80px);
}
.part1 {
height: 50%;
background: #eeeeee;
overflow-y: scroll;
}
.part2 {
height: 50%;
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
and here's what happen when I try to "set height" via flex:
body { padding: 0; margin: 0; }
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
flex-shrink: 1;
}
.part1 {
height: 50%;
background: #eeeeee;
overflow-y: scroll;
}
.part2 {
height: 50%;
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
You can consider a nested flexbox container and don't forget the use of min-height:0; to allow the elements to shrink.
body { padding: 0; margin: 0; }
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__navigation {
height: 80px;
background: gray;
}
.page__main {
flex-grow: 1; /* Fill the remaining space*/
display:flex; /* Nested Container*/
flex-direction:column;
min-height:0; /* Allow the element to shrink */
}
.part1 {
flex-basis: 50%;
background: #eeeeee;
overflow-y: scroll; /* Allow the element to shrink */
}
.part2 {
flex-basis: 50%;
min-height:0; /* Allow the element to shrink */
background: #cccccc;
}
<div class="page">
<div class="page__navigation">nav stuff</div>
<main class="page__main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</main>
</div>
Use flex-grow. Keep everything as the second one (flex one) and change:
Edit
.page {
height: 100vh;
display: flex;
flex-direction: column;
background: blue;
}
.page__main {
height: 100%;
min-height: 0;
flex: 1 1 auto;
}
Three value flex means flex: flex-grow | flex-shrink | flex-basis.
Flex-grow tells our element whether or not it can take up additional space.
Flex-shrink works very similarly to flex-grow, only instead of dealing with extra space, it deals with space not needed by an elements content.
Flex basis is best used when in conjunction with either flex-shrink or flex-grow.
You can check this article to understand better.
I would suggest css-grid approach : -
.page {
background: gray;
display: grid;
grid-template-rows: 100px auto;
height: 100vh;
color: white;
}
.nav {
grid-row: 1/2;
background: brown;
}
.main {
grid-row: 2/3;
background: green;
display: grid;
grid-template-rows: 30% 70%;
}
.part1 {
overflow: auto
}
.part2 {
background: blue
}
<div class="page">
<div class="nav">Nav</div>
<div class="main">
<div class="part1">
this one usually has more elements than it could contain and those are shown with scrolling
<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line<br>line
</div>
<div class="part2">
some
</div>
</div>
</div>
</div>

flexbox makes content disappear

I'm playing around with flexbox to get the hang of it but I am running into some issues. My goal is to have the window separated by four background colors where the first is just a header row and then the rest of the page is filled by 3 columns each a different background color. But for some reason if I write display: flex it doesn't show anything. Can someone explain to me how to get this desired effect?
.container {
width: 100%;
height: 100%;
}
.header {
height: 150px;
background-color: red;
}
.col-container {
widows: auto;
height: auto;
display: flex;
flex-direction: row;
}
.col {
flex: 1;
}
.col-container:nth-child(1) {
background: green;
}
.col-container:nth-child(2) {
background: blue;
}
.col-container:nth-child(3) {
background: yellow;
}
<body>
<div class="container">
<div class="header"></div>
<div class="col-container">
<div class="col"></div>
<div class="col"></div>
<div class="col"></div>
</div>
</div>
</body>
Here is a working example:
.container {
width: 100%;
height: 100%;
}
.header {
height: 150px;
background-color: red;
}
.col-container {
widows: auto;
height: auto;
display: flex;
flex-direction: row;
}
.col-1 {
flex: 1 1 33.333%;
background-color: green;
}
.col-2 {
flex: 1 1 33.333%;
background-color: blue;
}
.col-3 {
flex: 1 1 33.333%;
background-color: yellow;
}
<body>
<div class="container">
<div class="header"></div>
<div class="col-container">
<div class="col-1">ts</div>
<div class="col-2">dtd</div>
<div class="col-3">dt</div>
</div>
</div>
</body>
Here's what you needed to fix:
Set flex-direction to row. You most likely want the columns next to each other.
Add the classes to your HTML for the col-1, col-2 and col-3.
You need content in those col classes, or you won't see anything anyway.
I set a flex-basis (the third parameter in the flex shorthand) to 33.333%. You don't necessarily need this, but it's nice to see how much space a particular element will fill or change it.
EDIT For the comments:
body {
margin: 0;
padding: 0;
}
.container {
width: 100%;
height: 100%;
}
.header {
height: 150px;
background-color: red;
}
.col-container {
widows: auto;
height: auto;
display: flex;
flex-direction: row;
height: calc(100vh - 150px);
}
.col-1 {
flex: 1 1 33.333%;
background-color: green;
}
.col-2 {
flex: 1 1 33.3333%;
background-color: blue;
}
.col-3 {
flex: 1 1 33.3333%;
background-color: yellow;
}
<body>
<div class="container">
<div class="header"></div>
<div class="col-container">
<div class="col-1"></div>
<div class="col-2"></div>
<div class="col-3"></div>
</div>
</div>
</body>
Basically, you need to give the col-container a height. To achieve this, I used vh units in the calc statement. It subtracts your header height from the viewport height and gives the remainder. This also removes the necessity for filler content.

Trouble aligning items with flexbox [duplicate]

This question already has an answer here:
Remove space (gaps) between multiple lines of flex items when they wrap
(1 answer)
Closed 4 years ago.
enter code hereI can't really explain it better than this code example.
https://codepen.io/anon/pen/BYeger
I want to make #thing_down_here touch #thing_up_here, but I can't figure out the right combination.
html, body {
margin: 0;
padding: 0;
}
* {
box-sizing: border-box
}
#parent {
width: 100vw;
height: 100vh;
background: cornsilk;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
#thing_up_here {
flex: 1 0 100%;
background: skyblue;
height: 80px;
}
#thing_down_here {
flex: 0 0 50%;
background: lightgreen;
height: 100px;
}
<div id="parent">
<div id="thing_up_here"></div>
<div id="thing_down_here"></div>
</div>
You need to use use the align-content property to set the distribution along the cross-axis.
html, body {
margin: 0;
padding: 0;
}
* {
box-sizing: border-box
}
#parent {
width: 100vw;
height: 100vh;
background: cornsilk;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: flex-start;
}
#thing_up_here {
flex: 1 0 100%;
background: skyblue;
height: 80px;
}
#thing_down_here {
flex: 0 0 50%;
background: lightgreen;
height: 100px;
}
<div id="parent">
<div id="thing_up_here"></div>
<div id="thing_down_here"></div>
</div>
Read more about align-content.
Add align-content: flex-start to #parent
This defines the default behaviour for how flex items are laid out along the cross axis on the current line. Think of it as the justify-content version for the cross-axis (perpendicular to the main-axis).
flex-start: cross-start margin edge of the items is placed on the cross-start line
The default is stretch which is causing your issue
More on it at https://css-tricks.com/snippets/css/a-guide-to-flexbox/
html, body {
margin: 0;
padding: 0;
}
* {
box-sizing: border-box
}
#parent {
width: 100vw;
height: 100vh;
background: cornsilk;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-content: flex-start;
}
#thing_up_here {
flex: 1 0 100%;
background: skyblue;
height: 80px;
}
#thing_down_here {
flex: 0 0 50%;
background: lightgreen;
height: 100px;
}
<div id="parent">
<div id="thing_up_here"></div>
<div id="thing_down_here"></div>
</div>

flexbox how to achieve this specific layout?

Like in the image - http://i65.tinypic.com/aa7ndw.png Examples and live flex configurators are explain only simple examples, or I just don't get it.
Will I be able to use media queries to for example not display a4 when < 800px?
I have always used float and flex is somehow 'different' anyway I would like to know it better, so any help is appreciated.
flex specific example
Apply display: flex to a container and its child elements will be displayed in flex. For this layout, you will want to wrap the elements when width is already filled for the current row.
The header and footer will be width: 100%, taking a full row. #a3 and #a4 will have flex: 1 to distribute the width of their row, taking each one 50% of the width.
div.flex-container{
width: 200px;
height: 300px;
background-color: black;
display: flex;
flex-flow: row wrap;
}
#a1, #a2{
width: 100%;
}
#a3, #a4{
flex: 1;
}
#a5, #a6, #a7{
height: 50px;
width: 80%;
margin: auto;
margin-bottom: 1rem;
}
/* Example styles */
div{
text-align: center;
}
#a1{
background-color: red;
}
#a2{
background-color: limegreen;
}
#a3{
background-color: royalblue;
}
#a4{
background-color: cyan;
}
#a5, #a6, #a7{
background-color: fuchsia;
}
<div class="flex-container">
<div id="a1">a1</div>
<div id="a3">a3</div>
<div id="a4">a4
<div id="a5">a5</div>
<div id="a6">a6</div>
<div id="a7">a7</div>
</div>
<div id="a2">a2</div>
</div>
And yeah, you can use media queries as normal
div.flex-container{
width: 200px;
height: 300px;
background-color: black;
display: flex;
flex-flow: row wrap;
}
#a1, #a2{
width: 100%;
}
#a3, #a4{
flex: 1;
}
#a5, #a6, #a7{
height: 50px;
width: 80%;
margin: auto;
margin-bottom: 1rem;
}
#media (max-width: 800px){
#a4{
display: none;
}
}
/* Example styles */
div{
text-align: center;
}
#a1{
background-color: red;
}
#a2{
background-color: limegreen;
}
#a3{
background-color: royalblue;
}
#a4{
background-color: cyan;
}
#a5, #a6, #a7{
background-color: fuchsia;
}
<div class="flex-container">
<div id="a1">a1</div>
<div id="a3">a3</div>
<div id="a4">a4
<div id="a5">a5</div>
<div id="a6">a6</div>
<div id="a7">a7</div>
</div>
<div id="a2">a2</div>
</div>

Resources