Flex-grow не подбирает гибкие элементы, как ожидалось

Кажется, что содержимое внутри гибкого div влияет на его расчетный размер относительно свойства flex-grow. Я делаю что-то неправильно?

В приведенной ниже скрипте вы увидите цифровую панель. Все строки содержат 3 номера, кроме нижней строки. Эта строка должна иметь "0" ширину из двух чисел, поэтому flex-grow: 2 и ":" (двоеточие) будет размером 1 число, следовательно flex-grow: 1.

Я что-то упустил?

Правая сторона "0" должна быть выровнена с 8, 5 и 2 над ней. Это немного.

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

.numbers {
    display: flex;
    flex-direction: column;
}

.row {
    display: flex;
    flex-direction: row;
    flex-grow: 1;
    justify-content: space-between;
}

.button {
    display: flex;
    flex-grow: 1;
    justify-content: center;
    align-items: center;
    margin: 5px;
    border-radius: 5px;
    border: 1px solid gray;
    background: rgba(255, 255, 255, 0.2);
    cursor: pointer;
}

.button#number0 {
    flex-grow: 2;
}

.button#colon {
    flex-grow: 1;
}
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>

Ответ 1

Краткий анализ

Проблема состоит в том, что строки 1-3 имеют два горизонтальных поля, а строка 4 имеет только одну.

enter image description here

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

Поскольку flex-grow применяется только к свободному пространству и находится под сильным влиянием содержимого и полей, это не самый безопасный способ определения размера элементов Flex.

Попробуйте вместо этого flex-basis base. Добавьте это к своему коду:

.button    { flex-basis: 33.33%; }
#number0   { flex-basis: calc(66.67% + 10px); }
*          { box-sizing: border-box; }

.numbers {
    display: flex;
    flex-direction: column;
}

.row {
    display: flex;
    flex-direction: row;
    flex-grow: 1;
    justify-content: space-between;
}

.button {
    display: flex;
    flex-basis: 33.33%;
    justify-content: center;
    align-items: center;
    margin: 5px;
    border-radius: 5px;
    border: 1px solid gray;
    background: rgba(255, 255, 255, 0.2);
    cursor: pointer;
}

#number0   { flex-basis: calc(66.67% + 10px); }
*          { box-sizing: border-box; }
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>

Ответ 2

Обновление 3:

Я выяснил еще один способ избавиться от несоосности.

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

flex только версия

.row {
  width: 60%;
  margin: auto;
  display: flex;
}
.button {
  flex: 0 0 33.3%;
  text-align: center;
  position: relative;
  padding: 10px 5px;
  box-sizing: border-box;
  pointer-events: none;
}
.button#number0 {
  flex: 0 0 66.6%;
}

.button:before,
.button:after {
  content: " ";
  border-radius: 5px;
  border: 1px solid gray;  
  cursor: pointer;
  position: absolute;
  left: 5px;
  top: 5px;
  right: 5px;
  bottom: 5px;
  pointer-events: auto;
}
.button:before {
  background: rgba(255, 255, 255, 0.9);
  z-index: -1
}
.button:hover:before {
  background: rgba(0, 0, 0, 0.1);
}
.button:hover:after {
  border: 2px solid red;
}
.button:active:before {
  background: rgba(255, 0, 0, 0.5);
}
<div class="numbers">
    <div class="row">
        <div class="button number" id="number1">1</div>
        <div class="button number" id="number2">2</div>
        <div class="button number" id="number3">3</div>
    </div>
    <div class="row">
        <div class="button number" id="number4">4</div>
        <div class="button number" id="number5">5</div>
        <div class="button number" id="number6">6</div>
    </div>
    <div class="row">
        <div class="button number" id="number7">7</div>
        <div class="button number" id="number8">8</div>
        <div class="button number" id="number9">9</div>
    </div>
    <div class="row">
        <div class="button number" id="number0">0</div>
        <div class="button" id="colon">:</div>
    </div>
</div>

Ответ 3

Я думаю, что все, что сказал Michael_B, верное. Только решения немного неудобны. Я лично не люблю вычислять. Он просто не чувствует себя хорошо.

Проблема у вас более общая. Вы накладываете слишком много обязанностей на один элемент. В этом случае это класс .button. Flex и Margin с гибким ростом - это слишком большая ответственность. Попытайтесь разбить это. Это означает больше элементов DOM, но это избавляет вас от большой боли.

.numbers {
  display: flex;
  flex-direction: column;
  max-width: 200px;
  margin: 0 auto;
}

.row {
  display: flex;
  flex-direction: row;
  flex-grow: 1;
  justify-content: space-between;
}

.row > .box {
  display: flex;
  flex-basis: 33.3333%;
  justify-content: center;
  align-items: center;
}

.row > .box.box-2 {
  flex-basis: 66.6667%;
}

.button {
  border-radius: 5px;
  border: 1px solid gray;
  background: rgba(255, 255, 255, 0.2);
  cursor: pointer;
  width: auto;
  text-align: center;
  margin: 5px;
  width: 100%;
}
<div class="numbers">
    <div class="row">
      <div class="box"><div class="button number" id="number1">1</div></div>
      <div class="box"><div class="button number" id="number2">2</div></div>
      <div class="box"><div class="button number" id="number3">3</div></div>
    </div>
    <div class="row">
      <div class="box"><div class="button number" id="number4">4</div></div>
      <div class="box"><div class="button number" id="number5">5</div></div>
      <div class="box"><div class="button number" id="number6">6</div></div>
    </div>
    <div class="row">
      <div class="box"><div class="button number" id="number7">7</div></div>
      <div class="box"><div class="button number" id="number8">8</div></div>
      <div class="box"><div class="button number" id="number9">9</div></div>
    </div>
    <div class="row">
      <div class="box box-2"><div class="button number" id="number0">0</div></div>
      <div class="box"><div class="button" id="colon">:</div></div>
        
        
    </div>
</div>

Ответ 4

flexbox, на мой взгляд, плохо реагирует на полях.

Лучший подход/обходной путь, который я предпочитаю, состоит в том, чтобы убедиться, что все дети Flex имеют 0 полей, установите контейнер flex на justify-content: space-between;, а затем дайте детям общую ширину менее 100%. Остальная часть будет вашей маржой.

Другими словами, если вам нужно два элемента в строке, установите их шириной 49%, и у вас будет 2% пространства между ними. Три элемента, каждый по 32% в ширину, и у вас будет 2% между ними. В примере калькулятора ячейка 0 должна быть 66%, а остальные 32%.

Изменить: обратите внимание, что, поскольку причины (а именно, что content-box ужасно), если у какого-либо из ваших детей есть границы, вам нужно использовать box-sizing: border-box, чтобы мое предложение работало правильно.

https://jsfiddle.net/r3L1mtbe/2/

Ответ 5

Важно использовать стенографию для поддержки кросс-браузера:

.row {
    display: flex;
    flex-direction: row; /* <-- this is the default so unnecessary to state */
    flex-grow: 1;
    justify-content: space-between;
}

.button {
    display: flex;
   /* flex-grow: 1; replace with shorthand */ 
   flex:1 0 100%; /* probably making the "width: 100%;" unnecessary */
    justify-content: center;
}

.button#number0 {
    /* flex-grow: 2; replace with shorthand */ 
   flex:2 0 100%;
}

.button#colon {
    /* flex-grow: 1; replace with shorthand */ 
    flex:1 0 100%;
}