Vertical middle for an element within a variable height container - html

I have the following situation:
A variable height div (#container) with an image on the inside (image that is placed within another div) that I need to float:right and align vertically in the middle. How to do this?
Thanks.
EDIT:
Maybe I didn't make it clear enough that i do not know beforehand how much content the container has, from a few lines to a wall of text, so any solution relying on its height won't work (and that's my problem :P)
This is a fiddle with an example of possible content to which align the image: http://jsfiddle.net/9DbmN/

You should take a look at Centering in the Unknown by Chris Coyier. Imo it´s a pretty solid solution to the holy grail of vertical centering.

I would not discourage using tables here))) If you use a two-cell table with vertical-align: middle set on its td elements - it will perfectly (and easily!!!) solve your problem.
If you want to have two containers, one of which (the one with the image) will be floated to the right and needed centering - I'd say you'll have to avoid using float property for this. Because a) as far as I understand you don't need you content on the left to be UNDER the image, right? b) floats are block-level elements and you can't change it even if you set display: table-cell, the browser will still render it as display: block - which leads me to the conclusion that you won't manage to center it by css (at least by the means I'm aware of).
If you don't need ie7 support a possible workaround might be this:
html:
<div id="container">
<div class="content">Content goes here, vertically aligned with the image</div>
<div class="i_used_to_be_floated_right">Image goes here</div>
</div>
css:
#container {
display: table;
width: 100%;
}
.content, .i_used_to_be_floated_right {
display: table-cell;
vertical-align: middle;
}
.content {
background: green;
width: 80%;
}
.i_used_to_be_floated_right{
background: red;
width: 20%;
}
The working example live can be seen here: http://jsfiddle.net/skip405/sDXMj/1/
But if you need ie7 - I would vote for the table-solution I stated at the very beginning.

Related

When a flexbox item has wrapping text the item fills the container and has extra whitespace at the end

Using a flexbox layout, I have a container with three divs in it. What I'm going for is the first div hugging the left edge of the container while the remaining two divs snuggle up on the right edge of the container. I'm admittedly very new to using the flex layout, but it seems straightforward enough.
Simple html:
<div class="container">
<div class="one">Left</div>
<div class="two">Middle</div>
<div class="three">Right</div>
</div>
And associated css:
.container{
display: flex;
align-items: center;
}
.one{
margin-right:auto;
}
The above code usually displays exactly as intended, and for most cases is perfect. Where trouble rears up is when, for example, that third item has enough text to wrap. When this happens the third item fills with whitespace to the right of the text, leaving no space between items one and two. It is subtle with small words, but pretty obvious with two large words that break right in the middle. The following codepen explains it better than I can.
Codepen showing the issue: http://codepen.io/camwheel/pen/XjjyOx
Am I abusing/misusing flex syntax here, or is there a legitimate issue with wrapped text in a flex item? More importantly in the short term, is there anything I can do to get around this issue?
If your divs only contain text then you can do the following:
Skip flexing the last item
text-align: right on the middle element
.container {
display: flex;
background: salmon;
}
.one, .two {
flex: 1;
}
.two {
text-align: right;
}
<div class="container">
<div class="one">Left</div>
<div class="two">Middle</div>
<div class="three">Right</div>
</div>
As Michael_B pointed out in comments, this isn't a flex issue. It comes down to a limitation of CSS. Parent items don't know when child items shrink (which happens to the width when text wraps) and so can't collapse back down. For a more in depth assessment see his earlier post here.

Chrome and Edge floating middle image below first and last, is this correct?

It seems that in Microsoft's edge and google chrome the floating doesn't rearrange the divs properly, if you have three divs floated left and the page is scaled in a width between 444 and 436 px the third div goes to the second div's position instead of going below it. This "bug" does not occur in firefox.
I made a JSFiddle to be tested http://jsfiddle.net/e47jckrh/
HTML
<div id="d1">
<p>1</p>
</div>
<div id="d2">
<p>2</p>
</div>
<div id="d3">
<p>3</p>
</div>
CSS
div{
float: left;
}
Down below there is a visual representation of how it should behave
Full page Layout
Correct div floating when page width is more than 444px
Wrong div floating order when page width is between 444 and 436px
Correct div floating when page width is less than 444px
It may be just me thinking there is something wrong, but i assume the firefox behavior to be the correct one.
I've edited your fiddle here: http://jsfiddle.net/e47jckrh/5/
You didn't float all your elements as you'd suggested in the question. So I added float: left; to the div numbered 3 and set all 3 to display: inline-block;. And using display: table; and display: table-cell; with vertical-align: center; is a really old way to get something to align vertically.
These 3 lines work for most things:
position: relative;
top: 50%;
transform: translateY(-50%);
Okay. So #d3 shouldn't be on the right side at all because it isn't floated, but you used display:table. This gives it the effect of being floated with the other two divs for some reason.
Since it uses display: table #d3's margins are off the page but don't count as "not fitting" and don't force it to the next line.
#d2 is floated though so its margins DO affect it. So in the small range you're experiencing this #d1 + #d2 won't fit because of their margins contributing to an overall larger size width but #d1 + #d3 will because #d3 is not being affected by its margin on the right side giving the combo an overall smaller size width.
Simple solution is to float #d3 as well:
#d3 {
background-color: #ede4ad;
border: 3px dotted #6e5b3c;
clear: right;
float: left;
}
The behavior is caused by margin-right.
When div 2 reaches its containers right limit it overflows. In this case you control his limit by margin-right. BUT margin-right is only effective if there is succeeding element ( its calculated base on a succeeding element ). In this case div 3.
After it overflows in new line the div 3 takes its spot. But in this case margin-right has no effect since its the last element in this flow.
EDIT : I just realized you haven't floated all element , I don't know if that was your initial idea. If it was I won't delete this answer.

Vertical centering of multiple images inside one DIV

I have a simple DIV with a fixed height like and several images with individual heights inside (their height is equal or less the height of the outer DIV):
<div>
<img src="..">
<img src="..">
...
</div>
This markup is as-is and can not be changed. I need to display all images side by side and all images should be vertically aligned with the middle of the DIV (so the padding top and bottom is identical per-image).
How to do that without changing the markup? Various answers deal with a markup where the image is placed itself inside a DIV which is not the case here.
After re-reading your question, that the <div> is at least as high as the highest image, simply do this:
CSS
img {
vertical-align: middle;
}​
Try it here: http://jsfiddle.net/AsD9q/
You can also prevent the div from breaking (when the viewport is to small) by setting an explicit width or using white-space: nowrap; on the container: http://jsfiddle.net/MvDZJ/ (using width) or http://jsfiddle.net/xMtBp/ (using white-space)
That's the outcome:
First answer, which works with every height of the div:
As you said nothing about container itself, I assume, that it's not wider than the viewport. Than you could simply do something like this:
HTML
<div>
<img src="http://lorempixel.com/200/100/">
<img src="http://lorempixel.com/200/80/">
<img src="http://lorempixel.com/200/120/">
<img src="http://lorempixel.com/200/60/">
</div>​
CSS
​div {
display: table-cell;
vertical-align: middle;
/* only added for demonstration */
height: 200px;
border: 1px solid red;
}
img {
vertical-align: middle;
}
This won't work in IE7 though, as it can't handle display: table-cell. You can try it here: http://jsfiddle.net/3vXXy/.
This can be done with jQuery, the problem is you have no explicit selectors to work with so it would affect every image in every div on the page.
First you need to set the images to the top of the div like this in the CSS:
div img{vertical-align:top;}
Then take each image in succession, get it's height and set it's top padding to half the difference between the height of the div and the height of the image.
​$(document).ready(function(){
$("img").each(function(){
var margin= ($(this).parent().height() - $(this).height())/2;
$(this).css('margin-top',margin);
});
});​
Again, not an ideal solution without good solid selectors, but it does work. http://jsfiddle.net/calder12/H4Wkw/

Image goes beyond container div bounds

Can someone take a look at the following fiddle: http://jsfiddle.net/R4bCy/1/
I thought that a div should adjust it's height in order to accommodate it's elements, unless the elements are positioned absolutely.
Why does the div not expand to the full height of the image?
I need to the image to be aligned to the right. The only ways that I know how to do this is align='right', position:absolute; right: 0; and float:right, all of which make the containing div not adjust it's height to the image height.
.intro {
margin: 10px;
outline: 1px solid #CCC;
background: #A00;
color: #FFF;
height:auto;
overflow:auto;
}
​.img{
float:right;
height:auto;
}​
<div class="intro">
<div class="img"> <img src="http://1.bp.blogspot.com/_74so2YIdYpM/TEd09Hqrm6I/AAAAAAAAApY/rwGCm5_Tawg/s1600/tall+copy.jpg" style="margin: 10px 10px; "/></div>
<p>Sorry, but the page you requested could not be found.</p>
</div>​​​​​​​​​​
DEMO
'Why does the div not expand to the full height of the image?'
Because floats will overlap with blocks, only block formatting contexts contain floats. (You can find a pretty good overview of the whole topic here: http://www.yuiblog.com/blog/2010/05/19/css-101-block-formatting-contexts/ )
On to solve the problem at hand:
The align=right will actually result in the img being float: right (the align attribute is deprecated and css should be used).
To contain the floated image in its parent div you need either have the parent div establish a block formatting context (block formatting contexts enclose nested floats) or explicitly clear the float with an additional element after the img that is styled as a clear: right.
An easy solution to create a block formatting context is to float the parent div as well, although my preferred solution in this case would be to simply set its overflow to hidden (also resulting in a block formatting context).
Check out the updated fiddle http://jsfiddle.net/R4bCy/8/.
What you need to do is add after the p tag,
<div style="clear:both;"></div>
Whoops, apologies, posted and you edited your question - the align right is floating it I believe (you should instead use float:right and a clearfix of some sort).
example: http://jsfiddle.net/R4bCy/5/
This is what I believe you want:
http://jsfiddle.net/R4bCy/6/
If you wanted the text on the left and the image floated to the right, please do this is your CSS:
http://jsfiddle.net/R4bCy/15/
You can also have two divs that have a width of 50% contained within a container div. This will allow you a little more flexibility in your placement of the image because the text and image will each have their own modifiable divs with independent attributes

Three part dynamic spacing wo/Table and Absolute Positioning

I'm trying to place 3 divs within a larger div such that the center one is 800px wide, and centered, and the other two fill the space remaining. I cannot use tables, nor can I use absolute positioning, as I have html below that must be outside the three divs but inside the larger div. I can get the center div:
.center-div {
width: 800px;
margin-left: auto;
margin-right: auto;
}
But how do I position the other two divs?
<div id="outer">
<div id="left-div"></div>
<div id="center-div"></div>
<div id="right-div"></div>
</div>
You could try messing around with display: table-row; for the container div and display: table-cell; for the inner divs. You might even need a second container with display: table;—the basic idea is emulating a table without using table, tr, and td.
All those table-values for the display property are specified in CSS 2.1, but I have never personally tested which browsers support them. I’ll bet my money though that IE6 won’t be able to cope with it. ;-)