21

I just can't get the button with class align-right to vertically align in the middle.

HTML:

<div class="panel-footer">
    <span style="width:100%;" class="header-footer-item">  
        <button class="align-right" type="button">Save</button>
    </span>    
</div>

CSS:

.panel-footer {
    height: 70px;
    vertical-align: middle;
    border: solid;
}

.header-footer-item {
    display: inline-block;
    line-height: 70px;
    border: solid red;

}

.align-right {
    float: right;
}

.align-middle {
  vertical-align: middle;
}

Here's the jsfiddle: https://jsfiddle.net/d1vrqkn9/2/

If I remove float:right from the button, it works, but I want it on the right.

If I change header-footer-item from inline-block to inline then the floated button renders above its containing element, which I thought was against the rules: (#4 in the accepted answer here How to vertically middle-align floating elements of unknown heights?) - although the parent element is then vertically aligned in the middle.

I have added line heights as per CSS Vertical align does not work with float

The big question is - how do I fix it? I'm also interested to know why making a child element (the button) float right makes the parent element (the span) no longer vertically align in the containing div (but only if it is inline-block, not inline). ...and finally, isn't it 'against the rules' (https://www.w3.org/TR/CSS21/visuren.html#float-rules, #4) for a floating box's outer top to be higher than the top of its containing block? ...which it clearly is if header-footer-item is inline.

There are so many questions about vertically aligning things you'd think they'd make a css for "Seriously, vertically align this thing - no matter what, no complaints, just do it: sudo force vertical-align:middle !important or I'm coming for you"

AndrewL64
  • 15,794
  • 8
  • 47
  • 79
WillyC
  • 3,917
  • 6
  • 35
  • 50
  • 1
    [mcve] in your question please – j08691 Feb 09 '17 at 20:53
  • You want the button to be centered horizontally and vertically? – Donnie D'Amato Feb 09 '17 at 20:55
  • 1
    is it what you need?: https://jsfiddle.net/banzay52/r5bLb1c5/1/ – Banzay Feb 09 '17 at 20:57
  • here is another solution, is that what you want? [https://jsfiddle.net/zyd3jd9b/](https://jsfiddle.net/zyd3jd9b/) – Charlie Ng Feb 09 '17 at 21:01
  • 1
    @j08691 I linked to a jsfiddle page with the exact issue - does that not meet the criteria? – WillyC Feb 09 '17 at 21:03
  • @fauxserious - I want the button on the right but aligned in the middle vertically. – WillyC Feb 09 '17 at 21:04
  • @Banzay Close but the button isn't in the middle - the top of the button is in the middle. I want the centre of the button in the middle. – WillyC Feb 09 '17 at 21:06
  • 1
    No, unfortunately it doesn't meet the criteria. If jsFiddle is ever down, goes away, or blocked, then your question loses all value for future visitors. – j08691 Feb 09 '17 at 21:06
  • @CharlieNg I'd prefer to avoid using display:table, but I appreciate that this works and I wasn't specific on that in the initial post. – WillyC Feb 09 '17 at 21:08
  • the center of button actually is in the middle! :) it's a well known vertical centering trick - top: 50% combine with translateY(-50%); Even you can visually compare my solution with solution using display: table. – Banzay Feb 09 '17 at 21:12
  • According to the selected answer, he wanted the red box centered vertically, and the button inside right aligned. – Donnie D'Amato Feb 09 '17 at 21:14
  • @Banzay I can measure it - the bottom of the button is 1mm closer to the the border than the top of the button. So maybe it isn't that the top of the button is entered, but it is still not centred to the middle (at least in my browser). I can see it even measuring aside. The accepted answer is dead in the middle. – WillyC Feb 09 '17 at 21:17
  • @fauxserious I honestly don't even care about that span, I just had it there because another answer on SO suggested adding another DOM element may make this easier to manipulate. – WillyC Feb 09 '17 at 21:18
  • Except you wouldn't even need that. I'll put an answer that will handle it with just the button. – Donnie D'Amato Feb 09 '17 at 21:19
  • @j08691 OK - sorry, I didn't know. I read the link you provided and didn't see anything that prohibited jsfiddle meeting that criteria but I will include the example directly in the question from here on. Thanks. – WillyC Feb 09 '17 at 21:25
  • Actually try posting a question with no code and a link to jsFiddle and see what happens. You'll get a lovely big, red warning box that explains the issue in a little more detail. – j08691 Feb 09 '17 at 21:26
  • @WillyC I highly recommend to look this as reference in the future [centering-css-complete-guide](https://css-tricks.com/centering-css-complete-guide/) :) – Charlie Ng Feb 10 '17 at 08:39
  • @CharlieNg that looks great - much appreciated! – WillyC Feb 10 '17 at 13:36

6 Answers6

19

The cleanest way to do that is to use flex like this:

  1. Add display: flex to your outer div panel-footer [Check code below]

  2. Remove the float and use text-align:right on the span for the button. [Check code below]

  3. Add align-self: center to the inner span. [Check code below]


For 1:

.panel-footer {
    height: 70px;
    border: solid;
    display:flex;
}

For 2:

.header-footer-item {
        text-align: right;
}

For 3:

.header-footer-item {
    align-self: center;
}

jsFiddle: https://jsfiddle.net/d1vrqkn9/4/

AndrewL64
  • 15,794
  • 8
  • 47
  • 79
  • This looks like a winner. I'd still love to know the answers to my secondary questions because it doesn't seem like it is following 'the rules' as stated at w3.org (specifically that floating elements should not render higher than their containing element), but I'll take it. – WillyC Feb 09 '17 at 21:11
  • "....isn't it 'against the rules' for a floating box's outer top to be higher than the top of its containing block?" -- What do you mean by "higher than"? – AndrewL64 Feb 09 '17 at 21:15
  • Rendered above it on the Y axis. In my original code if you change the span to `display:inline` you can see the button is entirely rendered above (Y axis) the span, which from the w3.org rules I linked too seems wrong. I mean, I'm obviously the one who's incorrect but I am trying to learn why. – WillyC Feb 09 '17 at 21:22
12

Here's a version with proper HTML, and just enough CSS.

.panel-footer {
    height: 70px;
    border: solid;
    position: relative;
}
.panel-footer button {
  position: absolute;
  right: .5em;
  top: 50%;
  transform: translate(0,-50%);
}
    <div class="panel-footer"> 
            <button>Save</button>
    </div>
junkfoodjunkie
  • 3,168
  • 1
  • 19
  • 33
  • The top of the button is aligned in the middle, but I want the centre of the button to be aligned. – WillyC Feb 09 '17 at 21:09
  • 1
    Eh, what? No, the middle of the button is aligned in the center. What browser are you using if you see the top aligned in the middle? – junkfoodjunkie Feb 09 '17 at 21:23
  • It isn't actually the top, but it is slightly shifted to the bottom. If I use a pixel ruler the bottom of that button is 10px closer to the border than the top of the button. Safari 10.0.3. – WillyC Feb 09 '17 at 21:36
1

There's an accepted answer already with some flexbox magic, here's an answer without it and the extra wrapping span element.

.panel-footer{
   position:relative;
  height: 200px;
  border:1px solid #000;
}

.panel-footer button.align-right{
  position:absolute;
  right:0;
  top:50%;
  transform:translateY(-50%);
}
<div class="panel-footer">
    <button class="align-right" type="button">Save</button>
</div>
Donnie D'Amato
  • 3,832
  • 1
  • 15
  • 40
0

If you don't need your button to be box-modeled then you can remove float:right; and add text-align:right to parent.

But I agree with previous answer that flexbox is pretty good answer to all positioning doubts.

Solution with text-align: https://jsfiddle.net/d1vrqkn9/8/

Solution with flexbox: https://jsfiddle.net/d1vrqkn9/9/

Kasia
  • 1,665
  • 1
  • 10
  • 16
0

line-height will do. Try different height values.

<span style="width:100%; line-height: ??px;" class="header-footer-item">
John Phelps
  • 134
  • 1
  • 7
0

In my point of view, trying to achieve that with a float element is a dead end. If your goal is to have an element at the right inside another element, you better use another solution, like table positionning.

You just have to create the 4 following css class (the row element is not used in this case) :

.table {
    display: table;
    width: 100%;
}

.row {
    display: table-row;
    width: 100%;
}

.cell {
    display: table-cell;
}

.cell-min-width {
    display: table-cell;
    width: 1%;
}

Then you just have to change your code for :

<div class="panel-footer table"> <!-- Position with table -->
    <span style="width:100%;" class="header-footer-item">
        <div class="cell"></div><!-- Empty cell to fill the left-->
        <div class="cell-min-width"> <-- Cell with min width to fit the button -->
          <button class="" type="button">Save</button>
        </div>  
    </span>    
</div>

https://jsfiddle.net/outch27/d1vrqkn9/366/

Laurent
  • 469
  • 3
  • 7