В CSS Flexbox, почему нет свойств «justify-items» и «justify-self»?

678

Рассмотрим основную ось и поперечную ось гибкого контейнера:

введите описание изображения здесь                                                                                                                                                    Источник: W3C

Для выравнивания гибких элементов вдоль главной оси есть одно свойство:

Для выравнивания изгибаемых элементов вдоль поперечной оси есть три свойства:

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

Тем не менее, эти направления могут быть легко взаимозаменяемы с flex-directionсобственностью.

/* main axis is horizontal, cross axis is vertical */
flex-direction: row;
flex-direction: row-reverse;

/* main axis is vertical, cross axis is horizontal */    
flex-direction: column;
flex-direction: column-reverse;

(Ось креста всегда перпендикулярна главной оси.)

Моя точка зрения при описании работы осей заключается в том, что в обоих направлениях нет ничего особенного. Главная ось, поперечная ось, они одинаковы по важности и flex-directionпозволяют легко переключаться назад и вперед.

Так почему же поперечная ось получает два дополнительных свойства выравнивания?

Почему align-contentи align-itemsобъединены в одно свойство для главной оси?

Почему главная ось не получает justify-selfсвойства?


Сценарии, где эти свойства будут полезны:

  • размещение гибкого элемента в углу гибкого контейнера
    #box3 { align-self: flex-end; justify-self: flex-end; }

  • сделать группу из flex-элементов align-right ( justify-content: flex-end), но первый элемент выровнять по левому краю ( justify-self: flex-start)

    Рассмотрим заголовок раздела с группой элементов навигации и логотипом. С justify-selfлоготипом можно было выровнять влево, в то время как навигационные элементы остаются далеко вправо, и все это плавно регулируется («сгибается») к разным размерам экрана.

  • в ряду из трех гибких элементов прикрепите средний элемент к центру контейнера ( justify-content: center) и выровняйте соседние элементы по краям контейнера ( justify-self: flex-startи justify-self: flex-end).

    Обратите внимание, что значения space-aroundи свойство space-betweenon justify-contentне будут держать средний элемент по центру контейнера, если смежные элементы имеют разную ширину.

версия jsFiddle


На момент написания этой статьи не упоминалось justify-selfни justify-itemsо спецификации Flexbox .

Однако в модуле выравнивания блоков CSS , который является незаконченным предложением W3C по созданию общего набора свойств выравнивания для использования во всех блочных моделях, есть следующее:

введите описание изображения здесь                                                                                                                                                    Источник: W3C

Вы заметите это justify-selfи justify-itemsрассматриваются ... но не для flexbox .


В заключение я повторю главный вопрос:

Почему отсутствуют свойства "justify-items" и "justify-self"?

Майкл Бенджамин
источник
4
Как вы ожидаете justify-selfработать на гибкий элемент? Предположим, у вас есть элементы a, b, c, d с дополнительным пространством для распределения вокруг них, а контейнер flex имеет их justify-content: space-between, поэтому они заканчиваются как | abcd |. Что бы это значило добавить, например, justify-self: centerили «justify-self: flex-end» просто к пункту «b» там? Где вы ожидаете, что это пойдет? (Я вижу некоторые демонстрации в одном из ответов здесь, но я не вижу четкого способа, как это будет работать в целом.)
Дхолберт,
(Альтернативно: предположим, что у нас есть justify-content: flex-start, поэтому в начале пункты переполнены, как | abcd |. Что бы вы ожидали от него, если вы поместите justify-self: [anything]туда элемент «b»?)
Дхолберт,
1
@dholbert, вы писали: как бы вы justify-selfработали с флексом? Я бы сказал, не так иначе, как autoполя уже работают на гибких элементах. Во втором примере justify-self: flex-endпункт d переместит его в дальний край. Это само по себе было бы отличной особенностью, которую autoуже могут делать поля. Я разместил ответ с демонстрацией.
Майкл Бенджамин
2
Я в основном вижу больше вариантов использования здесь, и варианты использования хороши - но хитрый момент заключается в том, как включить это в фактический способ, который justify-contentи justify-selfуказан, так, чтобы случаи с конфликтами (как сценарии, о которых я спрашивал) четко и разумно определены. Как я уже отмечал в своем ответе, {justify|align}-selfречь идет{justify|align}-self о выравнивании элементов в большем поле, размер которого не зависит от значения - и на главной оси такого блока нет, чтобы можно было выровнять гибкий элемент.
Дхольберт
1
RE "ничем не отличается от авто наценок" - я на самом деле спрашивал о том, как вы представляете justify-selfи как будете justify-contentвзаимодействовать в тех случаях, когда они конфликтуют (например, сценарии, которые я изложил). Автомобильные поля просто не взаимодействуют justify-contentвообще - они крадут все упаковочное пространство, прежде чем justify-contentполучить возможность его использовать. Таким образом, авто наценки не очень хороший аналог того, как это будет работать.
Дхолберт

Ответы:

1256

Методы выравнивания гибких элементов вдоль главной оси

Как указано в вопросе:

Для выравнивания гибких элементов вдоль главной оси есть одно свойство: justify-content

Чтобы выровнять нежесткие элементы вдоль поперечной оси есть три свойства: align-content, align-itemsиalign-self .

Затем возникает вопрос:

Почему нет justify-itemsиjustify-self свойств?

Один ответ может быть: потому что они не нужны.

Спецификация flexbox предоставляет два метода выравнивания элементов flex вдоль главной оси:

  1. Свойство justify-contentключевого слова и
  2. auto поля

обосновывать-контент

В justify-contentсовмещается собственности сгибать элементы вдоль главной оси гибкого контейнера.

Он применяется к гибкому контейнеру, но влияет только на гибкие элементы.

Есть пять вариантов выравнивания:

  • flex-start Гибкие элементы упакованы в начале линии.

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

  • flex-end Гибкие элементы упакованы в конце линии.

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

  • center Гибкие элементы упакованы по направлению к центру линии.

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

  • space-betweenЭлементы Flex расположены равномерно, первый элемент выровнен по одному краю контейнера, а последний элемент - по противоположному краю. Края , используемые первыми и последние пункты зависят flex-directionи режим записи ( ltrили rtl).

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

  • space-around~ То же самое, что и space-betweenс половинными пробелами на обоих концах.

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


Авто наценки

С autoполями , гибкие элементы могут быть отцентрированы, разнесены или упакованы в подгруппы.

В отличие от того justify-content, что применяется к гибкому контейнеру, autoполя относятся к гибким элементам.

Они работают, потребляя все свободное пространство в указанном направлении.


Выровняйте группу изгибаемых элементов справа, но первый элемент слева

Сценарий из вопроса:

  • сделать группу из flex-элементов align-right ( justify-content: flex-end), но первый элемент выровнять по левому краю ( justify-self: flex-start)

    Рассмотрим заголовок раздела с группой элементов навигации и логотипом. С justify-selfлоготипом можно было выровнять влево, в то время как навигационные элементы остаются далеко вправо, и все это плавно регулируется («сгибается») к разным размерам экрана.

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

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


Другие полезные сценарии:

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

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

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


Поместите гибкий элемент в угол

Сценарий из вопроса:

  • размещение гибкого элемента в углу .box { align-self: flex-end; justify-self: flex-end; }

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


Центрируйте гибкий элемент по вертикали и горизонтали

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

margin: autoявляется альтернативой justify-content: centerи align-items: center.

Вместо этого кода в контейнере flex:

.container {
    justify-content: center;
    align-items: center;
}

Вы можете использовать это на элементе flex:

.box56 {
    margin: auto;
}

Эта альтернатива полезна при центрировании гибкого элемента, который переполняет контейнер .


Отцентрируйте гибкий элемент и отцентрируйте второй гибкий элемент между первым и краем

Гибкий контейнер выравнивает гибкие элементы, распределяя свободное пространство.

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

В приведенных ниже примерах невидимые третьи гибкие элементы (вставки 61 и 68) представлены для уравновешивания «реальных» предметов (вставки 63 и 66).

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

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

Конечно, этот метод не является чем-то большим с точки зрения семантики.

В качестве альтернативы вы можете использовать псевдоэлемент вместо фактического элемента DOM. Или вы можете использовать абсолютное позиционирование. Здесь рассматриваются все три метода: гибкие элементы по центру и снизу.

ПРИМЕЧАНИЕ. Приведенные выше примеры будут работать - с точки зрения истинного центрирования - только когда самые внешние элементы равны высоте / ширине. Когда гибкие элементы имеют разную длину, см. Следующий пример.


Центрируйте гибкий элемент, когда соседние элементы различаются по размеру

Сценарий из вопроса:

  • в ряду из трех гибких элементов прикрепите средний элемент к центру контейнера ( justify-content: center) и выровняйте соседние элементы по краям контейнера ( justify-self: flex-startи justify-self: flex-end).

    Обратите внимание, что значения space-aroundи свойство space-betweenon justify-contentне будут сохранять средний элемент по центру относительно контейнера, если смежные элементы имеют разную ширину ( см. Демонстрацию ).

Как уже отмечалось, если все гибкие элементы не имеют одинаковую ширину или высоту (в зависимости от flex-direction), средний элемент не может быть действительно центрирован. Эта проблема дает веские основания для justify-selfсвойства (конечно, для решения задачи).

Вот два метода решения этой проблемы:

Решение № 1: Абсолютное позиционирование

Спецификация flexbox обеспечивает абсолютное позиционирование элементов flex . Это позволяет среднему предмету быть идеально отцентрированным независимо от размера его родных братьев.

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

В приведенных ниже примерах средний элемент центрируется с абсолютным позиционированием, а внешние элементы остаются в потоке. Но та же схема может быть достигнута и в обратном порядке: отцентрируйте средний элемент по центру justify-content: centerи расположите абсолютно все внешние элементы.

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

Решение № 2: Вложенные Flex-контейнеры (без абсолютного позиционирования)

.container {
  display: flex;
}
.box {
  flex: 1;
  display: flex;
  justify-content: center;
}
.box71 > span { margin-right: auto; }
.box73 > span { margin-left: auto;  }

/* non-essential */
.box {
  align-items: center;
  border: 1px solid #ccc;
  background-color: lightgreen;
  height: 40px;
}
<div class="container">
  <div class="box box71"><span>71 short</span></div>
  <div class="box box72"><span>72 centered</span></div>
  <div class="box box73"><span>73 loooooooooooooooong</span></div>
</div>

Вот как это работает:

  • Div верхнего уровня (.container ) - это гибкий контейнер.
  • Каждый дочерний .boxэлемент div ( ) теперь является гибким элементом.
  • Каждый .boxэлемент дан flex: 1для того, чтобы распределить контейнерное пространство одинаково.
  • Теперь элементы занимают все пространство в строке и имеют одинаковую ширину.
  • Сделайте каждый элемент (вложенным) гибким контейнером и добавьте justify-content: center.
  • Теперь каждый spanэлемент представляет собой центрированный гибкий элемент.
  • Используйте гибкие autoполя, чтобы сместить внешние spans влево и вправо.

Вы также можете отказаться justify-contentи использовать autoполя исключительно.

Но justify-contentможет работать здесь, потому что autoполя всегда имеют приоритет. Из спецификации:

8.1. Выравнивание по auto полям

До выравнивания через justify-contentи align-selfлюбое положительное свободное пространство распределяется по автоматическим полям в этом измерении.


justify-content: space-same (концепция)

Возвращаясь к justify-contentминутке, вот идея еще одного варианта.

  • space-same~ Гибрид space-betweenи space-around. Гибкие элементы расположены равномерно (как space-between), за исключением того, что вместо полусегментных пробелов на обоих концах space-aroundесть полноразмерные пробелы на обоих концах.

Это расположение может быть достигнуто с ::beforeи ::afterпсевдо-элементов на гибком контейнере.

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

(кредит: @oriol для кода и @crl для метки)

ОБНОВЛЕНИЕ: Браузеры начали реализацию space-evenly, которая выполняет вышеуказанное. Смотрите этот пост для деталей: Равное пространство между гибкими элементами


PLAYGROUND (включает код для всех примеров выше)

Майкл Бенджамин
источник
1
Ответ выше чехлов главной оси , justify-contentи autoполей. Для другой стороны монеты - по поперечной оси , align-items, align-selfи align-content- см этот пост: stackoverflow.com/q/42613359/3597276
Michael Benjamin
4
@MarkW, вы делаете аргументы в пользу justify-selfсобственности ... autoполя полезны, но justify-self: centerбыли бы идеальными. Способ решения поставленной вами проблемы - создать невидимые дубликаты на противоположной стороне. Смотрите мой ответ здесь: stackoverflow.com/q/38948102/3597276
Майкл Бенджамин
5
Ваша space-sameконцепция сейчас реальна. Он называется space-evenly, но на данный момент поддерживается только Firefox: developer.mozilla.org/en-US/docs/Web/CSS/justify-content
benface
1
@benface, да, ты прав. Спасибо что подметил это. Я на самом деле писал space-evenlyв других ответах: stackoverflow.com/q/45134400/3597276
Майкл Бенджамин
1
Фактически space-evenly был поддержан в Chrome 57-60, но только для Grid layout. Эта ошибка была исправлена, и начиная с Chrome 61 она поддерживается и для Flexbox. Кроме того , есть способ эмуляции без псевдо-элементов: .item { margin-right: auto } .item:first-child { margin-left: auto }.
Илья Стрельцын
155

Я знаю, что это не ответ, но я хотел бы внести свой вклад в это дело, чтобы оно того стоило. Было бы здорово, если бы они могли выпустить justify-selfflexbox, чтобы сделать его по-настоящему гибким.

Я считаю, что когда на оси несколько элементов, наиболее логичным способом justify-selfповедения является выравнивание с ближайшими соседями (или ребром), как показано ниже.

Я искренне надеюсь, что W3C это заметит и, по крайней мере, рассмотрит. знак равно

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

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

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

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

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

отметка
источник
12
@ Марк, это потрясающе! Спасибо, что нашли время, чтобы составить это. Я надеюсь, что вы не возражаете, но я представил это здесь: discourse.wicg.io/t/flexbox-justify-self-property/1146
Zaqx
1
@Zaqx уверен, чем больше выдержка, тем лучше. Серьезно надеюсь, что они найдут способ воплотить это в реальность, очень хотелось бы запачкать мои руки на этом.
Марк
1
Привет Марк, @Zaqx, я опубликовал ответ, который может охватывать некоторые варианты использования, упомянутые в этом ответе. Я обнаружил, что многое можно сделать на главной оси без необходимости justify-selfи justify-items.
Майкл Бенджамин
3
@Michael_B Рад, что вы узнали больше о flexbox и цените то, что вы нашли время, чтобы отформатировать свои заметки в ответ. Маржа: auto - это действительно круто (хотя вы обнаружите, что браузеры, в которых реализованы версии спецификации flexbox 2009 и 2012 годов, не имеют эквивалентной функции, которая значительно снижает возможность ее использования на рабочем сайте). Однако даже в браузерах, которые поддерживают margin: auto, основной вариант использования элемента, центрированного относительно его контейнера, в то время как пространство существует, все еще невозможен без свойства justify-self или подобного.
Zaqx
1
@Zaqx, спасибо за отзыв. И да, я согласен с вами, autoполя не являются полной заменой justify-self. Я осторожно озвучил свой предыдущий комментарий, сказав, что autoполя будут покрывать некоторые варианты использования . Как вы заметили, он не может центрировать элемент на месте, когда соседние элементы имеют разные размеры. Тем не менее, он предоставляет больше возможностей для выравнивания элементов Flex. Когда я впервые начал изучать flexbox, я думал, что justify-contentневидимые спейсерные элементы были единственным способом.
Майкл Бенджамин
20

Это было задано в списке в стиле www, и Таб Аткинс (редактор спецификаций) дал ответ, объясняющий почему . Я подробно остановлюсь здесь.

Для начала давайте предположим, что наш flex-контейнер является однострочным ( flex-wrap: nowrap). В этом случае очевидно, что существует разница в выравнивании между главной осью и поперечной осью - на главной оси есть несколько элементов, уложенных друг на друга, но только один элемент расположен на поперечной оси. Так что имеет смысл иметь настраиваемое для каждого элемента «align-self» на поперечной оси (поскольку каждый элемент выравнивается отдельно), тогда как это не имеет смысла на главной оси (поскольку там пункты выровнены все вместе).

Для многострочного flexbox та же логика применяется к каждой «гибкой линии». В данной строке элементы выровнены по отдельности по перекрестной оси (поскольку в поперечной оси имеется только один элемент на линию), а по основной оси - все вместе.


Вот еще один способ формулируя его: так, все из *-selfи *-contentсвойства о том , как распределить дополнительное пространство вокруг вещей. Но ключевое отличие состоит в том, что *-selfверсии предназначены для случаев, когда на этой оси есть только одна вещь , а версии - для тех случаев, когда на этой оси*-content потенциально много вещей . Сценарии «одно против многих» - это разные типы проблем, поэтому у них есть разные типы опций - например, значения space-around/ space-betweenимеют смысл *-content, но не для *-self.

SO: На главной оси flexbox есть много вещей, которые должны распределять пространство вокруг. Таким образом, *-contentсвойство имеет смысл, но не *-selfсвойство.

В противоположность этому, в поперечной оси у нас есть и a, *-selfи *-contentсвойство. Один определяет, как мы будем распределять пространство вокруг множества линий сгиба ( align-content), а другой ( align-self) определяет, как распределить пространство вокруг отдельных элементов сгиба на поперечной оси в пределах данной линии сгиба.

(Я игнорирую *-itemsсвойства здесь, так как они просто устанавливают значения по умолчанию для *-self.)

dholbert
источник
1
Я понимаю, как justify-selfможет быть проблема на оси с несколькими элементами в отличие от одного элемента. Однако я действительно надеюсь, что они рассмотрят это дальше, в ситуации с несколькими предметами, как они будут justify-selfсебя вести, потому что в некоторых ситуациях это может быть действительно полезным. Например ( stackoverflow.com/questions/32378953/… ).
Марк
Хорошая находка в этом списке рассылки. Попытка обернуть голову вокруг этого, поскольку я все еще вижу хорошие варианты использования для justify-self.
Майкл Бенджамин
Я добавил немного больше разъяснений, объясняя, как обстоит дело со *-selfслучаями, когда у нас есть только одна вещь для выравнивания, тогда как со *-contentслучаями, когда у нас есть много вещей для выравнивания. Это делает это немного яснее?
Дхолберт
Да, это более понятно. Я ценю объяснение. Но, похоже, все сводится к простому предпочтению авторов спецификаций, а не конкретной необходимости, основанной на логике. Из списка рассылки, на который вы ссылаетесь : Свойства * -self работают только в том случае, если дочерний элемент находится на этой оси один. Почему? Кажется, в этом нет необходимости. Это произвольное решение. Предпочтение Фактически, autoполя, также являющиеся частью спецификации, позволяют выравнивать * -self с несколькими элементами в строке. Нет четкой причины, по которой свойства ключевых слов не могут.
Майкл Бенджамин
1

Я знаю, что это не использует flexbox, но для простого варианта использования из трех элементов (один слева, один в центре, один справа) это может быть легко достигнуто с помощью display: gridродительского, дочернего элементов grid-area: 1/1/1/1;и justify-selfпозиционирования из тех детей.

<div style="border: 1px solid red; display: grid; width: 100px; height: 25px;">
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: left;"></div>
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: center;"></div>
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: right;"></div>
</div>

Venryx
источник
Спасибо за ответ, но он не решает вопрос. Кроме того, есть более простой способ сделать ваш макет: jsfiddle.net/fga89m2o
Майкл Бенджамин
0

Я только нашел свое решение этой проблемы, или, по крайней мере, мою проблему.
Я использовал justify-content: space-aroundвместо justify-content: space-between;.

Таким образом, конечные элементы будут придерживаться сверху и снизу, и вы можете иметь собственные поля, если хотите.

Лейф Мессингер LOAF
источник