it-roy-ru.com

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

Я бы хотел, чтобы AB и C были выровнены посередине.

Как я могу заставить D полностью повернуть направо?

ДО:

 enter image description here

ПОСЛЕ:

 enter image description here

Какая лучшая практика для этого?

ul {
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
li {
  display: flex;
  margin: 1px;
  padding: 5px;
  background: #aaa;
}
li:last-child {
  background: #ddd;
  /* magic to throw to the right*/
}
<ul>
  <li>A</li>
  <li>B</li>
  <li>C</li>
  <li>D</li>
</ul>

https://jsfiddle.net/z44p7bsx/

62
hazyred

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

  • CSS Позиционирование 
  • Flexbox с невидимым элементом DOM
  • Flexbox с невидимым псевдоэлементом
  • Flexbox с flex: 1
  • CSS Grid Layout

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

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

Применить position: absolute к пункту D.

Теперь этот элемент абсолютно позиционируется внутри гибкого контейнера.

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

Используйте свойства смещения CSS top и right, чтобы переместить этот элемент в позицию.

li:last-child {
  position: absolute;
  top: 0;
  right: 0;
  background: #ddd;
}
ul {
  position: relative;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
li {
  display: flex;
  margin: 1px;
  padding: 5px;
  background: #aaa;
}
p {
  text-align: center;
  margin-top: 0;
}
span {
  background-color: aqua;
}
<ul>
  <li>A</li>
  <li>B</li>
  <li>C</li>
  <li>D</li>
</ul>
<p><span>true center</span></p>

Одно предостережение этот метод заключается в том, что некоторые браузеры не могут полностью удалить абсолютно позиционированный элемент Flex из обычного потока. Это меняет выравнивание нестандартным, неожиданным способом. Подробнее: Абсолютно позиционированный гибкий элемент не удаляется из нормального потока в IE11


Метод № 2: Сгибание авто полей и невидимый изгиб (элемент DOM)

С помощью комбинации auto поля и нового невидимого гибкого элемента можно получить макет.

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

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

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

Короче:

  • Создайте дубликат элемента D.
  • Поместите это в начало списка.
  • Используйте поля flex auto для сохранения центрирования A, B и C, при этом оба элемента D создают равный баланс с обеих сторон.
  • Применить visibility: hidden к дубликату D

li:first-child {
  margin-right: auto;
  visibility: hidden;
}
li:last-child {
  margin-left: auto;
  background: #ddd;
}
ul {
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
li {
  display: flex;
  margin: 1px;
  padding: 5px;
  background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
  <li>D</li><!-- new; invisible spacer item -->
  <li>A</li>
  <li>B</li>
  <li>C</li>
  <li>D</li>
</ul>
<p><span>true center</span></p>


Метод № 3: Сгибание авто полей и невидимый изгиб (псевдоэлемент)

Этот метод похож на # 2, за исключением того, что он более чистый семантически, и ширина D должна быть известна.

  • Создайте псевдоэлемент с той же шириной, что и D.
  • Поместите его в начало контейнера с помощью ::before.
  • Используйте гибкие поля auto, чтобы A, B и C были идеально отцентрированы, а элементы псевдо и D создают равный баланс с обоих концов.

ul::before {
  content:"D";
  margin: 1px auto 1px 1px;
  visibility: hidden;
  padding: 5px;
  background: #ddd;
}
li:last-child {
  margin-left: auto;
  background: #ddd;
}
ul {
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
}
li {
  display: flex;
  margin: 1px;
  padding: 5px;
  background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
  <li>A</li>
  <li>B</li>
  <li>C</li>
  <li>D</li>
</ul>
<p><span>true center</span></p>


Способ № 4: Добавить flex: 1 к левому и правому элементам

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

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

NOTEоб использовании этого метода с min-height: В настоящее время в Chrome, Firefox, Edge и, возможно, в других браузерах правило сокращения flex: 1 разбивается на следующее:

  • flex-grow: 1
  • flex-shrink: 1
  • flex-basis: 0%

То, что процентная единица (%) в flex-basis вызывает сбой этого метода при использовании min-height в контейнере. Это связано с тем, что, как правило, процентная высота дочерних элементов требует явной установки свойства height родительского элемента.

Это старое правило CSS, появившееся в 1998 году ( CSS Level 2 ), которое до сих пор действует во многих браузерах в той или иной степени. Для получения полной информации см. здесь и здесь .

Вот иллюстрация проблемы, размещенной в комментариях пользователя user2651804 :

#flex-container {
  display: flex;
  flex-direction: column;
  background: teal;
  width: 150px;
  min-height: 80vh;
  justify-content: space-between;
}

#flex-container>div {
  background: orange;
  margin: 5px;
}

#flex-container>div:first-child {
  flex: 1;
}

#flex-container::after {
  content: "";
  flex: 1;
}
<div id="flex-container">
  <div>very long annoying text that will add on top of the height of its parent</div>
  <div>center</div>
</div>

Решение состоит в том, чтобы не использовать процентную единицу. Попробуйте px или просто вообще ничего ( это то, что на самом деле рекомендует спецификация , несмотря на тот факт, что по крайней мере некоторые из основных браузеров добавили процентную единицу по любой причине).

#flex-container {
  display: flex;
  flex-direction: column;
  background: teal;
  width: 150px;
  min-height: 80vh;
  justify-content: space-between;
}

#flex-container > div {
  background: orange;
  margin: 5px;
}


/* OVERRIDE THE BROWSER SETTING IN THE FLEX PROPERTY */

#flex-container > div:first-child {
  flex: 1;
  flex-basis: 0;
}

#flex-container::after {
  content: "";
  flex: 1;
  flex-basis: 0;
}


/* OR... JUST SET THE LONG-HAND PROPERTIES INDIVIDUALLY

#flex-container > div:first-child {
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0;
}

#flex-container::after {
  content: "";
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: 0;
}
 */
<div id="flex-container">
  <div>very long annoying text that will add on top of the height of its parent</div>
  <div>center</div>
</div>


Метод № 5: CSS Grid Layout

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

Просто создайте сетку с несколькими столбцами. Затем поместите ваши предметы в средний и конечный столбцы. По сути, просто оставьте первый столбец пустым.

ul {
  display: grid;
  grid-template-columns: 1fr repeat(3, auto) 1fr;
  grid-column-gap: 5px;
  justify-items: center;
}

li:nth-child(1) { grid-column-start: 2; }
li:nth-child(4) { margin-left: auto; }

/* for demo only */
ul { padding: 0; margin: 0; list-style: none; }
li { padding: 5px; background: #aaa; }
p  { text-align: center; }
<ul>
  <li>A</li>
  <li>B</li>
  <li>C</li>
  <li>D</li>
</ul>
<p><span>| true center |</span></p>

107
Michael_B

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

.parent {
  display: flex;
  justify-content: flex-end;
}

.center {
  margin: auto;
}

http://codepen.io/rgfx/pen/BLorgd

3
rgfx

Я расширил Michael_B 's ответ

.center-flex__2-of-3 > :nth-child(1), .center-flex__2-of-3 > :nth-child(3) {
  flex: 1;
}
.center-flex__2-of-3 > :nth-child(1) {
  justify-content: flex-start;
}
.center-flex__2-of-3 > :nth-child(3) {
  justify-content: flex-end;
}
.center-flex__1-of-2 > :nth-child(1) {
  margin: auto;
}
.center-flex__1-of-2 > :nth-child(2) {
  flex: 1;
  justify-content: flex-end;
}
.center-flex__2-of-2 > :nth-child(1) {
  flex: 1;
  justify-content: flex-start;
}
.center-flex__2-of-2 > :nth-child(2) {
  margin: auto;
}
.center-flex__1-of-2:before, .center-flex__1-of-1:before {
  content: '';
  flex: 1;
}
.center-flex__1-of-1:after, .center-flex__2-of-2:after {
  content: '';
  flex: 1;
}

[class*=center-flex] {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  border: 10px solid rgba(0, 0, 0, 0.1);
}
[class*=center-flex] > * {
  display: flex;
}
li {
  padding: 3px 5px;
}
2 of 3
<ul class="center-flex__2-of-3">
  <span>
    <li>Accusamus</li>
    <li>Porro</li>
  </span>
  <span>
    <li>Lorem</li>
    <li>Dolor</li>
  </span>
  <span>
    <li>Porro</li>
    <li>Culpa</li>
    <li>Sit</li>
  </span>
</ul>

<br><br>
1 of 2
<ul class="akex center-flex__1-of-2">
  <span>
    <li>Lorem</li>
    <li>Dolor</li>
  </span>
  <span>
    <li>Porro</li>
    <li>Culpa</li>
    <li>Sit</li>
  </span>
</ul>

<br><br>
2 of 2
<ul class="akex center-flex__2-of-2">
  <span>
    <li>Porro</li>
    <li>Culpa</li>
    <li>Sit</li>
  </span>
  <span>
    <li>Lorem</li>
    <li>Dolor</li>
  </span>
</ul>

<br><br>
1 of 1
<ul class="center-flex__1-of-1">
  <span>
    <li>Lorem</li>
    <li>Dolor</li>
  </span>
</ul>

Здесь с помощью SASS в качестве кодовой ручки

0
yunzen