Given the following markup:
<div class="box">
<div class="A">A</div>
<div class="B">B</div>
<div class="C">C</div>
</div>
How do I achieve the following layout:
With the following behavior:
A has fixed width of 150px
Height of C is based on the height of the content inside of it (which changes), but it always remains fixed to the bottom.
The flex container (.box) width takes up the full width of the browser.
B and C always take up the remaining width of the container (.box) after A's 150px of width is taken into account.
What about A's and B's height? Is it fixed or it varies depending on
the content or something else?
The height of the content inside of A will not change, but the height of the content inside of B will change. .box height should equal max(height A, height B + C)
Here's a pen where everything is stubbed out
Your result is conceptually simple, but you need to use more than just 3 consecutive elements to accomplish what you want. Flex box is the bee's knees but it can't magic your layout. You need a separate sub-layout.
HTML
<div class="box flex">
<div class="a">A</div>
<div class="b-c flex column">
<div class="b">B</div>
<div class="c"></div>
</div>
<div>
CSS
.box {
display: flex;
align-items: stretch;
width: 100vw;
}
.a {
flex: 0 0 150px;
}
.b-c {
flex-direction: column;
display: flex;
flex-grow: 1;
}
Related
I'm using Bulma have a column of cards which need to have the same height regardless of the content.
To achieve so I have created the following class
.equal-height
display: flex
flex-direction: column
height: 100%
My HTML looks like
<div class='columns is-multiline'>
<div class='column is-one-fifth'>
<div class='card equal-height'>
<div class='card-content'>
# CONTENT GOES HERE
</div>
<div class='card-footer'>
# FOOTER GOES HERE
</div>
</div>
</div>
<div class='column is-one-fifth'>
<div class='card equal-height'>
<div class='card-content'>
# CONTENT GOES HERE
</div>
<div class='card-footer'>
# FOOTER GOES HERE
</div>
</div>
</div>
</div>
Which produces something like
Now I'm trying to make the card-footer to stick at the bottom of the card like below.
I have tried a few things with flex but they don't really make sense.
Any ideas on how I may do it?
Add "flex: auto;" to '.card-contents' to make the card-footer to stick at the bottom of the card. Here is the working jsfiddle link.
.equal-height {
display: flex;
flex-direction: column;
height: 100%;
}
.equal-height .card-content {
flex: auto;
}
Add this CSS
.card-footer {
margin-top: auto;
}
working demo : https://jsfiddle.net/baLg7940/
UPDATE:
I made a fiddle for testing.
An illustration of what I'd like to achieve: (Rows and columns are Bootstrap 4 rows and columns.)
The page should only have scrollbars if the second row is already
"fully compressed" (0 height) and still the header + first row +
footer can't fit in the viewport.
The second row doesn't have to fill
in all remaining pale green place. It's height can be flexible.
Flexbox? Max-width? Overflow... How should I start? What could be a good solution?
HTML:
<div class="page">
<div class="header">
...<br>...
</div>
<div class="main">
<div class="container-fluid">
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header"> .... </div>
<div class="card-body"> .... </div>
</div>
</div>
<div class="col-6">
<div class="card">
<div class="card-header"> .... </div>
<div class="card-body"> .... </div>
</div>
</div>
</div>
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header"> .... </div>
<div class="card-body scrollable"> THIS <br> SHOULD <br> BE <br> THE <br> SCROLLABLE <br> CONTENT </div>
</div>
</div>
</div>
</div>
</div>
<div class="footer">
...
</div>
</div>
CSS:
div.page {
background-color: palegreen;
display: flex;
flex-direction: column;
min-height: 100vh;
max-height: 100vh;
}
div.header,
div.footer {
background-color: grey;
padding: 0.5em;
}
div.main {
display: flex;
flex-grow: 1;
}
div.row {
margin-top: 1em;
}
div.scrollable {
/* ??? */
}
The key is how you calculate the height for the <main> and usage of flex, esp. flex-grow, flex-shrink.
<header>, <main> and <footer>
The second row doesn't have to fill in all remaining pale green place. It's height can be flexible.
So I assume you want the <header> and <footer> always stay on top and bottom. Instead of regular absolute positioning approach, I want to explicitly set the heights for them, as well as for <main>.
HTML
<header>header</header>
<main class="container-fluid"></main>
<footer>footer</footer>
SCSS
$custom-header-height: 3rem;
$custom-footer-height: 2rem;
header, footer {
background-color: var(--gray);
// In order to position the text to the center, like your picture
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
}
header {
height: $custom-header-height;
}
footer {
height: $custom-footer-height;
}
main {
// Calculate the height for main, which is 100% viewport height -
// height of header - height of footer
height: calc(100vh - #{$custom-header-height} - #{$custom-footer-height});
background-color: var(--teal);
}
Result
This gives you the playground you can build stuff on.
First Row
The first row is free to expand as high as its contents, but you don't want it to take up any free space. That's why you set flex-grow: 0;. Also when you resize the window and the space for first row is shrinking, you don't want the cards go over the row. That's why you set flex-shrink: 0;. We might as well use the shortcut flex: 0 0 auto; for those 2.
But in order to set that, the first row (as well as the second row) needs to be flexbox children. So we set display:flex; on its parent - <main>.
HTML
<header>header</header>
<main class="container-fluid">
<div class="row first-row">
<div class="col-6">
<div class="card">...</div>
</div>
<div class="col-6">
<div class="card">...</div>
</div>
</div>
</main>
<footer>footer</footer>
SCSS (In addition)
main {
display: flex;
flex-flow: column nowrap;
}
.first-row {
// I purposely make first row's background yellow so that you can see it
background-color: var(--yellow);
flex: 0 0 auto;
}
Result
Second Row
The key here is to make the <card> not to grow when there is space, but shrink on limited space, which is the default of flexbox children: flex: 0 1 auto;
But again, in order to use that, its parent needs to display: flex;. Here the parent is col-6 since we want to use bootstrap grid system.
HTML
<header>header</header>
<main class="container-fluid">
<div class="row first-row">
<div class="col-6">
<div class="card">...</div>
</div>
<div class="col-6">
<div class="card">...</div>
</div>
</div>
<div class="row second-row">
<div class="col-6">
<div class="card">
...
...
...
</div>
</div>
</div>
</main>
<footer>footer</footer>
SCSS (In addition)
.second-row {
// I purposely make second row's background to be blue so that you can see it
background-color: var(--blue);
// Any column, class name starts as "col-"
[class*="col-"] {
display: flex;
flex-flow: column nowrap;
// So that when the second row is compressed to 0, it doesn't show
// the row completely.
min-height: 0;
.card {
// flex-grow: 0;
// flex-shrink: 1;
// Might as well just set it
// flex: 0 1 auto;
// But this is the default of flexbox children so we don't need to set
// it here.
.card-body {
overflow-y: auto;
}
}
}
}
Result
The second row doesn't have to fill in all remaining pale green place. It's height can be flexible.
An illustration of what I'd like to achieve
The page should only have scrollbars if the second row is already "fully compressed" (0 height) and still the header + first row + footer can't fit in the viewport
Notes
There is still a funkiness when the second row is fully compressed. The scrollbar is still hanging there and I don't know how to get rid of it.
The code can be simplified a little bit without usage of bootstrap grid system.
Demo
https://codepen.io/anon/pen/XBqyxZ
Sorry for this lengthy post. If you want to know more about flexbox, here is a great guide: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
I would but a set the height (or max-height if you prefer) on the card and then set overflow to scroll.
<html>
<div class="box">
<div class="content">
Dispassionate extraterrestrial observer citizens of distant epochs
permanence of the stars billions upon billions vastness is bearable only
through love brain is the seed of intelligence.
</div>
</div>
</html>
<style>
.box {
width: 500px;
overflow: scroll;
}
</style>
i ma having trouble to play with boostrap 4 css.
I would like to have in a row two jumbotron with the same height no matter what is inside and with the inside of the div vertically aligned center.
my code is the following :
<div class="container">
<div class="row">
<div class="col-8">
<div class="jumbotron greenback">
<h7>Welcome to the Project test Detail page</h7>
</div>
</div>
<div class="col-4">
<div class="jumbotron greenback">
<div class="inner-score">
<div class="score-title">
<h6>Team Score</h6>
</div>
<div class="score-value">
<h4>85</h4>
</div>
</div>
</div>
</div>
</div>
</div>
I created a jsfidlle to show you https://jsfiddle.net/kscv67kt/2/
As you can see now the two jumbotron have vertical text align center but are not full row height..
Have you tried adding height: 100% to the jumbotron elements?
.jumbotron.greenback {
height: 100%;
}
This will cause both elements to fill the height of the container (the .row in this case).
Worth noting that setting height: 100% would cause the element's bottom margin to overflow it's container, so for neatness you could adjust the jumbotron's and their container's margin-bottom properties accordingly...
.container {
margin-bottom: 32px /* Moving the margin-bottom value of the
.jumbotron to it's outer container. */
}
.jumbotron.greenback {
height: 100%;
margin-bottom: 0;
}
Alternatively with jQuery...
$(document).ready(function() {
var jumboMaxHeight = 0
$(".jumbotron").each(function(){
if ($(this).height() > jumboMaxHeight) {
jumboMaxHeight = $(this).height() }
})
$(".jumbotron").height(jumboMaxHeight)
})
Edit: To centre the text elements within the .jumbotron, there are a number of ways you could do it, one is using flexbox properties on the parent element (in conjunction with the jQuery solution)...
.jumbotron.greenback {
text-align: center;
display: flex;
align-items: center;
justify-content: space-around;
}
I'm using Bootstrap 4 (now I'm on alpha-6).
I have this situation:
<body>
<!-- HERE I HAVE one div automatically generated with randomly ID and class -->
<div class="bigone">
<div class="container-fluid">
<div class="header">
My header
</div>
</div>
<div class="mybar">
Nav bar
</div>
<div class="main">
<div class="container-fluid">
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header">
Card Header
</div>
<div class="list-group list-group-flush">
<b>FIRST LINK</b>
Dapibus ac facilisis in
Dapibus ac facilisis in
Morbi leo risus
<b>LAST LINK</b>
</div>
<div class="card-footer">
Card Footer
</div>
</div>
</div>
<div class="col-6">
<h1>FIRST LINE</h1> So many words, so many words. So many words, so many words. So many words, so many words.
<br> So many words, so many words. So many words, so many words. So many words, so many words.
<br> So many words, so many words. So many words, so many words. So many words, so many words.
<br>
<h1>LAST LINE</h1>
</div>
</div>
</div>
</div>
<div class="footer">
Footer
</div>
</div>
<!-- HERE THAT DIV CLOSED -->
</body>
This is the css:
.bigone {
display: flex;
min-height: 100vh;
flex-direction: column;
}
.main {
flex: 1;
}
There is a DEMO on plnkr: https://plnkr.co/edit/Q9PQIj8uDFY80bxJGks3
I need footer to be on bottom when the page content is empty, for this reason I'm using: .bigone { height: 100vh; } and Bootstrap Flexbox align utilities like: <div class="bigone d-flex flex-column">
Now I need the list-group in card and the col-6 with "so many words" to be scrollable, so to have an height for both max to the bottom where the footer is.
In a nutshell: BODY must not have the scroll bar.
My header and footer height are not fixed, they change.
How to? I'm not a flexbox expert.
I don't need IE, just Chrome.
IMPORTANT:
I can't make my card height fixed with something like this:
height: calc(100vh - header.height - footer.height - etc...);
because my header, footer, etc. heights change dynamically.
Picture of the problem:
According to the spec, the setting flex: 1 (on the .main element) is equivalent to flex: 1 1 0, shorthand for:
flex-grow: 1
flex-shrink: 1
flex-basis: 0
However, for some reason, flex: 1 is not working as expected in your code. (I'm only checking in Chrome, per your question).
However, if you give .main the full shorthand – and make it a flex container and add overflow – your layout appears to work.
.main {
flex: 1 1 0; /* flex: 1, which you had before, is equivalent but doesn't work */
display: flex;
flex-direction: column;
overflow-y: scroll;
}
revised plunkr
Reference:
7.1.1. Basic Values of flex
EDIT (based on changes to the question)
My answer above removes scrollbars from the body and provides a vertical scrollbar for the .main section.
To make vertical scroll bars available for each column in the .main section, make this adjustment:
.main {
flex: 1 1 0;
display: flex;
}
.container-fluid {
display: flex;
}
.col-6 {
overflow-y: auto;
}
revised plunkr
I have
<div class="fixed-top collapse show wrapper">
<ul class="list-group bg-white menu">
</ul>
</div>
I fixed it by
.wrapper {
margin-top: 48px; /* place it under navbar */
height: 100vh;
overflow: scroll;
padding-bottom: 48px; /* compensate margin top */
}
Created a new Plunker to showcase what you're looking for.
To keep the footer on the bottom use Bootstrap Flexbox Auto Margins.
If you want to keep your main content within the initial viewport height, use the flex-grow:1 property with overflow-y:scroll. Its height will adopt responsively based on the space the other elements use.
Hope this helped.
I'm trying to create a grid layout based on flexbox:
.container {
width: 360px; /* Try to change this. Possible values: 240px, 360px, 480px.*/
background: #eee;
display: flex;
flex-flow: row wrap;
margin: 0 -10px;
}
.cell {
box-sizing: border-box;
padding: 10px;
flex: 0 0 120px;
max-width: 120px;
}
.cell.wide {
flex: 1 0 120px;
max-width: 240px;
}
.inner {
background: red;
height: 100px;
color: #fff;
padding: 10px;
box-sizing: border-box;
}
.wide .inner {
background: blue;
}
<div class="container">
<div class="cell">
<div class="inner">1</div>
</div>
<div class="cell wide">
<div class="inner">2</div>
</div>
<div class="cell">
<div class="inner">3</div>
</div>
<div class="cell">
<div class="inner">4</div>
</div>
<div class="cell wide">
<div class="inner">5</div>
</div>
<div class="cell">
<div class="inner">6</div>
</div>
<div class="cell wide">
<div class="inner">7</div>
</div>
<div class="cell">
<div class="inner">8</div>
</div>
<div class="cell">
<div class="inner">9</div>
</div>
<div class="cell">
<div class="inner">10</div>
</div>
<div class="cell">
<div class="inner">11</div>
</div>
<div class="cell wide">
<div class="inner">12</div>
</div>
<div class="cell">
<div class="inner">13</div>
</div>
</div>
This JSFiddle helps to illustrate my problem.
A container element .container can contain any number of cells.cell. There are two types of cells: a regular one with a fixed width (the red ones in the jsfiddle) and a wide one .cell.wide (the blue ones) which are twice as wide but could shrink to the width of the regular cell if there is not enough space in the current row. Each row must be filled completely.
So in the example (see fiddle):
Cell #2 should be wide and push #3 to the next row.
In the second row, which then contains #3, #4 and #5, cell #5 should stay small, because there's no space for a larger cell and rows should be filled completely.
etc
By the way: The grid container is of variable width and rows can therefore contain between two and four cells. You can try this out in the fiddle by changing to width to the specified possible values.
After trying around in the fiddle for the whole morning and trying numerous combinations of the flex, width, min-width and max-width properties I definitely need you help! Thanks in advance!
I already have a Javascript workaround (counting columns and adding classes) but would much prefer a CSS-only solution.
I believe the answer is that what you're looking for is not possible with Flexbox. The reason is that the sizing algorithm (in simplified terms) uses a couple of steps to determine the actual size of the element:
Determine the preferred minimum size (the value of flex-basis if set to a length/percentage, the value of main axis size if declared to be auto, and min-content size if not). In your case, both .cell and .cell.wide prefer 120px.
Place items as if they had the preferred size.
Evaluate each resulting line (in a wrapping flex flow) and determine any remaining space.
Distribute remaining space (per line) according to flex-grow.
In your case, this means that each item (regardless if .wide or not) will evaluate to a preferred size of 120px, and thus fits 3 items on each row. At this point, the flex-grow factor does nothing, as there isn't any space left to grow, so the fact that .wide items have a flex-grow of 1 is irrelevant. I think your example would require a form of "sometimes min-width, sometimes not" behavior that flexbox just doesn't do — there would be too many layout passes for the browser to do (e.g. reflowing into lines several times etc).
The only CSS-based solution I can think of is to hardcode all the possible scenarios in something akin to "Quantity Queries", but that would get unwieldy fast...
Closest I can get with flexbox is something like https://jsfiddle.net/qde5xq09/1/.