当边项具有不同宽度时,保持中间项居中

Keep the middle item centered when side items have different widths

设想以下布局,其中点代表方框之间的 space:

[Left box]......[Center box]......[Right box]

当我删除右边的框时,我喜欢中心框仍然在中心,像这样:

[Left box]......[Center box].................

如果我删除左边的框,同样如此。

................[Center box].................

现在,当中心框中的内容变长时,它将根据需要占用尽可能多的可用空间 space,同时保持居中。左右框永远不会缩小,因此当where没有space离开时,overflow:hiddentext-overflow: ellipsis将生效以打破内容;

[Left box][Center boxxxxxxxxxxxxx][Right box]

以上都是我理想中的情况,但是不知道怎么实现这个效果。因为当我像这样创建一个弹性结构时:

.parent {
    display : flex; // flex box
    justify-content : space-between; // horizontal alignment
    align-content   : center; // vertical alignment
}

如果左右框的大小完全一样,我就得到了想要的效果。但是,当两者之一来自不同尺寸时,居中框不再真正居中。

有没有人可以帮助我?

更新

A justify-self 会很好,这将是理想的:

.leftBox {
     justify-self : flex-start;
}

.rightBox {
    justify-self : flex-end;
}

If the left and right boxes would be exactly the same size, I get the desired effect. However when one of the two is a different size the centered box is not truly centered anymore. Is there anyone that can help me?

这里有一个使用 flexbox 使中间项目居中的方法,无论兄弟姐妹的宽度如何。

主要特点:

  • 纯粹CSS
  • 无绝对定位
  • 没有JS/jQuery

使用嵌套弹性容器和 auto 边距:

.container {
  display: flex;
}
.box {
  flex: 1;
  display: flex;
  justify-content: center;
}

.box:first-child > span { margin-right: auto; }

.box:last-child  > span { margin-left: auto;  }

/* non-essential */
.box {
  align-items: center;
  border: 1px solid #ccc;
  background-color: lightgreen;
  height: 40px;
}
p {
  text-align: center;
  margin: 5px 0 0 0;
}
<div class="container">
  <div class="box"><span>short text</span></div>
  <div class="box"><span>centered text</span></div>
  <div class="box"><span>loooooooooooooooong text</span></div>
</div>
<p>&#8593;<br>true center</p>

工作原理如下:

  • top-level div (.container) 是弹性容器。
  • 每个 child div (.box) 现在都是弹性项目。
  • 每个 .box 项目被给予 flex: 1 以便平均分配容器 space ()。
  • 现在这些项目占用了行中的所有 space 并且宽度相等。
  • 使每个项目成为(嵌套的)弹性容器并添加 justify-content: center
  • 现在每个 span 元素都是一个居中的弹性项目。
  • 使用弹性 auto 边距左右移动外部 span

您也可以放弃 justify-content 而只使用 auto 页边距。

但是 justify-content 可以在这里工作,因为 auto 页边距总是优先的。

8.1. Aligning with auto margins

Prior to alignment via justify-content and align-self, any positive free space is distributed to auto margins in that dimension.

  1. 在容器中使用三个弹性项目
  2. 设置flex: 1为第一个和最后一个。这使得它们平均增长以填充中间一个剩余的可用 space。
  3. 因此,中间的会趋于居中
  4. 但是,如果第一个或最后一个项目具有宽内容,则该弹性项目也会由于新的 min-width: auto 初始值而增长。

    注意 Chrome 似乎没有正确实施。但是,您可以将 min-width 设置为 -webkit-max-content-webkit-min-content,它也会起作用。

  5. 只有在那种情况下,中间元素才会被推出中心。

.outer-wrapper {
  display: flex;
}
.item {
  background: lime;
  margin: 5px;
}
.left.inner-wrapper, .right.inner-wrapper {
  flex: 1;
  display: flex;
  min-width: -webkit-min-content; /* Workaround to Chrome bug */
}
.right.inner-wrapper {
  justify-content: flex-end;
}
.animate {
  animation: anim 5s infinite alternate;
}
@keyframes anim {
  from { min-width: 0 }
  to { min-width: 100vw; }
}
<div class="outer-wrapper">
  <div class="left inner-wrapper">
    <div class="item animate">Left</div>
  </div>
  <div class="center inner-wrapper">
    <div class="item">Center</div>
  </div>
  <div class="right inner-wrapper">
    <div class="item">Right</div>
  </div>
</div>
<!-- Analogous to above --> <div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item animate">Center</div></div><div class="right inner-wrapper"><div class="item">Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">Left</div></div><div class="center inner-wrapper"><div class="item">Center</div></div><div class="right inner-wrapper"><div class="item animate">Right</div></div></div>

您可以这样做:

.bar {
    display: flex;    
    background: #B0BEC5;
}
.l {
    width: 50%;
    flex-shrink: 1;
    display: flex;
}
.l-content {
    background: #9C27B0;
}
.m { 
    flex-shrink: 0;
}
.m-content {    
    text-align: center;
    background: #2196F3;
}
.r {
    width: 50%;
    flex-shrink: 1;
    display: flex;
    flex-direction: row-reverse;
}
.r-content { 
    background: #E91E63;
}
<div class="bar">
    <div class="l">
        <div class="l-content">This is really long content.  More content.  So much content.</div>
    </div>
    <div class="m">
        <div class="m-content">This will always be in the center.</div>
    </div>
    <div class="r">
        <div class="r-content">This is short.</div>
    </div>
</div>

不是默认使用 flexbox,而是使用 grid 在 2 行 CSS 中解决它,而在顶级子项中没有额外的标记。

HTML:

<header class="header">
  <div class="left">variable content</div>
  <div class="middle">variable content</div>
  <div class="right">variable content which happens to be very long</div>
</header>

CSS:

.header {
  display: grid;
  grid-template-columns: [first] 20% auto [last] 20%;
}
.middle {
  /* use either */
  margin: 0 auto;
  /* or */
  text-align: center;
}

Flexbox 很不错,但不应该是所有问题的答案。在这种情况下,网格显然是最干净的选择。

甚至为您的测试乐趣制作了一个代码笔: https://codepen.io/anon/pen/mooQOV

您也可以使用这种简单的方法来实现中间元素的精确居中对齐:

.container {
    display: flex;
    justify-content: space-between;
}

.container .sibling {
    display: flex;
    align-items: center;
    height: 50px;
    background-color: gray;
}

.container .sibling:first-child {
    width: 50%;
    display: flex;
    justify-content: space-between;
}

.container .sibling:last-child {
    justify-content: flex-end;
    width: 50%;
    box-sizing: border-box;
    padding-left: 100px; /* .center's width divided by 2 */
}

.container .sibling:last-child .content {
    text-align: right;
}

.container .sibling .center {
    height: 100%;
    width: 200px;
    background-color: lightgreen;
    transform: translateX(50%);
}

代码笔:https://codepen.io/ErAz7/pen/mdeBKLG

这是一个使用网格而不是 flexbox 的答案。此解决方案不需要 HTML 中的额外孙元素,就像接受的答案那样。与 2019 年的网格答案不同,即使一侧的内容足够长以溢出到中心,它也能正常工作。

该解决方案没有做的一件事是显示省略号或隐藏中心框中的额外内容,如问题中所述。

section {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
}

section > *:last-child {
  white-space: nowrap;
  text-align: right;
}

/* not essential; just for demo purposes */
section {
  background-color: #eee;
  font-family: helvetica, arial;
  font-size: 10pt;
  padding: 4px;
}

section > * {
  border: 1px solid #bbb;
  padding: 2px;
}
<section>
  <div>left</div>
  <div>center</div>
  <div>right side is longer</div>
</section>

<section>
  <div>left</div>
  <div>center</div>
  <div>right side is much, much longer</div>
</section>

<section>
  <div>left</div>
  <div>center</div>
  <div>right side is much, much longer, super long in fact</div>
</section>

这是另一种方法,在 parents 和孩子中使用 display: flex

.Layout{
    display: flex;
    justify-content: center;
}
.Left{
    display: flex;
    justify-content: flex-start;
    width: 100%;
}
.Right{
    display: flex;
    justify-content: flex-end;
    width: 100%;
}
<div class = 'Layout'>
    <div class = 'Left'>I'm on the left</div>
    <div class = 'Mid'>Centered</div>
    <div class = 'Right'>I'm on the right</div>
</div>

虽然我在这方面可能会迟到,但所有这些解决方案似乎都很复杂,并且可能无法正常工作,具体取决于您所面临的情况。

非常简单,只需将要居中的组件用 position : absolute 包裹起来,同时让其他两个用 justify-content : space-between 包裹起来,就像这样:

CSS:

.container {
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: lightgray;
}

.middle {
  position: absolute;
  margin-left: auto;
  margin-right: auto;
  /* You should adapt percentages here if you have a background ; else, left: 0 and right: 0 should do the trick */
  left: 40%;
  right: 40%;
  text-align: center;
}

/* non-essential, copied from @Brian Morearty answer */
.element {
  border: 1px solid #ccc;
  background-color: lightgreen;
}

p {
  margin: 5px;
  padding: 5px;
}
<div class="container">
  <p class="element">First block</p>
  <p class="middle element">Middle block</p>
  <p class="element">Third THICC blockkkkkkkkk</p>
</div>

关键是要用flex-basis。那么解决方案很简单:

.parent {
    display: flex;
    justify-content: space-between;
}

.left, .right {
   flex-grow: 1;
   flex-basis: 0;
}

CodePen 可用 here

稍微更健壮的网格解决方案如下所示:

.container {
  overflow: hidden;
  border-radius: 2px;
  padding: 4px;
  background: orange;
  display: grid;
  grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr);
}

.item > div {
  display: inline-block;
  padding: 6px;
  border-radius: 2px;
  background: teal;
}

.item:last-child > div {
  float: right;
}
<div class="container">
  <div class="item"><div contenteditable>edit the text to test the layout</div></div>
  <div class="item"><div contenteditable>just click me and</div></div>
  <div class="item"><div contenteditable>edit</div></div>
</div>

您可以在 Codepen 中看到它:https://codepen.io/benshope2234/pen/qBmZJWN

我想要问题中显示的确切结果,我结合了 gamliela 和 Erik Martín Jordán 的答案,它最适合我。

.parent {
    display: flex;
    justify-content: space-between;
}

.left, .right {
   flex-grow: 1;
   flex-basis: 0;
}

.right {
   display: flex;
   justify-content: flex-end;
}

Michael Benjamin 有一个不错的答案,但没有理由不能/不应该进一步简化:

.container {
  display: flex;
}

.box {
  flex: 1;
  display: flex;
  justify-content: center;
}

.box:first-child { justify-content: left; }

.box:last-child  { justify-content: right;  }

和html

<div class="container">
  <div class="box">short text</div>
  <div class="box">centered tex</div>
  <div class="box">loooooooooooooooong text</div>
</div>