Flexbox height not updating when content changes - css

There seems to be a problem with flexbox in chrome which affects columns of variable height. When the contents of these columns change the column should resize, but it doesn't
I have created a JS fiddle here - http://jsfiddle.net/KVQTd/2/
Just hit the 'remove content button' to see what I mean.
This is the simplest example of using flexbox to create columns to demonstrate that nothing else is causing it.
.wrapper{
display: flex;
align-items: stretch;
}
.column1{
flex: 1;
}
.column2{
flex: 1;
}
I'm pretty sure this is a bug in Chrome because when you go into developer tools and switch flex off and on again it then calculates the height correctly.
I have submitted a bug report here - https://code.google.com/p/chromium/issues/detail?id=369869&thanks=369869&ts=1399226675 -
...but I don't have time to wait for new versions of Chrome to be released so I was hoping somebody might be able to think of a clever solution. Perhaps some kind of javascript which watches the height of the inner content and adjusts forces a recalculation of the flexbox height?

This works for me:
var elem = document.getElementById("myFlexbox");
elem.style.display='none';
elem.offsetHeight; // no need to store this anywhere, the reference is enough
elem.style.display='flex';
Also see: How can I force WebKit to redraw/repaint to propagate style changes?

In order to work in Chrome, it needs a refresh or some kind of reflow. DEMO
If you script force the main container to be recalculated, you have something that works.
(this looks like some very old bug of Opera)
In order to do that, we can switch from position static to relative and use a pseudo to insert some content.
CLASS wrapper becomes an ID to easily select it via JavaScript
<div id="wrapper">
<div class="column1">This column Has some content</div>
<div class="column2">This column also has some content
<div id="contentToHide">
<p>Sed egestas, ante et vulputate volutpat, eros pede semper est, vitae luctus metus libero eu augue. Morbi purus libero, faucibus adipiscing, commodo quis, gravida id, est. Sed lectus. Praesent elementum hendrerit tortor. Sed semper lorem at felis. Vestibulum volutpat, lacus a ultrices sagittis, mi neque euismod dui, eu pulvinar nunc sapien ornare nisl. Phasellus pede arcu, dapibus eu, fermentum et, dapibus sed, urna.</p>
</div>
</div>
</div>
<button id="removeButton">Remove Content</button>
<br/>
<button id="addButton">Add Content</button>
javaScript update
document.getElementById('removeButton').addEventListener("click", function (event) {
document.getElementById('contentToHide').classList.add("hidden");
document.getElementById('wrapper').classList.add("prelative");
});
document.getElementById('addButton').addEventListener("click", function (event) {
document.getElementById('contentToHide').classList.remove("hidden");
document.getElementById('wrapper').classList.remove("prelative");
});
CSS update:
#wrapper {
display: flex;
width: 400px;
margin-bottom: 30px;
}
.column1 {
padding: 10px;
background: #DDD;
}
.column2 {
padding: 10px;
background: #EEE;
width:50%;
}
#contentToHide.hidden {
display: none;
}
.prelative {
position:relative;
}
div:before {
content:attr(class);
left:-9999px;
position:absolute;
}
Actually, for .hidden and pseudo you can just do :
#contentToHide.hidden ,
div:before {
content:attr(class);
left:-9999px;
position:absolute;
}

Try to set height: 100% for columns

I solved this by setting height: max-content on the children of the flex container

Related

center a div inside a fixed one at the center of the screen

I have a div fixed at the top of my screen. Inside this div I put one with position absolute that I want to center in the middle of the screen.
#menu{
position:fixed;
width:100%;
height:30px;
background:#000;
}
#center{
position:absolute;
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -50px;
width: 100px;
height: 100px;
background:#fff;
}
..
<div id="menu">
<div id="center">
how to center this div?
</div>
</div>
if I change the #menu position to relative it works fine... but I need this to be fixed. what is the problem that I cannot put div #center in the middle?
https://jsfiddle.net/y5s77mmq/1/
thank you friends!
There are two ways you can achieve this. One is to give your #center div a fixed position:
#center {
position:fixed; /* change this to fixed */
top: 50%;
left: 50%;
margin-top: -50px;
margin-left: -50px;
width: 100px;
height: 100px;
background:#fff;
}
However, this will keep it centered to the screen and not the page.
If you want to center it vertically and horizontally on the web page, one option is to use flex:
#container {
display: flex;
/* establish flex container */
flex-direction: column;
/* make main-axis vertical */
justify-content: center;
/* align items vertically, in this case */
align-items: center;
/* align items horizontally, in this case */
height: 500px;
/* for demo purposes */
border: 1px solid black;
/* for demo purposes */
background-color: #eee;
/* for demo purposes */
}
.box {
width: 300px;
margin: 5px;
text-align: center;
}
#center {
background: #fff;
width:100px;
height:100px;
}
<div id="container">
<!-- flex container -->
<div id="center" class="box">
how to center this div?
</div>
</div>
Also, since the #center div is not related to your #menu div, it shouldn't be nested.
Disclaimer: Looking at your past questions it looks like you know enough about css, so you probably don't need such a long explanation, but I explained everything just in case someone else less knowledgeable about css finds this answer.
The flex solution mentioned by #DrewKennedy is best, but if you cannot use flex for any reason, here is another solution, similar to the first solution DrewKennedy mentioned. This solution uses absolute positioning, so it is centred to the page, but it can be changed to fixed to get the same effect as the other answer.
The basic idea is pretty much the same. When you set it to absolute/fixed positioning, you can set it to be half the screen's width and height from the top and left. This might mean that the content will only start at the middle, so it will not be centred, so in DrewKennedy's answer, he takes away half of the width and the height of the element from the margins to fix this.
However, this solution uses the translation transformation to move it back. When you use the translate() transformation with a percentage, it moves the element relative to it's own size. This means that you can use it for dynamically sized things. This example has a full paragraph in it, and is vertically centred. When you use the exact same css, but have only one word inside the div, it is also still vertically centred..
Here is the relevant css & html:
* {
margin: 0;
padding: 0;
}
html,
body {
height: 100%;
}
body {
background-color: #050505;
}
.middle-align {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* Works with dynamically sized things too! */
max-width: 700px;
min-width: 100px;
/* Pointless styles to make it look nice: */
font-family: 'Times New Roman', serif;
background-color: #ddd;
padding: 50px;
outline: 2px solid rgba(0, 0, 0, 0.2);
outline-offset: -25px;
}
<div class="middle-align">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean viverra fermentum metus sit amet consectetur. Integer dolor purus, pretium at arcu ac, ornare interdum lacus. Cras diam nibh, fringilla sed elementum quis, varius vitae enim. Nunc nec orci
imperdiet, malesuada nunc vitae, lobortis lacus. Donec et magna ornare, facilisis urna et, hendrerit massa. Aenean vitae convallis nisl. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Morbi quis convallis
tellus. Maecenas a lorem ac turpis malesuada aliquam et sit amet sem. Nullam eu neque mi. Pellentesque ac ullamcorper felis, a mollis arcu. Vestibulum at dui congue, euismod tortor at, auctor est. Pellentesque faucibus dui nec dui hendrerit vestibulum.
</div>
Change position to fixed in #center. See JSFiddle.

Vertically align a div in a parent which has height auto AND min-height set?

I'm stuck on this one.
I want to vertically center a div. Its parent has an unknown height, however, it does have a min-height.
How can I do this?
Here is one approach using the CSS3 transform property.
Use absolute positioning to place the top edge of the child element at 50% from the top, and then use the transform: translateY(-50%) to adjust for the child's height.
.parent {
height: auto;
min-height: 200px;
border: 1px dotted gray;
position: relative;
}
.child {
border: 1px dotted blue;
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
.content {
margin-left: 100px;
margin-right: 400px;
}
<div class="parent">
<div class="child">child</div>
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer facilisis velit ut neque tempor quis cursus tortor suscipit. Curabitur rutrum magna vitae arcu pharetra eget cursus ante accumsan. Nunc commodo malesuada adipiscing. Pellentesque consequat laoreet sagittis. Sed sit amet erat augue. Morbi consectetur, elit quis iaculis cursus, mauris nulla hendrerit augue, ut faucibus elit sapien vitae justo. In a ipsum malesuada nulla rutrum luctus. Donec a enim sapien. Sed ultrices ligula ac neque vulputate luctus. Suspendisse pretium pretium felis, in aliquet risus fringilla at. Nunc cursus sagittis commodo.
</div>
</div>
An other solution requires Javascript.
Javascript can help you to get the real height of the parent element :
var myElt = <your parent selector>;
var myEltHeight = myElt.offsetHeight;
After that, you can set the 'line-height' property of the parent to be equal to this height,
myElt.style.lineHeight = myEltHeight + 'px';
And finally add a 'vertical-align: middle' to him.
myElt.style.verticalAlign = 'middle';
Of course you have to re-do the maths each time the parent element is resized (with a window resizing for instance)...
For the record, I did not test this solution. It probably needs some adjustments ...
Use a table display, like this:
div {
height: 80vh;
/* Random height and width */
width: 80%;
border: 5px solid blue;
display: table;
}
p {
display: table-cell;
height: 100%;
vertical-align: middle;
text-align: center;
}
<div>
<p>
Some centered content.
</p>
</div>
I do not recommend this usage, but you can use a display:flex on the parent element, and use one of the following, according to your needs, on the child item :
The flex-direction property establishes the main axis.
The justify-content property defines how flex items are laid out along the main axis on the current line.
The align-items property defines the default for how flex items are laid out along the cross axis on the current line.
The align-self property defines how a single flex item is aligned on the cross axis, and overrides the default established by align-items.
Source : Using CSS flexible boxes
This guide can be helpful to understand the mechanism : A Complete Guide to Flexbox
/!\ Warning :
flexbox properties are really attractive (I have been really interested in them some times ago) but they become really instable as soon as you use some absolute positionning within the DOM.
flexbox properties needs some vendor prefixes for not-even-so-old version of almost all browsers. And sometimes the properties does not even have the same names (there are the old, tweener and new syntaxes. See the end of this post : A Complete Guide to Flexbox)

Stack a relative DIV on an absolute DIV

As I try to solve the problem that led to this my unsolved unsolved question, I decided to bring up the Green DIV to the front since the content doesn't bleed off of it.
Structure
Green paper: Main DIV.rack
Orange and Gray paper: inserted via CSS :before and :after
HTML
<div class="rack">
Content
</div><!-- End Rack -->
CSS
.rack {
width: 70%;
height: 100%;
background: #7FAE68;
margin: 155px 0 100px 0;
position: relative;
float: left;
left: 15%;
z-index: 9999;
transform:rotate(1deg);
-ms-transform:rotate(1deg);
-webkit-transform:rotate(1deg);
padding-bottom:50px;
}
.rack::before {
content: "";
background: #E1BB70;
position: absolute;
height: 100%;
width: 100%;
z-index: -2;
transform:rotate(1deg);
-ms-transform:rotate(1deg);
-webkit-transform:rotate(1deg);
float: left;
left: 0%;
}
.rack::after {
content: "";
background: #E5E8EC;
position: absolute;
height: 100%;
width: 100%;
z-index: -1;
transform:rotate(-1deg);
-ms-transform:rotate(-1deg);
-webkit-transform:rotate(-1deg);
border: solid 1px #ddd;
left: 0%;
top: 0;
}
Note
If you look at the fiddle here, you'll see that the content doesn't bleed beyond the main DIV(gree paper) no matter the height. Since that's that's the case, my best bet would be to bring the green DIV to the top. There's nothing I haven't tried to no avail. Any help on how this can be achieved.
This image shows that the content(sidebar for example) is still within green(main)DIV.
Interested question.
This image from this awesome post will make you understand more about layer stack of pseudo elements:
then you will realize that your requirement is impossible.
Anyways, I created some thing looks similar to your need, using the box-shadow to make another "stack". See the fiddle.
JSFiddle
Previous poster is quite correct. The elements created using :before, :after, and content are children of the .rack and z-index applied to them is not global, but operates within their relatively positioned parent. That's why you cannot move these behind the .rack. One solution is to wrap the content in a div and use :before and :after on the wrapper div.
Here's the fiddle: http://jsfiddle.net/73Fyk/1/.
One caveat. The way to stack the :before and :after elements behind the .rack is not to position the .rack relatively. Then, the absolutely placed :before and :after are positioned, in this case, within the body can be easily moved behind the .rack. I do not like this latter approach. It is much better to keep the related entities together and to just add a tiny hair of markup to wrap the content and to roll from there.
"There's nothing I haven't tried. Any help on how this can be achieved."
Why not just use nested divs? Works just as well, and the code is much more intuitive. Demo here: http://jsbin.com/vizer/1/edit?html,output.
And this is the used code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Demo Stacked Paper</title>
<style>
html {
font-size: 62.5%;
}
body {
font: normal 1.3em Verdana;
padding: 75px; /* for the demo */
background-color: white; /* for the JSBin demo */
}
.rackGrandParent {
background-color: lightgrey;
width: 200px;
transform:rotate(2deg);
-ms-transform:rotate(2deg);
-webkit-transform:rotate(2deg);
}
.rackParent {
background-color: gold;
transform:rotate(-4deg);
-ms-transform:rotate(-4deg);
-webkit-transform:rotate(-4deg);
}
.rack {
background-color: lightseagreen;
transform:rotate(2deg);
-ms-transform:rotate(2deg);
-webkit-transform:rotate(2deg);
padding: 10px;
}
</style>
</head>
<body>
<div class="rackGrandParent">
<div class="rackParent">
<div class="rack">Mauris eu lacus ac nunc tincidunt vehicula. Donec congue, ligula quis vehicula pellentesque, nisi lacus sodales elit, quis elementum nunc risus non ligula. Maecenas eget bibendum ante. Sed bibendum lectus sodales faucibus mattis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis vel dolor quis metus facilisis dignissim. Suspendisse erat nibh, mollis nec pellentesque id, mattis eu purus. Quisque a nulla pretium, dignissim lectus at, tempor ipsum. Integer quis arcu leo. Maecenas feugiat, nisi viverra mattis pulvinar, urna nulla porttitor orci, vitae condimentum velit nisi sed turpis.</div>
</div>
</div>
</body>
</html>

how to enforce hover state div is shown above other elements and outside of container?

i've been going over this one for about two days.
example
it's a fairly complicated design, so to reduce code pasted here i've recreated the main structure on this jsfiddle and included the simplified code at the end of this post:
http://jsfiddle.net/rwone/zwxpG/10/
scenario
i have a container with numerous <li>'s containing a div (containing dynamic content from a database) that initially has the property display: none.
on hovering over an image in these <li>'s however, i wish to show the div.
it is working, however the div appears to be beneath other elements in the container which has a fixed height and overflow-y: auto.
what i've tried
i have tried combinations of z-index's and absolute and relative positioning, but i haven't been able to find a solution yet.
i've isolated two causes in the code below and the jsfiddle (shown as /* comments */) but these do not work on the live test site.
question
my question is therefore, is there another way to enforce that the hover state div is shown on top of and outside of the container that is enclosing it?
it is not an ideal solution that i can fix these issues in the jsfiddle but not the live site, but i just thought i'd ask if there was another way to approach this altogether?
thank you.
html
<div id="wrapper">
<div id ="hbar_one"></div>
<div id="hbar_two"></div>
<div id="container_a">
<div id="container_b">
<ul>
<li>
hover me #1
<div id="container_c">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In fringilla porttitor ante ut varius. Fusce volutpat velit ut orci porttitor cursus. Donec est eros, tempor ac elementum et, volutpat sit amet lorem. Mauris iaculis eros nec sapien hendrerit at sodales nibh iaculis. Morbi imperdiet porta est vitae suscipit. Curabitur sit amet diam in nulla consectetur placerat. Etiam in sapien ac mi scelerisque congue eu id lectus. Proin fermentum auctor turpis vel adipiscing. Maecenas at convallis sapien.
</div>
</li>
<li>
hover me #2
<div id="container_c">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In fringilla porttitor ante ut varius. Fusce volutpat velit ut orci porttitor cursus. Donec est eros, tempor ac elementum et, volutpat sit amet lorem. Mauris iaculis eros nec sapien hendrerit at sodales nibh iaculis. Morbi imperdiet porta est vitae suscipit. Curabitur sit amet diam in nulla consectetur placerat. Etiam in sapien ac mi scelerisque congue eu id lectus. Proin fermentum auctor turpis vel adipiscing. Maecenas at convallis sapien.
</div>
</li>
</ul>
</div>
</div>
<div id="hbar_three"></div>
<div id="hbar_four"></div>
</div>
css
#wrapper {
width: 300px;
}
#hbar_one {
background: #cc0000;
height: 50px;
}
#hbar_two {
background: #ffcc00;
height: 50px;
}
#container_b {
height: 50px;
/* cause one - on its own, this causes the undesired 'underneath' effect */
overflow-y: auto;
}
ul li {
display: inline;
/* cause two - on its own, this causes the undesired 'underneath' effect */
position: relative;
}
#container_c {
display: none;
}
ul li:hover #container_c {
background: #00AFF0;
display: block;
width: 200px;
height: 200px;
position:absolute;
top: -20px;
left: 50px;
z-index: 999;
overflow: hidden;
}
#hbar_three {
background: #cccccc;
height: 50px;
}
#hbar_four {
background: #000000;
height: 50px;
}
update
in response to answer below, here is further information on the actual content that is being displayed upon hover (everything within the #container_c div). each <li> has its own unique content:
​<li class=".class1 .class2">
<img src="http://path/to/image.jpg">
<div id="container_c">
<h4>title</h4>
<div id="container_c_left">
<span id="cl1">text</span>
<span id="cl2">text</span>
<span id="cl3">text</span>
</div>
<div id="container_c_right">
<span id="cr1">text</span>
<span id="cr2">text</span>
</div>
<span id="cc1">text</span>
<span id="cc2"><a class= "linkclass" href="http://path/to/link.html">link</a></span>
</div>
</li>
You only want to display one of these hover elements at a time?
Put a single DIV outside of the main body and make it hidden.
Then use javascript to adjust its position and content every time you hover over an LI.
No need to give every LI its own DIV.
Store the contents inside a data attribute
<li id=something data-some-content="Hello joe">
Then you can retrieve it with jQuery like so
$("#something").data('some-content')
Your CSS styles are correct but in your HTML you have two <div> elements with the id='container_c' and that's invalid, IDs are unique and you can't give same id to two or more elements. If you two ore more elements to be given same style then try class='container_c' and in the CSS change the #container_c to .container_c
Check this fiddle for the fixed version
http://jsfiddle.net/DeepakKamat/zwxpG/13/
the solution was a mixture of #NoPyGod's jquery suggestion and to have a better understanding of how absolute and relative positioning work.
basically, when absolute and relative positioning are applied to a div, this position is relative to the position of the last element that had absolute or relative positioning defined and is a 'container' of the div you are working with.
to escape from the 'container' that had overflow: auto and a fixed height and width, i had to remove erroneous positioning back till a parent div that was not constrained by overflow and height and width restraints that were impacting on the hover state div.
a working jsfiddle is here:
http://jsfiddle.net/rwone/eeaAr/
i also implemented #Deepak Kamat's suggestion to only have one id per page and change the rest of the div's to be identified by classes.
i subsequently read the article below that made more sense to me this time and after working in this context:
http://css-tricks.com/the-difference-between-id-and-class/
thank you to all for your assistance!
html
<div id="wrapper">
<div id ="hbar_one"></div>
<div id="hbar_two"></div>
<div id="container_a">
<div id="container_b">
<div class="class1 class2 magic" data-unique-content=".hidden_db_data_div">
<img src="http://lorempixel.com/g/50/50/">
<div class="hidden_db_data_div">
some amazing html
</div>
</div>
<div class="class1 class2 magic" data-unique-content=".hidden_db_data_div">
<img src="http://lorempixel.com/g/50/50/">
<div class="hidden_db_data_div">
more amazing html
</div>
</div>
<div class="class1 class2 magic" data-unique-content=".hidden_db_data_div">
<img src="http://lorempixel.com/g/50/50/">
<div class="hidden_db_data_div">
even more amazing html
</div>
</div>
</div>
</div>
<div id="hbar_three"></div>
<div id="hbar_four"></div>
</div>
css
#wrapper {
width: 300px;
}
#hbar_one {
background: #cc0000;
height: 50px;
}
#hbar_two {
background: #ffcc00;
height: 50px;
}
#container_b {
height: 100px;
overflow-y: auto;
}
.hidden_db_data_div {
display: none;
background: #00AFF0;
width: 120px;
height: 150px;
color: red;
position:absolute;
overflow: hidden;
z-index: 999;
}
img {
width: 50px;
height: 50px;
}
.magic {
display: inline;
}
#container_a { position:relative; }
#hbar_three {
background: #cccccc;
height: 50px;
}
#hbar_four {
background: #000000;
height: 50px;
}
script
$(".magic").hover(
function () {
$(this)
.find('.hidden_db_data_div')
.css({'left':$(this).position().left+20 + "px", 'top':'-20px'})
.fadeIn(200);
},
function() {
$(this)
.find('.hidden_db_data_div')
.fadeOut(100);
}
);

Is there a way to have divs "greedily" grab width?

I have 2 divs that are side by side. They are both closable via jquery. When they are both visible, they have a fixed width, but when one is closed, I want the remaining div to expand to eat up the width that the closed div used to take up. Is there a way to do this using just CSS (aside from the close button), or do I have to resort to javascript?
The only method I could see for solving this with CSS would be to add classes to the containing element:
<div id="container" class="left|right|both">
<div class="left"></div>
<div class="right"></div>
</div>
Style the contents depending on what the parent class is. If left is the class, you give the first div a non-restricted width and hide the second div. The same goes for right and the second div. When the parent is both, you give both divs 50%.
All your JavaScript would need to do is handle which class is currently applied to the container.
You need to atleast write one line of javascript for this and then you can use css for the effect.
Using jquery, toggle a class to the parent of divs whenever you click on the close. Find the jquery code for the click on the close button and add
$("#parent").toggle("classname");
Use css like
#parent div { width: /*fixed*/100px; }
#parent.classname div { width: 100%; }
Does something like this work?
HTML:
<div id="parent">
<div class="right">div2</div>
<div class="left">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam semper porta sem, at ultrices ante interdum at. Donec condimentum euismod consequat. Ut viverra lorem pretium nisi malesuada a vehicula urna aliquet. Proin at ante nec neque commodo bibendum. Cras bibendum egestas lacus, nec ullamcorper augue varius eget.</div>
</div>
<br />
<button id="remove">Remove Div 2</button>
CSS:
#parent {
overflow: hidden;
border: 1px solid red
}
.right {
float: right;
width: 100px;
height: 100px;
background:green;
}
.left {
overflow: hidden;
height: 100px;
background:red;
}​
​
JS:
$('#remove').on('click', function() {
var div2 = $('.right')
//div2.hide('slow'); // you could hide it as well
div2.remove();
});​
Example:
http://jsfiddle.net/9Q86Y/
Edit
You could mimic tables by using
display:table
and
display:table-cell
See: http://jsfiddle.net/DUx3W/ (hat tip: #Jimmy Breck-McKye).
My original table fiddle: http://jsfiddle.net/6KkRL/

Resources