Ниже приведены пять вариантов достижения этой схемы:
- CSS Позиционирование
- Flexbox с невидимым элементом DOM
- Flexbox с невидимым псевдоэлементом
- Flexbox с
flex: 1
- CSS Grid Layout
Метод # 1: свойства позиционирования CSS
Применить position: relative
к гибкому контейнеру.
Применить 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>
Одно предостережение в отношении этого метода заключается в том, что некоторые браузеры могут не полностью удалить абсолютно позиционированный гибкий элемент из обычного потока. Это изменяет выравнивание нестандартным, неожиданным образом. Подробнее: Абсолютно позиционированный гибкий элемент не удаляется из обычного потока в IE11.
Метод # 2: гибкие автоматические поля и невидимый гибкий элемент (элемент DOM)
Макет может быть достигнут с помощью комбинации auto
полей и нового невидимого гибкого элемента.
Новый гибкий элемент идентичен элементу D и размещается на противоположном конце (левый край).
В частности, поскольку гибкое выравнивание основано на распределении свободного пространства, новый элемент является необходимым противовесом для сохранения горизонтального центрирования трех средних прямоугольников. Новый элемент должен иметь ту же ширину, что и существующий элемент D, иначе средние поля не будут точно центрированы.
Новый элемент удаляется из просмотра с помощью visibility: hidden
.
Коротко:
- Создайте дубликат
D
элемента.
- Поместите его в начало списка.
- Использование гибкого
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
к отдельным элементам, чтобы выровнять их содержимое.
ПРИМЕЧАНИЕ об использовании этого метода с min-height
: В настоящее время в Chrome, Firefox, Edge и, возможно, других браузерах сокращенное правилоflex: 1
сводится к следующему:
flex-grow: 1
flex-shrink: 1
flex-basis: 0%
Этот процент единица (%) по flex-basis
причинам этот метод , чтобы сломать , когда min-height
используется на контейнере. Это связано с тем, что, как правило, процентная высота дочерних элементов требует явной height
настройки свойства родительского элемента.
Это старое правило CSS, датируемое 1998 годом ( уровень CSS 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
Это может быть самый чистый и эффективный метод. Нет необходимости в абсолютном позиционировании, фальшивых элементах или другом взломе.
Просто создайте сетку из нескольких столбцов. Затем разместите свои предметы в средних и конечных столбцах. Как правило, просто оставьте первый столбец пустым.
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>