在元素的一部分上居中 Flexbox

Posted

技术标签:

【中文标题】在元素的一部分上居中 Flexbox【英文标题】:Center Flexbox on Part of Element 【发布时间】:2019-08-22 08:13:36 【问题描述】:

我正在尝试使用 flexbox 将两个元素沿下图所示的蓝线垂直居中。

问题是第二个框和文本是一个 div 的一部分,而 flexbox 想要像这样对齐它们:

通过使 div position: relative 和文本 position: absolute 我能够实现我的目标,除了这会导致整个容器在计算容器高度时排除文本:

如何在允许容器具有容器中所有内容的高度的同时正确居中这些元素?

期望的结果:

问题示例:(虽然框居中,但容器不包含文本,如蓝色边框所示。)

.container 
  display: flex;
  align-items: center;
  padding: 10px;
  border: 4px solid #00aaff;


.big-box 
  width: 200px;
  height: 100px;
  margin-right: 20px;
  padding: 10px;
  border: 4px solid black;


.small-box 
  width: 150px;
  height: 50px;
  padding: 10px;
  border: 4px solid black;


.group 
  position: relative;


.group p 
  position: absolute;
  margin-top: 20px;
<div class="container">
  <div class="big-box">
    Lots of content...
  </div>

  <div class="group">
    <div class="small-box">
      Some content...
    </div>

    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
  </div>
</div>

【问题讨论】:

我理解你是否正确理解你基本上希望右列(下面有短框和文本)从蓝色框的顶部垂直偏移,同时也导致蓝色框包裹所有包含的内容? 盒子里有内容吗? @MitchTalmadge 你能把你的代码放入sn-p吗? @DacreDenny 不仅仅是偏移,我希望短框与大框完美居中。当文本不存在时效果很好,但是添加文本会导致小框向上移动,以便小框+文本与大框居中。 您可能想切换到网格布局? 【参考方案1】:

我希望这是您正在寻找的解决方案

$(window).on('resize load', function()
  var coll = $('.big-box').height();
  var sheight = $('.small-box').height();
  var calci = (coll - sheight)/2;
  $('.small-box').css('margin-top':calci);
);
.container 
  padding: 10px;
  border: 4px solid #00aaff;
  position:relative;
  height:auto;
  display:inline-block;
  width:100%;

.big-box
  display:inline-block;
  width:49%;
  border:2px solid #000;
  float:left;
  height:200px;
  box-sizing:border-box;

.right-div
  display:inline-block;
  width:calc(100% - 49% - 20px);
  float:left;
  margin-left:20px;
  box-sizing:border-box;

.small-box
  border:2px solid #000;
  height:50px;
 
  
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
      <div class="big-box">
        Lots of content...
      </div>
      <div class="right-div">
        <div class="small-box">
            Some content...
        </div>
        <div class="group1">
                <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
        </div>
      </div>
</div>

【讨论】:

谢谢,但这是以框和文本组合为中心,而不仅仅是框。两个黑盒子中较小的一个应该与较大的盒子完全居中。我在帖子中添加了另一张图片以帮助澄清。 "big box" 高度设为 200 像素,您会发现它不起作用。文本会被左边的框而不是右边的框下推,这不是要求的。 哦,谢谢你指出@LGson。我假设高度将被固定为“大盒子”。但是,我已经相应地更新了我的答案。【参考方案2】:

我只找到了一个使用 javascript 和网格的解决方案。 原则上 JS 也应该和 flex 一起工作,但是我从 grid 开始,因为我认为从 flex 开始是不可能的。


  // define some vars local to this block
  // CSS selectors for the containers
  const containerSelector = '.container';
  const leftSelector = '.left-box';
  const rightSelector = '.right-box';

  // this function will recalculate the height of two grid boxes
  const recalc = () => 
    const containers = document.querySelectorAll(containerSelector);
    for (let container of containers) 
      const l = container.querySelector(`:scope > $leftSelector > *`).offsetHeight
      const r = container.querySelector(`:scope > $rightSelector > *`).offsetHeight
      const gap = parseInt(window.getComputedStyle(container).gridRowGap)
      // +-----+  +-----+
      // |     |  |  c  |
      // |     |  +-----+  ------.
      // |     |                  -- gap
      // |     |  +-----+  ------´
      // |  l  |  |  r  | 
      // |     |  +-----+  ------.
      // |     |                  -- gap
      // |     |  +-----+  --.---´ 
      // |     |  |  c  |     
      // +-----+  +- - -|     ------ text
      //          |     |     
      //          +-----+  --´
      // l = c + gap + r + gap + c
      // l = 2 * c + 2 * gap + r
      // l - r - 2 * gap = 2 * c
      const c = (l - r - 2 * gap) / 2
      container.style.gridTemplateRows = `$cpx auto $cpx auto`
    
  

  window.addEventListener('resize', recalc);
  window.addEventListener('load', recalc);
  recalc();
.container 
  align-content: left;
  border: 1px solid gold;
  width: 50%;
  margin: auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr auto 1fr auto;
  grid-auto-rows: auto;
  grid-gap: 1rem 50px;
  padding: 25px;
  grid-template-areas: "leftbox b" "leftbox rightbox" "leftbox mytextbox" "a mytextbox";


.container .left-box 
  grid-area: leftbox;
  background-color: green;


.container .right-box 
  grid-area: rightbox;
  background-color: orange;


.container .text-box 
  grid-area: mytextbox;
  background-color: yellow;


.container figure 
  border: 1px solid;
  margin: 0;


.container figure img 
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
<div class="container">
  <div class="left-box">
    <figure>
      <img src="http://picsum.photos/225/300?image=990" >
      <figcaption>Figure 1</figcaption>
    </figure>
  </div>
  <div class="right-box">
    <figure>
      <img src="http://picsum.photos/225/100?image=991" >
      <figcaption>Figure 2</figcaption>

    </figure>
  </div>
  <div class="text-box">Lorem ipsum dolor sit amet consectetur adipisicing elit. Est, cum porro quod unde neque doloribus excepturi odio nobis necessitatibus, nostrum labore id. Dolorem facere, quia nihil similique quis consectetur earum repudiandae non ut aperiam, dolore
    cum, corporis ratione quaerat temporibus.<br> Lorem ipsum dolor sit, amet consectetur adipisicing elit. Corrupti quam impedit perspiciatis sit nulla officiis in, delectus adipisci aliquam dolores, ratione voluptates dolorem odio ab ducimus praesentium
    omnis! Unde, at?<br>
  </div>
</div>

如果没有 JS 部分,左框会太大,因为 1fr 单元太贪心(或auto 行太勉强)。

.container 
  align-content: left;
  border: 1px solid gold;
  width: 50%;
  margin: auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr auto 1fr auto;
  grid-auto-rows: auto;
  grid-gap: 1rem 50px;
  padding: 25px;
  grid-template-areas: "leftbox b" "leftbox rightbox" "leftbox mytextbox" "a mytextbox";

.container .left-box 
  grid-area: leftbox;
  background-color: green;

.container .right-box 
  grid-area: rightbox;
  background-color: orange;

.container .text-box 
  grid-area: mytextbox;
  background-color: yellow;

.container figure 
  border: 1px solid;
  margin: 0;

.container figure img 
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
<div class="container">
  <div class="left-box">
    <figure>
      <img src="http://picsum.photos/225/300?image=990" >
      <figcaption>Figure 1</figcaption>
    </figure>
  </div>
  <div class="right-box">
    <figure>
      <img src="http://picsum.photos/225/100?image=991" >
      <figcaption>Figure 2</figcaption>

    </figure>
  </div>
  <div class="text-box">
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Est, cum porro quod unde neque doloribus excepturi odio nobis necessitatibus, nostrum labore id. Dolorem facere, quia nihil similique quis consectetur earum repudiandae non ut aperiam, dolore cum, corporis ratione quaerat temporibus.<br> Lorem ipsum dolor sit, amet consectetur adipisicing elit. Corrupti quam impedit perspiciatis sit nulla officiis in, delectus adipisci aliquam dolores, ratione voluptates dolorem odio ab ducimus praesentium omnis! Unde, at?<br>
  Lorem ipsum dolor sit amet consectetur adipisicing elit. Est, cum porro quod unde neque doloribus excepturi odio nobis necessitatibus, nostrum labore id. Dolorem facere, quia nihil similique quis consectetur earum repudiandae non ut aperiam, dolore cum, corporis ratione quaerat temporibus.<br> Lorem ipsum dolor sit, amet consectetur adipisicing elit. Corrupti quam impedit perspiciatis sit nulla officiis in, delectus adipisci aliquam dolores, ratione voluptates dolorem odio ab ducimus praesentium omnis! Unde, at?<br>
  </div>
</div>

我也创建了flex 版本

console.clear()

  const containerSelector = '.container';
  const leftColSelector = '.left-col';
  const rightColSelector = '.right-col';
  const leftSelector = '.left-box';
  const rightSelector = '.right-box';
  const rightSpacerSelector = '.right-spacer';

  const recalc = () => 
    const containers = document.querySelectorAll(containerSelector);
    for (let container of containers) 
      const l = container.querySelector(`:scope > $leftColSelector > $leftSelector > *`).offsetHeight;
      const r = container.querySelector(`:scope > $rightColSelector > $rightSelector > *`).offsetHeight;
      const s = container.querySelector(`:scope > $rightColSelector > $rightSpacerSelector`)
      const c = (l - r) / 2
      s.style.height = `$cpx`;
      // container.style.gridTemplateRows = `$cpx auto $cpx auto`
    
  

  window.addEventListener('resize', recalc);
  window.addEventListener('load', recalc);
  recalc();
.container 
  border: 1px solid gold;
  width: 50%;
  margin: auto;
  display: flex;
  flex-wrap: flex;
  padding: 25px;

.container .left-col,
.container .right-col 
  width: calc(50% - 25px);

.container .left-col 
  margin-right: 25px;

.container .right-col 
  margin-left: 25px;

.container .left-box 
  background-color: green;

.container .right-box 
  background-color: orange;

.container .text-box 
  background-color: yellow;

.container figure 
  border: 1px solid;
  margin: 0;

.container figure img 
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
<div class="container">
  <div class="left-col">
    <div class="left-box">
      <figure>
        <img src="http://picsum.photos/225/300?image=990" >
        <figcaption>Figure 1</figcaption>
      </figure>
    </div>
  </div>
  <div class="right-col">
    <div class="right-spacer"></div>
    <div class="right-box">
      <figure>
        <img src="http://picsum.photos/225/100?image=991" >
        <figcaption>Figure 2</figcaption>

      </figure>
    </div>
    <div class="text-box">Lorem ipsum dolor sit amet consectetur adipisicing elit. Est, cum porro quod unde neque doloribus excepturi odio nobis necessitatibus, nostrum labore id. Dolorem facere, quia nihil similique quis consectetur earum repudiandae non ut aperiam, dolore
      cum, corporis ratione quaerat temporibus.<br> Lorem ipsum dolor sit, amet consectetur adipisicing elit. Corrupti quam impedit perspiciatis sit nulla officiis in, delectus adipisci aliquam dolores, ratione voluptates dolorem odio ab ducimus praesentium
      omnis! Unde, at?<br>
    </div>

  </div>
</div>

【讨论】:

以上是关于在元素的一部分上居中 Flexbox的主要内容,如果未能解决你的问题,请参考以下文章

如何在Bootstrap中垂直居中未知高度的浮动元素?

难以垂直居中h1元素和输入元素

如何使元素居中

布局中常见的居中问题

使用“位置:粘性”将元素始终显示在屏幕上

Flexbox布局