Flex-элементы по центру и выравниванию по нижнему краю

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

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

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

введите здесь описание изображения

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


person Willege    schedule 24.03.2016    source источник


Ответы (3)


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

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

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

Примените position: relative к гибкому контейнеру.

Примените 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-элемент с абсолютным позиционированием из обычного потока. Это меняет расклад нестандартным, неожиданным образом. Дополнительные сведения: Абсолютно позиционированный гибкий элемент не удаляется из обычного потока в Firefox и IE11


Метод № 2: автоматические поля Flex и невидимый элемент Flex (элемент DOM)

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

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

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

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

Короче говоря:

  • Создайте дубликат зеленого прямоугольника.
  • Поместите его в начало списка.
  • Используйте гибкие поля 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 и невидимый элемент Flex (псевдоэлемент)

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

  • Создайте псевдоэлемент той же высоты, что и существующий зеленый прямоугольник.
  • Поместите его в начало контейнера с помощью ::before.
  • Используйте гибкие поля 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-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>

person Michael Benjamin    schedule 24.03.2016

пусть контейнер с 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>

person Le____    schedule 24.03.2016

вы можете использовать псевдо для перемещения вниз на одну строку первых трех контейнеров, а затем применить 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>

person G-Cyrillus    schedule 24.03.2016