沿共享基线垂直对齐相同高度块的文本(支持混合字体大小)

Vertically align text of same-height blocks along a shared baseline (supporting mixed font size)

我有一个 single-line/row navigation/menu,其中一些项目的字体更大,但我希望所有项目的文本沿着基线和谐对齐。

我还需要这些项目对悬停在菜单的整个高度上做出反应,这样用户就不必瞄准较小的文本(这是针对子菜单的,但不是这个问题的一部分)。

我尝试使用 Flexbox,但我不能混合使用 align-items: stretch(全高)和 align-items: baseline(文本对齐)

注意:菜单项的文本在 menu-item-label 包装器中,因为我将向项目添加更多内容(下拉箭头、图片...),但重要的是文本对齐方式。

body {
  font-size: 24px; /* Big value to ease highlighting of mis-alignemnt */
}

.some-existing-container {
  /* This container has some dimensions: I don't think it would cause conflict. */
  width: 100%;
  height: 4em;

  display: flex;
  align-items: center; /* Not mandatory */

  border: 1px solid blue; /* Highlighting */
}

.menu {
  display: flex;
  align-items: baseline;

  border: 1px solid green; /* Highlighting */
}

.menu-item {
  border: 1px dotted brown; /* Highlighting */
}

.menu-item:hover {
  background-color: grey; /* Highlighting */
}

.menu-item-label {
  border: 1px dotted pink; /* Highlighting */
}

.other {
  margin-left: auto; /* Places this block to the right in .some-existing-container */

  border: 1px solid purple; /* Highlighting */
}

.bigger {
  font-size: 4rem;
}

.stretched {
  align-items: stretch;
}
<p>Variant 1: Texts are aligned but items does not occupies the whole height:</p>
<div class="main">
  <div class="some-existing-container">
    <div class="menu">
      <div class="menu-item">
        <div class="menu-item-label">
          Home
        </div>
      </div>
      <div class="bigger menu-item">
        <div class="menu-item-label">
          Item1
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item2
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item3
        </div>
      </div>
    </div>
    <div class="other">
      Other
    </div>
  </div>
</div>
<p>Variant 2: Items of same-and-full height but texts are not aligned:</p>
<div class="main">
  <div class="some-existing-container">
    <div class="menu stretched">
      <div class="menu-item">
        <div class="menu-item-label">
          Home
        </div>
      </div>
      <div class="bigger menu-item">
        <div class="menu-item-label">
          Item1
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item2
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item3
        </div>
      </div>
    </div>
    <div class="other">
      Other
    </div>
  </div>
</div>

我想将两者混合为下面的蒙太奇:

有没有可能(有或没有JavaScript)?

我也尝试过网格布局但没有成功(参见 this JSFiddle)。

您尝试过使用 CSS 网格布局吗? https://www.w3schools.com/css/css_grid.asp

更新:

抱歉,我没有注意到您已经尝试过网格布局。 但我确实认为可以通过网格布局来实现它。

您介意发布您的代码的网格布局版本吗?我也许可以帮助你。

谢谢

  • 因为您的包装器“菜单”没有自己的高度,请为其设置高度,例如:
    .menu {
      height: 4rem;
      align-items: stretch
    }
  • 接下来,您应该添加“菜单项”:
    .menu-item {
      display: flex;
      align-items: center;
    }

我会保持基线对齐并考虑使用伪元素技巧来增加悬停区域:

body {
  font-size: 24px; /* Big value to ease highlighting of mis-alignemnt */
}

.some-existing-container {
  height: 4em;
  display: flex;
  align-items: center; 
  border: 1px solid blue; 
}

.menu {
  display: flex;
  align-items: baseline;
  border: 1px solid green; 
  overflow:hidden;
}

.menu-item {
  border: 1px dotted brown; 
  position:relative;
  z-index:0;
}
.menu-item::before {
  content:"";
  position:absolute;
  z-index:-1;
  top:-200px;
  bottom:-200px;
  left:0;
  right:0;
}

.menu-item:hover,
.menu-item:hover::before{
  background-color: grey;
}

.menu-item-label {
  border: 1px dotted pink; 
}

.other {
  margin-left: auto; 
  border: 1px solid purple; 
}

.bigger {
  font-size: 4rem;
}
<div class="main">
  <div class="some-existing-container">
    <div class="menu">
      <div class="menu-item">
        <div class="menu-item-label">
          Home
        </div>
      </div>
      <div class="bigger menu-item">
        <div class="menu-item-label">
          Item1
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item2
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item3
        </div>
      </div>
    </div>
    <div class="other">
      Other
    </div>
  </div>
</div>

这是我稍微修正一下你的 css 后的结果。

body {
  font-size: 24px; /* Big value to ease highlighting of mis-alignemnt */
}

.some-existing-container {
  /* This container has some dimensions: I don't think it would cause conflict. */
  width: 100%;
  height: 4em;

  display: flex;
  align-items: center; /* Not mandatory */

  border: 1px solid blue; /* Highlighting */
}

.menu {
  display: flex;
  align-items: baseline;
  /* Add this css */
  height: 4rem;
  ///////////////
  border: 1px solid green; /* Highlighting */
}

.menu-item {
  border: 1px dotted brown; /* Highlighting */
  /* Add this css */
  display: flex;
  align-items: center;
  //////////////////
}

.menu-item:hover {
  background-color: grey; /* Highlighting */
}

.menu-item-label {
  border: 1px dotted pink; /* Highlighting */
}

.other {
  margin-left: auto; /* Places this block to the right in .some-existing-container */

  border: 1px solid purple; /* Highlighting */
}

.bigger {
  font-size: 4rem;
}

.stretched {
  align-items: stretch;
}
<p>Variant 1: Texts are aligned but items does not occupies the whole height:</p>
<div class="main">
  <div class="some-existing-container">
    <div class="menu">
      <div class="menu-item">
        <div class="menu-item-label">
          Home
        </div>
      </div>
      <div class="bigger menu-item">
        <div class="menu-item-label">
          Item1
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item2
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item3
        </div>
      </div>
    </div>
    <div class="other">
      Other
    </div>
  </div>
</div>
<p>Variant 2: Items of same-and-full height but texts are not aligned:</p>
<div class="main">
  <div class="some-existing-container">
    <div class="menu stretched">
      <div class="menu-item">
        <div class="menu-item-label">
          Home
        </div>
      </div>
      <div class="bigger menu-item">
        <div class="menu-item-label">
          Item1
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item2
        </div>
      </div>
      <div class="menu-item">
        <div class="menu-item-label">
          Item3
        </div>
      </div>
    </div>
    <div class="other">
      Other
    </div>
  </div>
</div>