【问题标题】:Keep the middle item centered when side items have different widths当侧项具有不同的宽度时,保持中间项居中
【发布时间】:2015-11-29 11:37:48
【问题描述】:

想象以下布局,其中的点表示框之间的空间:

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

当我移除右边的盒子时,我喜欢中心盒子仍然在中心,就像这样:

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

如果我要删除左边的框,也是如此。

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

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

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

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

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

如果左右框大小完全相同,我会得到想要的效果。但是,当两者之一的大小不同时,居中的框不再真正居中。

有没有人可以帮助我?

更新

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

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

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

【问题讨论】:

  • 基本上......你不能。这不是flexbox 应该如何工作的。您可以尝试另一种方法。
  • 如果这样做的话,真的会完成 flexbox。因为 flexbox 是关于分配空间以及项目在其中的行为方式。
  • 我们今天早些时候讨论了justify-self,所以你可能会觉得这很有趣:stackoverflow.com/questions/32551291/…

标签: html css flexbox centering


【解决方案1】:

如果左右框的大小完全相同,我会得到想要的效果。但是,当两者之一的大小不同时,居中的框不再真正居中。有没有人可以帮助我?

这是一个使用 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>

它是这样工作的:

  • 顶级 div (.container) 是一个弹性容器。
  • 每个子 div (.box) 现在都是一个弹性项目。
  • 为每个 .box 项目分配 flex: 1 以便平均分配容器空间 (more details)。
  • 现在项目占用了行中的所有空间并且宽度相等。
  • 使每个项目成为(嵌套的)弹性容器并添加justify-content: center
  • 现在每个span 元素都是居中的弹性项目。
  • 使用 flex auto 边距将外部 spans 左右移动。

您也可以放弃 justify-content 并专门使用 auto 边距。

但是justify-content 可以在这里工作,因为auto 边距始终具有优先权。

8.1. Aligning with auto margins

在通过justify-contentalign-self 对齐之前,任何 正的可用空间分配到该维度的自动边距。

【讨论】:

  • 此解决方案不允许指定width
  • 更改弯曲元素的宽度以均匀分布空间完全忽略了 OP 的问题。他们的问题在元素之间有空间。例如:“想象以下布局,其中的点代表框之间的空间。”在 3 个大小均匀的元素中居中文本很简单。
  • OP 还说“当我移除右侧框时,我希望中心框仍然在中心,就像这样”,如果不使用第三个空列,您将如何处理?
  • 这正是我实现 MacOS 风格的窗口标题栏所需要的。添加white-space: nowrap 是防止文本在区域变得太小时时换行的最后一块拼图。
  • 这根本不允许元素像 OPs 问题那样具有不同的大小。
【解决方案2】:
  1. 在容器中使用三个弹性项目
  2. flex: 1 设置为第一个和最后一个。这使得它们平均增长以填充中间的可用空间。
  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>

【讨论】:

  • 优秀的解决方案。但是,我相信可以删除“中心” div 上的样式,因为“中心内部包装器”没有匹配的 CSS。 @Oriol
  • 这是一个比批准的解决方案更好的解决方案。只需在左右元素上设置flex: 1; 即可。
【解决方案3】:

你可以这样做:

.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>

【讨论】:

    【解决方案4】:

    与默认使用 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

    【讨论】:

    • +1 表示承认除了flex 之外可能还有其他选择。我唯一的反对意见是使用 flex (align-items: center) 垂直对齐变得更容易,以防您的项目高度不同并且需要对齐
    • 我喜欢这个解决方案以及使用网格解决这个问题的想法,但我认为您的解决方案有一些明显的缺点。首先,如果任何一个外部单元格的内容大于 20%,则内容要么换行,要么溢出到中心单元格。其次,如果中心大于 60%,它将增长到其内容框之外,并包裹或推出最后一个单元格。最后,中心不会移动以为外部细胞腾出空间。它只是迫使他们换行/溢出。这不是一个糟糕的解决方案,但 IMO,它不是“显然是最干净的选择”。
    【解决方案5】:

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

    .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%);
    }
    
    

    codepen:https://codepen.io/ErAz7/pen/mdeBKLG

    【讨论】:

      【解决方案6】:

      这是一个使用网格而不是 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>

      【讨论】:

      • 这行得通。我将&lt;section&gt; 标记更改为&lt;div class="alignThreeColumn"&gt; 并使用CSS 文件中的类名而不是.section 标记名。
      【解决方案7】:

      这是另一种方法,在父母和孩子中使用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>

      【讨论】:

        【解决方案8】:

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

        非常简单,只需将要居中的组件用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>

        【讨论】:

          【解决方案9】:

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

          .parent {
              display: flex;
              justify-content: space-between;
          }
          
          .left, .right {
             flex-grow: 1;
             flex-basis: 0;
          }
          

          CodePen 可用here

          【讨论】:

          • 这个答案效果很好,并为小屏幕包装了容器的孩子。
          • 这是迄今为止最简单和最可行的答案......
          • 我必须同意以前的 cmets。迄今为止最简单可行的解决方案。
          【解决方案10】:

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

          .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

          【讨论】:

            【解决方案11】:

            我想要问题中显示的确切结果,我结合了 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;
            }
            

            【讨论】:

              猜你喜欢
              • 2015-11-29
              • 1970-01-01
              • 2017-11-07
              • 2013-12-24
              • 1970-01-01
              • 2018-09-04
              • 2018-03-07
              • 1970-01-01
              相关资源
              最近更新 更多