display:table-cell doesn't work properly with 100% width - html

I wanted to align text vertically inside of div:
display:table-cell;
vertical-align: middle;
Text is getting aligned, but div (which has 100% width) becomes smaller in width. What is the problem? Is there any other good way to align vertically?
EDIT: little more HTML code:
<div style="position:absolute;top:40%;left:0%;">
<div id="posts" style="position:relative;">
<div style="display:table-cell;vertical-align: middle;width:100%;height:100px;position:relative;text-indent: 1.5em"></div>
<div style="display:table-cell;vertical-align: middle;width:100%;height:100px;position:relative;text-indent: 1.5em"></div>
</div>
</div>

An element displayed as table-cell without any parent explicitly displayed as table will create its own shadowy parent displayed as such (and another in-between set as table-row). It's nowhere to be seen in the DOM but it still have an effect.
The default table layout algorithm is table-layout: auto and you want table-layout: fixed: former layout algorithm will adapt dimensions of cells to your content; latter will respect what the author (you) says for widths. You can test by having very little content in 1 "cell" and then a very long multi-line content.
#posts {
position: relative;
display: table;
table-layout: fixed;
width: 100%;
}
You also should remove or adapt widths on cells: total should be 100% or else it'll be proportional on most browsers (Safari being at risk. Maybe not Saf 8 but 6 at least...)

I have updated your code to get it to work:
<div style="position:absolute;top:40%;left:0%;width:100%;">
<div id="posts "style="position:relative;width:100%;">
<div style="display:table; width:100%;">
<div style="display:table-cell;vertical-align: middle;width:100%;height:100px;position:relative;text-indent: 1.5em;text-align:center;">test
</div>
</div>
</div>
What you needed was to add a div with display: table in and set all the containing elements to 100% width. Also the div you are centring needed a text-align: center.

Related

CSS - Overflow scrolling not working

I have the following markup (see my Plunker):
<div class="workflow-step-container">
<div class="step-container">
<div class="step-bubble completed">1</div>
<span class="divider"></span>
</div>
<div class="step-container">
<div class="step-bubble completed">2</div>
<span class="divider"></span>
</div>
...
</div>
The number of steps (bubbles) can vary. What I would like to happen is if the number of bubbles exceeds the container width, I would like the bubble container to become horizontally scrollable. Currently, the content just wraps.
I've added overflow-x: auto;, but that doesn't seem to work.
Thanks in advance
Update
After adding white-space:nowrap; to my .workflow-step-container styles, the bubbles now do not wrap as desired. In my actual project, though, the content continues to wrap and doesn't ever become scrollable. Here is a screenshot. I tried wrapping the .workflow-step-container div in another div to which I set overflow-x: hidden;, but that did nothing. Here is a Plunker.
You could simply change the white-space property of the parent element to nowrap in order to prevent the inline-level elements from wrapping. In doing so, a horizontal scrollbar will be added when content overflows.
Updated Example
.workflow-step-container {
overflow-x: auto;
white-space: nowrap;
}
Based on your update, you need to add table-layout: fixed/width: 100% to the nested ancestor table element.
The problem was that the table element's width was being determined by the maximum width of the .workflow-step-container element. Adding a width of 100% forces the parent element to take the width of its parent element, and table-layout: fixed changes the layout algorithm to allow for this.
Updated Example
.col-xs-8 table {
table-layout: fixed;
width: 100%;
}

Why would the centering of an HTML element be affected by the width of its nephew?

Here's the basic structure I'm working with
<div class="choiceBox">
<h2>Title</h2>
<div class="column">
<h3>Subtitle 1</h3>
<input type="text">
<select multiple size="10"></select>
</div>
<div class="column">
<h3>Subtitle 2</h3>
<input type="text">
<select multiple size="10"></select>
</div>
</div>
The outer div is nowrap, everything (notably the headings) is centered by inheritance, and the inner divs are inline-blocks. JSFiddle of the CSS here.
There's just one weird thing about it. Originally (as in the JSFiddle above) I had the inputs and selects set to 100% width (by border-box) so that they are always the same width, even if one of them widens. This has the peculiar effect (in Firefox at least) that, when the window is resized to be narrower than the outer div's width, the h2 centers in the window rather than the div. You can see the same thing by shrinking the result frame on the JSFiddle.
This problem goes away by setting min-width instead of width on the select and input, so I do have a solution. But I have no idea why it would behave like this to begin with. Can anyone illuminate this mystery?
EDIT: Ideally, I'd like to know not only why width: 100% does foul things up, but also why min-width: 100% does not.
It is the combination of the display: inline-block; and white-space: nowrap; on the .choiceBox and the width: 100%; of the .column select, .column input.
Because of the display: inline-block; the .choiceBox should be as wide as its content. But with the white-space: nowrap; the width: 100%; is no longer enough to expand the div and it shrinks with the viewport. See: http://jsfiddle.net/1rw6wqee/3/
If I have to pick one, I would say the white-space: nowrap; is the bad guy here.

When does vertical-align works in table-cell, and when doesn't?

Theoretically, vertical-align supposed to work inside an element with display:table-cell. It always works if you add a wrapper with display:table around. But when it has no wrapper, sometimes it will work and sometimes vertical-align will be completely ignored, it seems random. Could you please explain me what are the requirements for a table-cell to support vertical-alignment.
This is a little bit speculative, but in the absence of any examples, I'm going to take a shot in the dark. Maybe you mean something like this:
<!DOCTYPE html>
<title>Test case</title>
<style>
.wrapper { height: 80px; width:100%; }
.percentage .wrapper { border: 1px solid red; }
.fixed .wrapper { border: 1px solid blue; }
.height-cells-test { margin-bottom: 20px; }
.as-block { display: block; }
.as-table { display: table; }
.cell { display:table-cell; vertical-align:middle; }
.percentage .cell { height: 100%; }
.fixed .cell { height: 80px; }
</style>
<div class="percentage height-cells-test">
<div class="wrapper as-block">
<div class="cell">
test percentage height of cell in block
</div>
</div>
<div class="wrapper as-table">
<div class="cell">
test percentage height of cell in table
</div>
</div>
</div>
<div class="fixed height-cells-test">
<div class="wrapper as-block">
<div class="cell">
test fixed height of cell in block
</div>
</div>
<div class="wrapper as-table">
<div class="cell">
test fixed height of cell in table
</div>
</div>
</div>
If you check this out in the jsfiddle, you'll see that of the four .wrapper blocks, the second, third and fourth blocks have their text vertically centred, the text in the first block appears at the top.
This case is when a percentage height for the cell is used in a display:block container.
To understand why this happens, see this text from the CSS 2.1 spec:
Document languages other than HTML may not contain all the elements in the CSS 2.1 table model. In these cases, the "missing" elements must be assumed in order for the table model to work. Any table element will automatically generate necessary anonymous table objects around itself, consisting of at least three nested objects corresponding to a 'table'/'inline-table' element, a 'table-row' element, and a 'table-cell' element. Missing elements generate anonymous objects ...
This is slightly misleading, as it starts by talking about using CSS with languages other than HTML, but what it means is using css table styling without using <table>, <tr>, <td> etc. so it applies here as well where display:table-cell is being used.
The spec goes on to give detailed rules (not reproduced here) about how these anonymous objects are created. The upshot is that in the case of the table-cell inside the block wrapper, an anonymous table and an anonymous table-row are generated around the table cell.
We can ignore the anonymous table-row, as that's not affecting the situation here.
The anonymous table matters though. This object has it's own height, and being a table is only as high as its content needs to be. When the table-cell is then told to be 100% height, that means 100% height of the anonymous table, not 100% of the height of the .wrapper.
So the table is small, and placed at the top left hand corner of the .wrapper, and the table-cell sits inside it. The vertical alignment is still happening, but inside a box that's no bigger than the text, so there's nowhere else for the text to go.
When the .wrapper block has styling of display:table, there is no need for an anonymous table object, and one isn't generated. So the table-cell is as high as the .wrapper and the vertical-align:middle can take effect across the whole of that space.

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/

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. ;-)