Выравнивание по центру и дну элементов flex

у меня есть контейнер (синий квадрат) со следующими свойствами:

display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;

поэтому его дети (светло-синие квадраты) устраиваются так, как вы видите ниже. Однако я хотел бы добавить еще одного ребенка (зеленый квадрат) из нормального потока и расположить его относительно своего родителя. Как вы видите ниже, я бы в идеале написать что-то вроде bottom: 20px; и margin: auto;.

enter image description here

Я пытался играть с z-index безрезультатно. Как мне подойти к этому? Должен ли я прибегнуть к созданию другого родительского элемента?

3 ответов


Ниже приведены пять вариантов достижения этого макета:

  1. позиционирование CSS
  2. Flexbox с невидимым элементом DOM
  3. Flexbox с невидимым псевдо-элементом
  4. Flexbox с flex: 1
  5. CSS Grid Layout

метод #1: свойства позиционирования CSS

применить position: relative к контейнеру flex.

применить position: absolute на зеленый шлейф пункт.

теперь зеленый квадрат абсолютно помещенный в контейнер.

более конкретно, зеленый квадрат удаляется из потока документа, но остается в пределах ближайший предок, расположенный.

используйте свойства смещения CSS top, bottom, left и right, чтобы переместить зеленый квадрат вокруг.

flex-container {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: nowrap;
  position: relative;
  border: 4px solid blue;
  height: 300px;
  width: 300px;
}
flex-container > flex-item:first-child {
  display: flex;
}
flex-container > flex-item:first-child > flex-item {
  border: 4px solid aqua;
  height: 50px;
  width: 50px;
  margin: 0 5px;
}
flex-container > flex-item:last-child {
  position: absolute;
  bottom: 40px;
  left: 50%;
  transform: translateX(-50%); /* fine tune horizontal centering */
  border: 4px solid chartreuse;
  height: 50px;
  width: 50px;
}
<flex-container>
    <flex-item><!-- also flex container -->
	    <flex-item></flex-item>
	    <flex-item></flex-item>
	    <flex-item></flex-item>
    </flex-item>
    <flex-item></flex-item>
</flex-container>

один предостережение: некоторые браузеры не могут полностью удалить абсолютно расположенный элемент flex из нормального потока. Это изменяет выравнивание нестандартным, неожиданным образом. Более детально: абсолютно позиционированный элемент flex не удаляется из нормального потока в Firefox & IE11


Метод #2: Flex Auto Margins & невидимый элемент Flex (элемент DOM)

с совмещением auto поля и новый, невидимый деталь гибкого трубопровода план можно достигнуть.

новый элемент flex идентичен нижнему элементу и помещается на противоположном конце (вверху).

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

новый элемент удаляется из поля зрения с visibility: hidden.

короче:

  • создайте дубликат зеленого ящика.
  • поместите его в начале списка.
  • использовать flex auto поля, чтобы держать синие ящики по центру, с обоих зеленых ящиков создания равного баланса с обоих концов.
  • применить visibility: hidden к дубликату зеленого цвета коробка.

flex-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    border: 4px solid blue;
    height: 300px;
    width: 300px;
}
flex-container > flex-item:first-child {
    margin-top: auto;
    visibility: hidden;
}
flex-container > flex-item:nth-child(2) {
    margin-top: auto;
    display: flex;
}
flex-container > flex-item:last-child {
    margin-top: auto;
    margin-bottom: auto;
}
flex-container > flex-item:first-child,
flex-container > flex-item:last-child {
    border: 4px solid chartreuse;
    height: 50px;
    width: 50px;
}
flex-container > flex-item:nth-child(2) > flex-item {
    border: 4px solid aqua;
    height: 50px;
    width: 50px;
    margin: 0 5px;
}
<flex-container>
    <flex-item></flex-item>
    <flex-item><!-- also flex container -->
	    <flex-item></flex-item>
	    <flex-item></flex-item>
	    <flex-item></flex-item>
    </flex-item>
    <flex-item></flex-item>
</flex-container>

Метод #3: Flex Auto Margins & невидимый элемент Flex (псевдо-элемент)

этот метод похож на #2, за исключением того, что он чище семантически, и высота зеленого ящика должна быть известна.

  • создайте псевдо-элемент с той же высотой, что и существующее зеленое поле.
  • поместите его в начале контейнера с ::before.
  • использовать flex auto поля, чтобы держать синие поля по центру, с зелеными элементами псевдо и DOM, создающими равный баланс с обоих концов.

flex-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    border: 4px solid blue;
    height: 300px;
    width: 300px;
}
flex-container::before {
  content: "";
  margin-top: auto;
  height: calc(50px + 8px);  /* height + borders */
  visibility: hidden;
}
flex-container > flex-item:first-child {
  margin-top: auto;
  display: flex;
}
flex-container > flex-item:last-child {
  margin-top: auto;
  margin-bottom: auto;
  border: 4px solid chartreuse;
  height: 50px;
  width: 50px;
}
flex-container > flex-item:first-child > flex-item {
  border: 4px solid aqua;
  height: 50px;
  width: 50px;
  margin: 0 5px;
}
<flex-container>
    <flex-item><!-- also flex container -->
        <flex-item></flex-item>
	    <flex-item></flex-item>
	    <flex-item></flex-item>
    </flex-item>
    <flex-item></flex-item>
</flex-container>

Метод #4: Добавить flex: 1 для верхнего и нижнего пунктов

начиная с Метода #2 или #3 выше, вместо того, чтобы беспокоиться о равной высоте для верхних и нижних элементов для поддержания равного баланса, просто дайте каждому flex: 1. Это заставит их обоих потреблять доступное пространство, таким образом центрируя средний деталь.

вы можете добавить display: flex к нижнему элементу, чтобы выровнять содержимое.


Метод #5: CSS Grid Layout

это может быть самый чистый и наиболее эффективный метод. Нет необходимости в абсолютном позиционировании, поддельных элементах или другом хакерстве.

просто создайте сетку с тремя строками. Затем выровняйте по центру элементы во второй и третьей строках. Первая строка может остаться пустой.

grid-container {
  display: grid;
  grid-template-rows: repeat(3, 1fr);
  align-items: center;
  justify-items: center;
  border: 4px solid blue;
  height: 300px;
  width: 300px;
}

grid-item:nth-child(2) {
  display: flex;
}

grid-item:nth-child(2)>flex-item {
  width: 50px;
  height: 50px;
  margin: 0 5px;
  border: 4px solid aqua;
}

grid-item:nth-child(3) {
  border: 4px solid chartreuse;
  height: 50px;
  width: 50px;
}
<grid-container>
  <grid-item></grid-item>
  <grid-item><!-- also flex container -->
    <flex-item></flex-item>
    <flex-item></flex-item>
    <flex-item></flex-item>
  </grid-item>
  <grid-item></grid-item>
</grid-container>

пусть контейнер с position: relative и зеленый квадрат с position:absolute;

body {
  margin: 0;  
}

#container {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: nowrap;
  width: 192px;
  height: 192px;
  border: 4px solid indigo;
  position: relative;
  background: lavender;
}

.blue {
  margin: 10px;
  width: 30px;
  height: 30px;
  outline: 4px solid skyblue;
  background: honeydew;
}

#green {
  position: absolute;
  width: 30px;
  height: 30px;
  left: 0;
  right: 0;
  margin: auto;
  bottom: 20px;
  outline: 4px solid yellowgreen;
  background: greenyellow;
}
<div id=container>
<div class=blue></div><div class=blue></div><div class=blue></div>
<div id=green></div>
</div>

вы можете использовать псевдо для перемещения по одной строке первых трех контейнеров, а затем применить margin:auto до последнего

div {
  display:flex;
  flex-wrap:wrap;
  border:#0066FD solid;;
  width:200px;
  height:200px;
  justify-content:space-around;
  /* show me box center */
  background:linear-gradient(to top,rgba(0,0,0,0.2) 50%, transparent 50%),linear-gradient(to left,rgba(0,0,0,0.2) 50%, transparent 50%)
 
}

span, div:before {
  width:50px;
  height:50px;
  border:solid #01CDFF;
  margin:0 auto 0;
}
span:last-of-type , div:before{
  margin: 12px auto;
  border:solid  #01FE43;
}
div:before {
  content:'';
  width:100%;
  border:none;
}

span {
   /* show me box center */
  background:linear-gradient(45deg,rgba(0,0,0,0.1) 50%, transparent 50%),linear-gradient(-45deg,rgba(0,0,0,0.1) 50%, transparent 50%)
  }
<div>
  <span></span>
  <span></span>
  <span></span>
  <span></span>
</div>