Центр Flexbox на части элемента - PullRequest
7 голосов
/ 01 апреля 2019

Я пытаюсь использовать flexbox для вертикального центрирования двух элементов вдоль синей линии, показанной на рисунке ниже.

Example 1

Проблема в том, что второе поле и текст являются частью одного div, и flexbox хочет выровнять их следующим образом:

Example 2

Делая div position: relative и текст position: absolute, я могу достичь своей цели, за исключением того, что из-за этого весь контейнер исключает текст при расчете высоты контейнера:

Example 3

Как правильно отцентрировать эти элементы, при этом позволяя контейнеру иметь высоту всего содержимого в контейнере?

Желаемый результат:

Desired Result

Пример проблемы: (Хотя поля расположены по центру, контейнер не содержит текст, как показано синей рамкой.)

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

Ответы [ 2 ]

6 голосов
/ 01 апреля 2019

Я нашел только решение, которое использует 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 = `${c}px auto ${c}px 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" alt="">
      <figcaption>Figure 1</figcaption>
    </figure>
  </div>
  <div class="right-box">
    <figure>
      <img src="http://picsum.photos/225/100?image=991" alt="">
      <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" alt="">
      <figcaption>Figure 1</figcaption>
    </figure>
  </div>
  <div class="right-box">
    <figure>
      <img src="http://picsum.photos/225/100?image=991" alt="">
      <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 = `${c}px`;
      // container.style.gridTemplateRows = `${c}px auto ${c}px 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" alt="">
        <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" alt="">
        <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>
4 голосов
/ 01 апреля 2019

Я надеюсь, что это решение, которое вы ищете

$(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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...