1

This question resulted from a fix suggested to this related question

I have 3 nested divs: outer, inner and item.

<div class="outer">
  <div class="inner"><div class="item"></div></div>
</div>

Given the following basic CSS:

.outer{
  width:50%;
  height:100px;
  border: 1px solid red;
  position:relative;
  overflow-x:hidden;
  box-sizing:border-box;
}
.inner{
  border:1px solid blue;
  height:100%;
  position: absolute;
  box-sizing: border-box;
  line-height:98px;
}
.item{
  width:100px;
  height:94px;
  background-color:yellow;
  display: inline-block;
  border:1px solid green;
  box-sizing:border-box;
  vertical-align:middle;
}

The challenge is to center the 'item' div vertically with equal (or no) gaps above/below, and no vertical scrollbars appearing.

Codepen here

Update:

As pointed out below, I should add that multiple items of different heights must be centered. The best answer so far is to add a negative margin to each item, resulting in the following: http://codepen.io/anon/pen/dYWEYZ

However, this smells bad (to me) as it requires an offset that depends on 3 other properties.

Community
  • 1
  • 1
Will Jenkins
  • 9,507
  • 1
  • 27
  • 46
  • there is so much hacky stuff here, why not just add another: margin-top: -5px; to the .item class centers it. http://codepen.io/anon/pen/PPmgBR – deebs Oct 07 '15 at 15:27
  • seems like it, with the 98px line-height, have to have overflow-x: hidden, have to have inline-block on the .item class. Either way, the margin-top: -5px fixes it because it adjusts to the 1px border for outer and inner (4px total) and line-height difference. If you make the borders 2px on outer and inner (8px total) then then margin top becomes -9px and it is fine. It's all about the borders, with the line-height thrown in – deebs Oct 07 '15 at 15:33
  • 2
    None of those things are hacky, they're required by the design. It's for an image carousel, the images are different heights and need to be stacked up together (needing inline-block), the overflow hidden is to only show some of the images at a time, yada yada. It's all required. – Will Jenkins Oct 07 '15 at 15:43

3 Answers3

0

If you use flexbox, this is easily achieved:

.inner{
  border:1px solid blue;
  height:100%;
  position: absolute;
  box-sizing: border-box;
  line-height:98px;
  display:flex;
  align-items:center;
}
Jesse
  • 1,262
  • 1
  • 9
  • 19
0

You can use display: table-cell; to get the vertical centering you want:

.outer{
  width:50%;
  height:100px;
  border: 1px solid red;
  position:relative;
  overflow-x:hidden;
  box-sizing:border-box;
}
.inner{
  border:1px solid blue;
  height:100%;
  position: absolute;
  box-sizing: border-box;
  line-height:98px;
  display: table; //must change this as well
}
.item{
  width:100px;
  height:94px;
  background-color:yellow;
  border:1px solid green;
  box-sizing:border-box;
  vertical-align:middle;
  display:table-cell; //update display type
}
Andrea
  • 839
  • 8
  • 21
0

The simple solution is http://codepen.io/anon/pen/jbmRjo

to add this to your .item class:

margin-top: -5px;

It's because of the borders on your outer and inner classes, as well as the line-height of the inner class. If you make the borders 2px instead of 1px, then the margin top becomes -9px. If you leave borders at 1px and make the line-height 96px the margin top becomes -3px.

So why can't you use a negative margin top?

deebs
  • 1,390
  • 10
  • 23
  • This does work (http://codepen.io/anon/pen/dYWEYZ) but it smells bad. The fact that we have to allow for 3 other dimensions outside the item is not great but if no-one else has a better solution I'll accept this answer... – Will Jenkins Oct 07 '15 at 15:46
  • I agree that it stinks a bit. It's definitely an interesting scenario though - is this something you're working on, or just curious about? – deebs Oct 07 '15 at 17:23