I have a app that uses a classic email like layout like the one below.
I have constructed it using the new CSS3 flexbox model and it works brilliantly until I add the ability for the user to dynamically add new items in the folders box. I would have hoped that flexbox worked in such a way that as long as there is space left in the folders box it would not begin growing into the tasks box underneath. Unfortunately this is not what I am seeing (in Chrome 17).
I have constructed a JSFiddle here that demonstrates the problem. Just click the Add Folder link and you will see the folders box growing, even though it has space enough left to accommodate the new child.
To the question. How can I construct two vertically aligned boxes using flexbox in such a way that one takes up two thirds of the available height (box-flex 2) and the other one third (box-flex 1) and that they do it in such a way that when new content is added to the first box it does not begin growing until it is out of space.
I can't say for sure if that's a browser bug or if it is in fact how the flex model is supposed to work. If that is how it should work I'd agree that's not exactly intuitive!
I found a work around by wrapping the lists in an absolutely positioned div with the overflow set to auto. This allows the flex boxes to maintain their original states and only change when the entire layout is recalculated vs. the content changing.
Here's the updated markup:
<section id="folders">
<div class="dynamicList">
<h2>Folders</h2>
<ul>
<li>Folder 1</li>
<li>Folder 2</li>
</ul>
Add Folder
</div>
</section>
And the updated CSS:
#left #tasks,
#left #folders {
position: relative;
}
.dynamicList {
bottom: 0;
left: 0;
overflow: auto;
position: absolute;
right: 0;
top: 0;
}
I forked your fiddle here to demo:
http://jsfiddle.net/MUWhy/4/
UPDATE:
If you want the headings to remain fixed and only have the contents of the folder and tasks lists scroll, then I would consider putting the headings and the add buttons in their own fixed-height boxes within the #left div. It's a bit more mark up but still pretty simple. I haven't tried it on JSFiddle but I think that would be the best route to go.
I have got this answer from my other question which is is the same more or less: https://stackoverflow.com/a/14964944/1604261
Instead of #LukeGT solution, that it is a workaround and not the solution to obtain the effect, you can apply a height to the element where you want to see a vertical scroll.
So the best solution if you want a min-height in the vertical scroll:
#container article {
-webkit-flex: 1 1 auto;
overflow-y: auto;
min-height: 100px;
}
If you just want full vertical scroll in case there is not enough space to see the article:
#container article {
-webkit-flex: 1 1 auto;
overflow-y: auto;
min-height: 0px; /* or height:0px */
}
If you do not set the height (using height or min-height) the vertical scroll will not be set. In all cases, even with height: 0px; the calculated height of the element will be different to zero.
My solution with -webkit prefix: http://jsfiddle.net/ch7n6/4/
Edit:
Since Firefox now supports full flexbox specification, removing -webkit- vendor prefix it will work with all browsers.
I prefer this solution to Jim's since it's less of a hack - it will work on any flexbox on any part of the page. Jim's can only work on a box in the very top left of a page.
I solved this by wrapping the part of the flex box that I wanted to scroll inside a div.scrollbox. I made the direct children of this div have a height of 0, so that adding extra elements within it would not affect the rest of the layout. I also set its overflow-y to auto so that a scrollbar would appear if its children extend beyond its bounds.
.scrollbox {
-webkit-flex: 1 1 auto;
overflow-y: auto;
}
.scrollbox > * {
height: 0;
}
Note that this will only work if the extendible content is placed within a containing element or containing elements. In this example, li elements are contained within a containing ul element, so it works.
I also had to make some changes in order to get the 3 components of the top left flexbox to arrange themselves properly, but this was application specific.
#folders {
display: -webkit-flex;
-webkit-flex-flow: column;
}
#folders h2, #folders #add {
-webkit-flex: 0 1 auto;
}
I forked the above jsfiddle here: http://jsfiddle.net/FfZFG/.
Related
I have an angular page, home, which is comprised of 2 components and a router-outlet
<div class="home-container">
<header></header>
<sub-header></sub-header>
<router-outlet></router-outlet>
</div>
I want the home-container above to always be, at a minimum, full screen height. The header should show, then the sub-header, then the contents of the router-outlet should always fill up at least the rest of the screen (or more if there's more content of course).
Normally this is easy but it seems the router-outlet is messing it up. Example can be seen http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas , hit run and then click the "Heroes" link to route. In this example I don't want the Heroes div to be taller than the screen, and don't understand why it is.
My styles to accomplish this are. (assume router-outlet is on 'my-page')
html, body {
height: 100%;
}
.home-container {
height: 100%;
}
.my-page {
height: 100%;
}
My expectation here obviously is that home-container is full screen, shows header, shows sub-header, and that my-page then fills in at a minimum the rest of the vertical height.
What is actually happening though, is that there's a scroll bar with available height that appears equal to my header and sub-header.
This plnkr http://plnkr.co/edit/56k9ZabLAGujBoX8Lsas illustrates exactly my meaning. If you click Run and then the link for "Heroes" you will see the router-outlet contents, in this case heroes-list.component, with a green background. I do not understand why the green here is bleeding below the screen when everything is set to 100%
Update I have tried using all manner of different CSS attributes to different levels in this nesting. Including 100vh vs 100%, min-height vs height, and every combination of body/html/home-container/my-page. I have also tried the same with Angular's CSS :host, to the same result of no different
Update2 If I move it out of the element then everything behaves as you'd expect and there's no vertical scroll bar. Something about the router-outlet wrapper adds vertical space somewhere but I cannot figure out where or what is causing it.
Final Update The below answers might be useful for some applications but I ended up just solving it by giving the .my-page a specified height, just doing height: calc(100vh - $headerheight - $subheaderheight) which gets the job done
As far as I understand, 100% on a child will be equal to the size of the parents natural height. If you want to fill the space available, you really should be using flex unless you have a requirement to support IE9 and below.
I would update your Anchors to be contained in a div (or another wrapper)
<h1 class="title">Component Router</h1>
<div>
<a [routerLink]="['CrisisCenter']">Crisis Center</a>
<a [routerLink]="['Heroes']">Heroes</a>
</div>
<router-outlet></router-outlet>
I would then utilize flexbox to allow the content to expand as required
.hero-list {
background-color: green;
height: 100%;
overflow:auto
}
undefined {
flex: 1;
}
body, html, my-app {
height: 100%;
}
my-app{
display: flex;
flex-flow: column;
}
Plunker to test: http://plnkr.co/edit/yE1KOZMr1pd5jQKlVYIN?p=preview
On chrome i still have scroll bars due to an 8px margin on body - this can easily be removed with CSS for a scroll free full height experience.
There are two causes that make your <body> element taller than 100% of the viewport:
Default margins of the <body> element that come from the browser's built-in styles and usually are 8px. This means that the <body> element will be as tall as the <html> element, but also will have 8px space above it and below it, causing the <html> element to overflow.
The top margin of the <h1> element "falls out" from the container due to margin collapsing. This makes the space above the <body> element equal to the default top margin of <h1> (about 21px instead of 8px).
Setting zero margin to <body> (part of ToTaTaRi's answer) helps you to solve the 1st issue. To solve the second one, you should make the <body> element or (probably better) the .my-app container establish the new Block Formatting Context. The easiest and most cross-browser way for this is setting the container overflow:hidden (other options are display:flow-root, which works for modern Chrome/Firefox, or column-count:1, which works in IE10+ and all modern browsers, you can compare nearly all the options in this live example).
First of all you should reset browser default styles at least somehow like this:
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
Then you could achive what you want without a flex layout if prefered through splitting the page into a header section and main content section with a preset division... So lets say the heading and the links go together into a container div with i.e. a height of 20% and the main content which is at the moment hold in a tag "undefined" gets a height of 80%, if you now set the height of the app container to 100% or 100vh it should work as expected!
EDIT (because the topic is still open...):
Have you tried this css code like explained above, works like charm!?
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body, my-app {
height: 100%;
height: 100vh;
}
h1 , h1 + div {
height: 10%;
height: 10vh;
}
undefined {
display: block;
background-color: green;
min-height: 80%;
min-height: 80vh;
}
I have this layout. A container div set to
.container {
width: 80vw;
max-height: 75vh;
margin: auto;}
Inside that is a panel div with header and body divs, then my nested flexboxes. See image below:
The main flexbox div is set to row, with 2 divs in it which are flexbox column.
Inside those there is one div each which has overflow-y set to scroll, and they both have a lot of content.
This is working perfectly in Chrome and Safari, but in IE11 the scrolling divs do not scroll -- they go to the full height of their content and spill out of the container.
To be clear: only those divs in yellow should scroll.
What am I missing here?
Update
I have created a stripped-down pen: http://codepen.io/smlombardi/pen/reodZE?editors=1100
I see this question already has an accepted answer, but that solution didn't work for me. Something else did so I thought I would share for anyone encountering this in future.
My layout was very similar to this. There was a lot of nesting. Getting it to work in Chrome was quite straight forward. However, getting it to work in Firefox would take me another day of research & experimentation. In hindsight, it was probably because I didn't understand flex-box well enough.
To get a more complicated flex-box layout working cross-browser (by working, I mean flex children scrolling for overflowing content), do the following:
give outermost container a predefined height
use Flexbox for all containers that wrap the scrollable container
Since content lays vertically on the page by default, it's recommended to use: flex-direction: column
for Firefox: explicitly set min-height: 0 for every flex-item parent all the way up to the outermost flex-box.
if you have multiple flex children and the child that will scroll needs to expand to fill all available space, use flex-grow: 1
I got this from an article by Stephen Bunch, which I think was originally posted somewhere on SO too. Kudos to him!
Still, your scrolling flex child container will not work in IE11. It will expand to the full height of the contained content.
To fix it in IE11, do this:
Add overflow: hidden; to all its parents
Thanks to the original poster geon on SO in another related question.
Also, having a diagram of the flex layout was vastly more helpful than giant walls of code while researching to fix my own flex layout issues. Thanks OP!
Hoped that helped. It certainly did for me. All my flex-box issues for this more complicated layout.
PS: if this didn't solve it for you, maybe consider this list of flex-box bugs and their workarounds / solutions: https://github.com/philipwalton/flexbugs
Not sure if this is the best way, but I simplified this down to a simple bootstrap row, 2 columns.
I set the container to 75vh, and the 2 columns to the same 75vh.
The key was to set the 2 scrolling divs to flex-basis: something rem:
.search-results {
overflow-y: scroll;
margin-bottom: 10px;
flex-basis: 10rem;
background-color: #c4decf;
}
.accordions {
overflow-y: scroll;
overflow-x: hidden;
flex-basis: 40rem;
flex-grow: 1;
background-color: #f0f0f0;
padding: 10px;
}
See updated codepen: http://codepen.io/smlombardi/pen/WwLgyV?editors=1100
None of the answers here worked for me.
My experience with IE is that both inheritance and properties needs to be set explicitly a lot of the time and the same was true here.
The fix in my case was then to set the max height of container element to 90vh and overflow-y to hidden.
The child element (scroll element) was set to inherit the max-height with overflow-y set to auto. Simply setting it to 100% did not work, really the keyword was "inherit"
all other parent elements got overflow hidden
I'm having a bit of a problem making script-less CSS-only animated transition of an element that's initially set to a fixed width and should expand on mouse over to auto width according to content in it. When mouse goes out it should collapse back to fixed width.
Let's say I have a menu:
<menu>
<li>Item</li>
<li>Item with long text</li>
</menu>
Initially it would display as a collapsed 50px wide vertical bar with icons only. When one mouses over it reveals icon labels.
This is a simplified example of what I'm trying to achieve. First menu is the one that needs to transition and second one is there just to show what auto width should be for this amount of content.
Problem
This is just part of the whole CSS that plays an important role here:
menu {
width: 50px;
}
menu:hover {
width: auto; /* setting to other fixed width works as expected */
}
The problem is that when you set width to auto one of the two will happen:
Browser animates from fixed width 0 (Chrome) - if we then add min-width it does next one
Browser doesn't animate anything just applies new style
You can make use of the max-width trick, it's not perfect, but it gets around the problems with transitioning a numeric value to a string state:
http://jsfiddle.net/Cqmuf/1/
(the above has been updated with float:left)
The downside to this method is that you have to set a max width for your menu, but then I usually find that this is a good thing to do anyway.
markup:
<div class="menu">
[i] Hello
[i] There
</div>
css:
div a {
display: block;
overflow: hidden;
white-space: nowrap;
}
.menu {
transition: all 2s;
max-width: 17px;
/*
here you can set float:left or position:absolute
which will force the menu to collapse to it's minimum
width which, when expanded, will be the actual menu
item widths and not max-width.
*/
float: left;
}
.menu:hover {
/*
If you have the possibility of varied widths, i.e. multilingual
then make sure you use a max-width that works for them all. Either
that or do what a number of multilingual sites do and set a body
class that states the current language, from there you can then
tailor your max-width differently e.g. wider for German.
*/
max-width: 300px;
}
Example of seperate dimensions for multilingual:
.lang-de .menu:hover { max-width: 400px; }
.lang-gb .menu:hover { max-width: 300px; }
So instead of transitioning the width, you are actually modifying the max-width property, which you can set a fixed value to more easily, all because it will only come into use when this limit has been reached, and remains invisible until then.
With CSS, how can i simply get a page with sticky header and footer which are appearing forever, whenever the page is scrolling or not. I found some sample online, but what i additional want is, the middle content area should be a 100% stretched area between header and footer whatever the browser size is.
I mean, most of the Samples i found, are making Header and Footer sticky correctly.., but these are just floating and actually covering the Top and Bottom parts of the 'middle' content area. That's not what i really want.
Can use absolute position for all 3 elements.
#header,#footer,#content { position:absolute; right:0;left:0}
#header{
height:100px; top:0;
}
#footer{
height:100px; bottom:0;
}
#content{
top:100px;
bottom:100px;
overflow:hidden; /* use this if don't want any window scrollbars and use an inner element for scrolling*/
}
DEMO: http://jsfiddle.net/RkX8B/
The solutions presented above work for very simple layout with no border, margin, and/or padding. Many, many solutions that you'll find on the Net will work for this.
However, almost all solutions fall completely apart if you simply add border, margin, and/or padding to any or all of your Divs.
Flex Boxes (CSS display:flex;) are incredibly powerful for this, and they work perfectly with any combination of border, margin, and/or padding.
They can portion your screen space into as many Divs as you need, using fixed size, percentage size, or "whatever's left" for each inner Div. These can be in any order, so you aren't limited to just headers and/or footers. They can also be used horizontally instead of vertically, and can next.
So you could have, say, a fixed-size header, a 20% footer, and a "whatever's left" client area between them that sizes dynamically. Inside that client area, in turn, you could have, say, a percentage-width menu bar at the left edge of the client area, a fixed-width vertical divider next to that, and a client area that takes up "whatever's left" to the right of that.
Here's a Fiddle to demonstrate all of this. The relevant CSS is remarkably simple.
CSS Flex Box (display:flex;) Demonstration with Borders/Margin/Padding
For instance, here are two CSS classes that create containers that will flow their contained Divs either horizontally or vertically, respectively:
.HorFlexContainer {
display: flex;
flex-direction: row;
flex-wrap: wrap;
flex: 1; /* this essentially means "use all parent's inner width */
}
.VertFlexContainer {
display: flex;
flex-direction: column;
flex-wrap: wrap;
flex: 1; /* this essentially means "use all parent's inner height */
}
The Fiddle above really shows it all off, though.
For reference, see this excellent article by Chris Coyier:
Flexbox Tutorial
Hope this all helps!
You're probably looking for the "position: fixed;" property, and setting the header to top: 0; and the footer to bottom: 0; You might also consider some padding to your "content area" to account for that header and footer space...
From the top of my head you would have something like:
header { position: fixed; top: 0; height: 100px; }
footer { position: fixed; bottom: 0; height: 100px; }
#container { padding: 100px 0; }
If you're using some kind of background on your container and want to stretch it, a height: 100%; should do...
I've never found a good way to use this kind of layout though... =\
My page I'm working on is at http://www.derekbeck.com/1775/excerpts/
It looks all fine in desktop browsers, but on mobile screenshots, like below, it is forced to wrap. (see below the image for my questions...)
(full sized image)
I've tried to make it wrap gracefully, but I have two questions:
1) Is there some CSS way to control how the div inline-block (class="exnote2") Want the entire chapter?<BR>Sign up for the newsletter! wraps?
Specifically, I want:
1a) that padding-left: 20px; on the left side of it to be non-existent if it is on a second line as below (but it is necessary to keep it 20px from the PDF icon if it is indeed all on one line),
1b) some whitespace above the div inline-block (class="exnote2"), so that it is not so close to the "Read Online" icon. If I add padding-top or margin-top however, it effects the nice layout for the desktop version (linked above).
For what it's worth, for 1b) above, I did jury-rig a solution together for the entire inline block that follows the image, the entire div inline block that contains text (class="exitemdetails"). I did it this way:
.exitemdetails {
margin-left: 25px;
/* The following allows for graceful wrapping for mobile phones */
padding-top: 20px;
position: relative;
top: -10px; /* half the padding-top */
}
I could jury-rig something for the Want the entire chapter?<BR>Sign up for the newsletter! line too, but I suspect under different conditions it would not display as I hoped. Hence, I post here hoping for a better, more elegant solution, namely, how to use CSS to control the way div's wrap, and the spacing between them only if they do wrap.
2) I have one other question related to this: is there no simple CSS way to shrink that book cover image down when there is not space enough? I tried this, but it does nothing:
.eximage {
width: auto;
height: auto;
}
.eximage img {
max-width: 100%;
height: auto;
}
Thanks for looking!
Derek
Have you considered using css media queries to change the layout of your page at different screen sizes? Might be worth a shot.
http://www.w3.org/TR/css3-mediaqueries/