Search code examples
htmlcss

One element's vertical alignment varies based on content of adjacent element


Here's what I am unable to recreate:

enter image description here

link to jsfiddle for reference

Here's the issue I'm having, "BBC" appears to jump up/down based on whether sign-in is included in the next div block. I can't get the border to stay within the 40px or get the "sign in" or "BBC" text to center or the BBC to center. I spent a couple of hours testing various items, but I couldn't get it to work--It would be very much appreciated if you could explain the code and the behavior that is taking place (why the HTML is rendering the way it is). Why do the BBC and left border of Sign In overflow the 40px height?

html, body, p {
  margin: 0;
  padding: 0;
}
.container {
  width: 1000px;
  margin: 0 auto;
}
.top-nav-bar {
  height: 40px;
  border-bottom: 1px firebrick solid;
  margin-bottom: 30px;
}
.top-nav-logo-area {
  display: inline-block;
  padding-right: 25px;
}
.logo {
  background-color: black;
  color: white;
  font-family: monospace;
  font-size: 25px;
}
.top-nav-link-div {
  display: inline-block;
  border-left: 1px #cccccc solid;
  height: 40px;
}
<!-- WITH CONTENT NEXT TO LOGO -->

<div class="container top-nav-bar">

  <div class="top-nav-logo-area">
    <span class="logo">B</span>
    <span class="logo">B</span>
    <span class="logo">C</span>
  </div>

  <div class="top-nav-link-div">
    hello
  </div>
</div>


<!--WITHOUT CONTENT NEXT TO LOGO -->

<div class="container top-nav-bar">

  <div class="top-nav-logo-area">
    <span class="logo">B</span>
    <span class="logo">B</span>
    <span class="logo">C</span>
  </div>

  <div class="top-nav-link-div">
    <!-- empty -->

  </div>
</div>


Solution

  • You're dealing with inline-block elements.

    The default value of the vertical-align property, which applies to inline-level elements, is baseline. This takes the logo container (.top-nav-logo-area) and aligns its baseline (or bottom margin edge, if there is no baseline), with the baseline of the parent box (.top-nav-bar).

    Except, you have constrained the height of the parent with height: 40px (the natural height is 46px).

    This forces the logo box to overflow the bottom of the parent.

    Whether or not the height of the parent is shortened, the vertical-align property should work on the logo container.

    From the spec:

    vertical-align

    This property affects the vertical positioning inside a line box of the boxes generated by an inline-level element.

    baseline

    Align the baseline of the box with the baseline of the parent box. If the box does not have a baseline, align the bottom margin edge with the parent's baseline.

    middle

    Align the vertical midpoint of the box with the baseline of the parent box plus half the x-height of the parent.

    * { box-sizing: border-box; }
    
    html, body, p {
        margin: 0;
        padding: 0;
    }
    
    .container {
        width: 1000px;
        margin: 0 auto;
    }
    
    .top-nav-bar {
        height: 40px;             /* height constrained; natural height 46px */
        border-bottom: 1px firebrick solid;
        margin-bottom: 30px;
    }
    
    .top-nav-logo-area {
        display: inline-block;
        padding-right: 25px;
        border: 1px dashed red;
        vertical-align: top;     /* other options include `baseline`, `bottom` and `middle` */
    }
    
    .logo {
        background-color: black;
        color: white;
        font-family: monospace;
        font-size: 25px;
    }
    
    .top-nav-link-div {
        display: inline-block;
        border-left: 1px #cccccc solid;
        height: 40px;
    }
    <!-- WITH CONTENT NEXT TO LOGO -->
    <div class="container top-nav-bar">
        <div class="top-nav-logo-area">
            <span class="logo">B</span>
            <span class="logo">B</span>
            <span class="logo">C</span>
        </div>
        <div class="top-nav-link-div">
            hello
        </div>
    </div>
    
    <!--WITHOUT CONTENT NEXT TO LOGO -->
    <div class="container top-nav-bar">
        <div class="top-nav-logo-area">
            <span class="logo">B</span>
            <span class="logo">B</span>
            <span class="logo">C</span>
        </div>
        <div class="top-nav-link-div"><!-- empty --></div>
    </div>

    jsFiddle