Разбивка гибкого поля на части элемента

#html #css #flexbox #css-grid

#HTML #css #гибкий блок #css-сетка

Вопрос:

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

Пример 1

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

Пример 2

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

Пример 3

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

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

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

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

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

Комментарии:

1. правильно ли я понимаю, что вы в основном хотите, чтобы правый столбец (с коротким полем и текстом внизу) был смещен по вертикали от верхней части синего поля, в то же время заставляя синее поле переносить все содержащееся содержимое?

2. Есть ли какое-либо содержимое в блоках?

3. @MitchTalmadge не могли бы вы поместить свой код во фрагмент, пожалуйста?

4. @DacreDenny Больше, чем смещение, я бы хотел, чтобы короткий блок был идеально центрирован с большим блоком. Это отлично работает, когда текст не существует, но добавление текста приводит к смещению маленького поля вверх, так что маленькое поле текст центрируются с большим полем.

5. Возможно, вы захотите переключиться на макет сетки?

Ответ №1:

Я только нашел решение, которое использует JavaScript и grid. В принципе, 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>  

Ответ №2:

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

 $(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>  

Комментарии:

1. Спасибо, но это центрирование на поле и тексте вместе взятых, а не только на поле. Меньший из двух черных ящиков должен быть точно центрирован с большим полем. Я добавил еще одну картинку к своему сообщению, чтобы прояснить ситуацию.

2. Сделайте «большую коробку» высотой 200 пикселей, и вы увидите, что это не сработает. Текст будет смещен вниз левым полем вместо правого, что не соответствует заданному.

3. Ооо, спасибо, что указали на это @LGSon. Я предположил, что высота будет фиксированной для «big-box». Тем не менее, я соответствующим образом обновил свой ответ.