I need to create a 2 rows layout for a web page to manage a section for filters and other section for results with the following characteristics:
the page cannot overflow the height of 100%
the height of the first row is based on his content (could be variable and a javascript function can change it by hiding some elements)
the height of the second row is the difference between 100% and the height of first row
in the second row the div with overflow must be the one with class "list" and I can't move it to div with class="result" (that will make it work)
HTML:
<div class="main">
<div class="filter">
<div class="filtercontent">
filter content
</div>
</div>
<div class="result">
<div class="resultcontent">
<div class="list">
<div class="listcontent">
list content
</div>
</div>
</div>
</div>
</div>
CSS:
.main {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
.filter {
width: 100%;
}
.result {
width: 100%;
}
.resultcontent {
height: 100%;
width: 100%;
}
.list {
height: 100%;
width: 100%;
overflow: auto;
}
.listcontent {
height: 1000px;
width: 2000px;
}
I tried with flexbox (in different ways) but I can't find a solution for the last point.
IMPORTANT: I can't use javascript to set the height of the rows. I need a solution using only CSS.
Thanks!
If you declare your .result div with "flex: 1" property it will take all space remaining in the outer div (.main). So if the .filter div occupies 500 height pixels the .result will adjust in the blank space filling the 100% from the parent. If you change it dynamically hiding or adding elements flex: 1 will guarantee that all remaining space will be populated by .result automatically.
Hope it helps
Related
I have a problem I can't solve which I want to reproduce a behaviour.
This behaviour consists in, per example:
Two divs(div1 and div2) in a flexbox row with flex-wrap, where the div2 shrinks(while you're changing window size) until it reaches a specific width, and only after that, I want it to drop down(or wrap it) from div1.
The only thing I can do to happen is:
when I change window size from the right, it instantly drops below div1 and after that it starts to shrink.
<body>
<div id="container">
<div class="item" id="pri"></div>
<div class="item" id="seg"></div>
</div>
</body>
/* CSS */
#container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.item {
width: 300px;
height: 200px;
}
.item#pri {
background-color: red;
}
.item#seg {
background-color: green;
width: 600px;
flex-shrink: 3;
margin-right: 20px;
}
Get rid of the wrap, which actually separates your divs and add min-width to the ids. Set the flex or width in percent to the one you want to shrink first and width in pixels to the second one.
I wrote some notes into code below:
#container {
display: flex;
flex-direction: row;
min-width: 500px;
max-width: 1200px;
background-color: violet;
padding: 10px;
}
.item {
height: 200px;
}
.item#pri {
min-width:300px;
flex: 70%; /* it will grow till 70% of the parent - but just in the moment, when there is space left*/
background-color: red;
}
.item#seg {
background-color: green;
min-width:200px; /*its standart 600px, but it can shrink down to 200px, normal size has priority */
width: 600px;
}
<div id="container">
<div class="item" id="pri"></div>
<div class="item" id="seg"></div>
</div>
Use flex-wrap as wrap on the parent Element.
Use the third constituent flex property basis on the children Elements (300px in the below example) which will act as a "min width" — before they start to wrap.
#container {
display: flex;
flex-wrap: wrap;
}
.item {
flex: 1 0 300px; /* 300 or any desired min width */
}
#one {background: red;}
#two {background: blue;}
<div id="container">
<div class="item" id="one">One</div>
<div class="item" id="two">Two</div>
</div>
I just learned with your answers. Though I didn't expose my real problem. I have a label with words on it, and next to it I have an input.
What I want to reproduce is the label staying in a specific size, and then the input with a width of 600px shrinking while window browser is getting small, and when it reaches a specific size, it drops under the label.
<label class="item" for="allwords">all these words: </label>
<input class="item" type="text" name="q">
I've running so many tests that my css file is all messed up. I've tried to put label and input inside of divs individually, and those divs inside of one div and playing with flexbox(parent / child).
The following does exactly what I want, but I don't understand why, which annoys me.
I want:
the "second" div to take as much space as it can, within the constraints of its parent
then divide that space evenly amongst it's 2 child divs
scale the imgs so that they fit exactly in their parent div
<!DOCTYPE html>
<html>
<head>
<style>
.root {
width: 500px;
height: 500px;
}
.flex-container {
display: flex;
flex-direction: column;
background-color: red;
height: 100%;
width: 100%;
}
.first {
background-color: blue;
}
.second {
background-color: darkmagenta;
flex-grow: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
.wrap {
height: 50%;
width: 100%;
}
img {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div class="root">
<div class="flex-container">
<div class="first">
This div should be sized accoring to it's content and wrap if needed
which it does, nice!
</div>
<div class="second">
<div class="wrap">
<img
src="https://www.publicdomainpictures.net/pictures/30000/velka/cat-13476279941Ls.jpg"
/>
</div>
<div class="wrap">
<img
src="https://www.publicdomainpictures.net/pictures/30000/velka/cat-13476279941Ls.jpg"
/>
</div>
</div>
</div>
</div>
</body>
</html>
After experimenting and messing around I arrived at this HTML and CSS. Crucial is the overflow: hidden; on the "second" div. Without it, the child imgs are displayed larger, growing the "second" div beyond its parent.
I do not understand how overflow: hidden; can affect the size of the childs - I would have expected them to be clipped. Any pointers?
I found a nicer way to do this in this post: flex child is growing out of parent
Instead of putting overflow: hidden; on the parent, that posts suggest setting min-height: 0; which allows its children to shrink and become smaller than their content.
That makes more sense to me.
EDIT
Found this post with even more detail, and a link to the flexbox spec which explains it all: Why don't flex items shrink past content size?
On a flex item whose overflow is visible in the main axis, when specified on the flex item’s main-axis min-size property, specifies an automatic minimum size. It otherwise computes to 0.
I'm trying to recreate something like the screenshot attached. Please, note the block with "another text" is aligned with the left column. Each grey box will be an image. Also take into consideration that the text can be multiple lines.
This is what I have so far: https://jsfiddle.net/chux/qgbw0moz/51/
The problem is that, when the first colum have more lines than the second one, the bottom of the boxes will be aligned, not the bottom of the images.
How can align them?
.container {
width: 100%;
}
img {
display: block;
margin: 0;
max-width: 100%
}
.row {
display: flex;
align-items: strech;
}
.row>.col {
flex-grow: 1;
}
.row-col {
background: grey;
flex-direction: column;
justify-content: space-between;
height: 100%;
display: flex;
}
.first-col {
background: red;
}
.second-col {
background: green;
}
.third-col {
background: pink;
}
<div class="container row">
<div class="col first-col">
<img src="https://placeimg.com/450/480/animals">
</div>
<div class="col">
<div class="row-col">
<div class="col second-col">
<img src="https://placeimg.com/400/180/animals">
</div>
<div class="col third-col">
<img src="https://placeimg.com/400/180/animals">
</div>
</div>
</div>
</div>
So, here goes, nice and simple - just give a fixed height to the text shown under each photo. You will have to decide about this height depending on your 'average text height' and use overflow:hidden or use the highest value possible.
.subtitle {
line-height:20px;
height:40px;
overflow:hidden;
}
Here is a working jsfiddle:
https://jsfiddle.net/scooterlord/7wqmf1Lr/
edit: here is another way to fake it. For the first column instead of using an img, just use a div element with a background image. Safely assuming that the second column might have variable height, expand the div with the background image on first column to consume all of the first column's height and then add a second row for either single or multi-text beneath. This might be a bit tricky for responsive -eg change the background image div's height to absolute value or add multiple layers of the same text to hide/show on specific resolutions (or use JS instead), but is certainly doable and a direct solution to your problem.
If you like I can help you with the implementation of the responsiveness as well - although out of the scope of this question.
Replaced img tag with div and background-image:
<div class="img" style="background-image:url(https://placeimg.com/400/480/animals)">
</div>
Added css:
.img {
display: block;
width: 100%;
height: 100%;
background-size: cover;
background-position: center center;
}
Working fiddle.
https://jsfiddle.net/scooterlord/7wqmf1Lr/13/
I have a simple HTML document. I have a header, a section and a div (that contains an unknown number of other divs).
The header and the section do not (and can not) have set heights. Their height comes from the content. Only their width is known (set to 100%).
Is it possible, with flexbox or other means, to get each of those child divs, in this case with class="fill" to be the height of the body - minus the header and section?
In other words, when someone goes to the page, I want them to see the header and the section and then have the first div.fill reach all the way to the bottom, forcing them to scroll to see the next div (but not scroll to see the bottom of the first child div).
I am using a templating system so unfortunately the structure of the HTML can not change and I would like to do this only in CSS.
<html>
<body>
<header> Header content, might contain an image</header>
<section> This is the sub header, unknown height </section>
<div class="container">
<div class="fill">I Want</div>
<div class="fill">Each of These</div>
<div class="fill">To be </div>
<div class="fill">The height of the body - the Header - the Section</div>
</div>
</body>
</html>
body {
display: flex;
flex-direction: column;
height: 100vh;
margin: 0;
}
.container {
flex: 1; /* 1 */
display: flex;
flex-direction: column;
overflow-y: scroll;
}
.fill { flex: 0 0 100%; } /* 2 */
header { background-color: aqua; }
section { background-color: orange; }
.fill:nth-child(odd) { background-color: yellow; }
.fill:nth-child(even) { background-color: lightgreen; }
<body>
<header> Header content, might contain an image</header>
<section> This is the sub header, unknown height </section>
<div class="container">
<div class="fill">I Want</div>
<div class="fill">Each of These</div>
<div class="fill">To be </div>
<div class="fill">The height of the body - the Header - the Section</div>
</div>
</body>
jsFiddle
Notes:
The flex-grow: 1 component of flex: 1 tells the .container element (a flex item child of body) to consume all remaining space. This will cause .container to use up any space not consumed by header and section.
The flex-basis: 100% component of flex: 0 0 100% tells the .fill items (flex item children of .container) to consume 100% height of the parent. So these items will always take the full height of flex-grow: 1 on the parent.
Because flex items are set, by default, to shrink in order to not overflow the container, an override is set with flex-shrink: 0 in the flex: 0 0 100% rule. This disables the shrinking feature and allows the items to stay fixed at 100% height. (Otherwise, regardless of the defined height / flex-basis, the items would shrink evenly to prevent an overflow. See demo.)
If you change the structure of the elements a bit you can get it with only css.
Basically add the first .fill element in a container with the header and the section (let's call it first). For the other divs use height: 100vh
body {
margin: 0;
}
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
.fill {
height: 100vh;
overflow: auto;
}
.first {
flex: 1;
}
header { background-color: aqua; }
section { background-color: orange; }
.first, .fill:nth-child(odd) { background-color: yellow; }
.fill:nth-child(even) { background-color: lightgreen; }
<html>
<body>
<div class="container">
<header> Header content, might contain an image</header>
<section> This is the sub header, unknown height </section>
<div class="first">I Want</div>
</div>
<div class="fill">Each of These</div>
<div class="fill">To be </div>
<div class="fill">The height of the body - the Header - the Section</div>
</body>
</html>
EDIT: My example was to complicated. So I made a simpler one.
http://codepen.io/knobo/pen/gaZVoN
.top grows beyond the available size of the html element. I don't want any content outside the current viewport which is 100vh, but I don't know the height of .bottom which can vary.
This line:
max-height: calc(100vh - 60px);
Makes it look like this works. But it does not, because I don't know the height of .bottom, which I just estimated to 60px;
<div class="page">
<div class="top">
<div class="left">Some text</div>
<div class="right">
<img src="http://placehold.it/350x1800">
</div>
</div>
<div class="bottom">
<button>Click</button>
<button>Click</button>
<button>Could be several lines</button>
</div>
</div>
html, body {
max-height: 100vh;
}
Css
.page {
display: flex;
flex-direction: column;
height: 100%;
}
.top {
flex: 1 1 auto;
display: flex;
overflow: hidden;
max-height: calc(100vh - 60px);
/*
I don't know the height of .bottom
It can change when browser is resized too..
How do I solve this.
*/
}
.left {
flex: 1 1 auto;
}
.bottom {
padding: 10px;
flex: 1 1 auto;
background-color: teal;
}
EDIT2: (included the original links from the first version)
http://codepen.io/knobo/pen/epboBv (css version. Does not work)
http://codepen.io/knobo/pen/wKRNjr/ (js version. Works. But I want to know how to do it with css.)
EDIT3
Screenshots:
When browser window is small, the bottom row disappears, when div.right is too big.
When browser window is large everything shows up (corectly)
This is how it should be: div.top is scaled down, and bottom row is stil visible. I was able to do it with javascript. I guess it should be possible with css too.
The solution is surprisingly easy.
.right {
position: relative;
/* width: Do something with width here. */
}
.nooverflow {
position: absolute;
}
then wrap the content of .right with class="nooverflow"
<div class="right">
<div class="overflow">
{{ Content of .right }}
</div>
</div>