Центрировать один элемент вместе с несколькими братьями и сестрами

У меня есть div с некоторым количеством пролетов, которые могут быть или не быть одинаковой ширины. Я знаю, что могу использовать text-align: center, чтобы центрировать весь контент внутри div. Однако я хочу выбрать конкретный отрезок и обозначить его как истинный центр, а не центр, являющийся средней точкой последовательности пролетов.

У меня была одна идея для имитации этого эффекта: у меня был бы желаемый средний элемент с двумя контейнерами слева и справа; левый будет выравниваться по правому краю, и наоборот. Эти контейнеры будут содержать другой контент в div. Если бы я мог заставить эти два контейнера заполнить оставшееся пространство в равных количествах, это привело бы к центрированию среднего элемента, сохраняя при этом левое и правое содержимое выровненными по центру. По сути, для этого потребуется, чтобы ширина двух контейнеров была установлена ​​ровно на половину оставшегося пространства в div. (Я не хочу менять размер среднего div.) Возможно ли это сделать только с помощью CSS?

Пример: с 4 пролетами, как назначить пролет 2 истинным центром?

div {
  width: 500px;
  padding: 4px;
  border: 1px dotted black;
}
span {
  display: inline-block;
  width: 100px;
  text-align: center;
  margin: 4px;
  box-sizing: border-box;
  border: 1px dotted black;
}
#b {
  /* ??? */
}
<div>
  <span id="a">1</span>
  <span id="b">2</span>
  <span id="c">3</span>
  <span id="d">4</span>
</div>


person codebreaker    schedule 31.12.2016    source источник
comment
Много ответов для нечетного числа (например, 3) элементов, где средний находится в центре, но мне было бы интересно увидеть элегантное решение для четного числа элементов (например, 4), где 2-й находится в центре.   -  person Daniel Farrell    schedule 31.12.2016


Ответы (3)


Это можно сделать с помощью флексбокса. Вы можете использовать display:flex; на div и использовать flex-grow:1; на 2nd span. Таким образом, вы можете покрыть весь div этим диапазоном.

Так как 1-й и 3-й пролет уже имеют одинаковую ширину, у вас будет 2-й пролет в мертвой точке. А затем используйте flex-basis на втором, чтобы получить желаемую ширину.

div.container{
  width: 500px;
  padding: 4px;
  border: 1px dotted black;
}
div.row{
  display:flex;
  align-items:center;
  justify-content:center;
}
span {
  display: inline-block;
  width: 70px;
  text-align: center;
  margin: 4px;
  box-sizing: border-box;
  border: 1px dotted black;
  transform:translate(50%,0);
}
#b {
}
<html>

<head></head>

<body>
  <div class='container'>
    <div class="row">
      <span id="a">1</span>
      <span id="b">2</span>
      <span id="c">3</span>
      <span id="d">4</span>
    </div>
  </div>
</body>

</html>

person ab29007    schedule 31.12.2016
comment
То, что я пытаюсь добиться, является своего рода обратным: span 2 занимает свою естественную ширину (или в данном случае 100 пикселей), а два других занимают оставшееся пространство в равных количествах. - person codebreaker; 31.12.2016
comment
@codebreaker Думаю, мне удалось поставить 2-й пролет в центр. Смотрите мой обновленный ответ - person ab29007; 31.12.2016
comment
Если это решит вашу проблему, пожалуйста, примите мой ответ. если нет, то, пожалуйста, скажите мне, что мне добавить к моему ответу, потому что я запутался в вашем последнем комментарии. - person ab29007; 31.12.2016
comment
Это работает, спасибо. Я, вероятно, должен был указать: промежутки в div могут быть не одинаковой длины. Есть ли способ адаптировать это решение для поддержки промежутков произвольного размера? - person codebreaker; 31.12.2016
comment
Он будет отлично работать, если все промежутки имеют одинаковый размер. после этого только javascript может помочь. и, пожалуйста, не забудьте принять ответ, если он работает в вашем случае. - person ab29007; 31.12.2016
comment
Извините, в своем вопросе я предложил два способа добиться эффекта, когда один элемент находится в центре, а другие выровнены по его левой и правой сторонам. Я думал, что это поможет прояснить, что я искал, но, возможно, нет. - person codebreaker; 31.12.2016
comment
Ok. нет проблем, я поработаю над тем, чтобы заставить это работать на неравной ширине, и если я найду это, я дам вам знать. - person ab29007; 31.12.2016
comment
Я переписал свой вопрос, чтобы лучше объяснить, что я пытаюсь сделать, надеюсь, это поможет. Спасибо за ваши старания. - person codebreaker; 31.12.2016

Вы можете использовать флексбокс. Основываясь на этом ответе,

.outer-wrapper {
  display: flex;
  padding: 4px;
  border: 1px dotted black;
}
.item {
  margin: 4px;
  text-align: center;
  border: 1px dotted black;
}
.left.inner-wrapper, .right.inner-wrapper {
  flex: 1;
  display: flex;
  align-items: flex-start;
  min-width: -webkit-min-content; /* Workaround to Chrome bug */
}
.left.inner-wrapper {
  justify-content: flex-end;
}
.animate {
  animation: anim 5s infinite alternate;
}
@keyframes anim {
  from { min-width: 0 }
  to { min-width: 50vw; }
}
<div class="outer-wrapper">
  <div class="left inner-wrapper">
    <div class="item animate">1. Left</div>
  </div>
  <div class="center inner-wrapper">
    <div class="item">2. Center</div>
  </div>
  <div class="right inner-wrapper">
    <div class="item">3. Right</div>
    <div class="item">4. Right</div>
  </div>
</div>
<!-- Analogous to above --> <div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">1. Left</div></div><div class="center inner-wrapper"><div class="item animate">2. Center</div></div><div class="right inner-wrapper"><div class="item">3. Right</div><div class="item">4. Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">1. Left</div></div><div class="center inner-wrapper"><div class="item">2. Center</div></div><div class="right inner-wrapper"><div class="item animate">3. Right</div><div class="item">4. Right</div></div></div><div class="outer-wrapper"><div class="left inner-wrapper"><div class="item">1. Left</div></div><div class="center inner-wrapper"><div class="item">2. Center</div></div><div class="right inner-wrapper"><div class="item">3. Right</div><div class="item animate">4. Right</div></div></div>

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

person Oriol    schedule 31.12.2016
comment
Мне потребовалась минута, чтобы понять, что происходит в анимации, но это действительно круто. Я думал, что гибкие блоки работают на основе пробелов, а не ширины. Это не то, что здесь происходит, не так ли? - person codebreaker; 31.12.2016
comment
@codebreaker Объяснение находится в связанном ответе, я использую три гибких поля, которые представляют левое, центральное и правое. Левый и правый изначально имеют размер 0 по ширине, а затем они увеличиваются, чтобы заполнить оставшееся пространство, поэтому центральный становится центрированным. Неявный min-width: auto предотвращает перекрытие. - person Oriol; 01.01.2017

Я предлагаю сделать это с макетом из 3 столбцов и использовать структуру таблицы CSS. Сделайте так, чтобы 1-й и 3-й столбцы занимали 50% от общей ширины, а средний столбец будет иметь только 0, но он будет пересчитывать ширину, чтобы соответствовать содержимому, и останется в центре, поскольку он находится в таблице.

Также поместите туда white-space: nowrap;, если внутри несколько слов, но удалите его по мере необходимости, если есть только одно слово или фиксированная ширина.

.container {
  display: table;
  border-collapse: collapse;
  width: 100%;
}
.item {
  display: table-cell;
  vertical-align: top;
  padding: 4px;
  border: 1px solid grey;
}
.item-a {
  width: 50%;
  text-align: right;
}
.item-b {
  text-align: center;
  white-space: nowrap; /* remove as needed */
}
.item-c {
  width: 50%;
}
.item span {
  display: inline-block;
  border: 1px solid red;
}
.item-b span {
  padding: 0 50px; /* for demo only */
}
<div class="container">
  <span class="item item-a">
    <span>1</span>
  </span>
  <span class="item item-b">
    <span>2</span>
  </span>
  <span class="item item-c">
    <span>3</span>
    <span>4</span>
  </span>
</div>

jsFiddle

person Stickers    schedule 31.12.2016