Какой волшебный CSS вызывает разницу между text-vertical-align между <button> и <div>?

Я обнаружил, что текст внутри <button> автоматически вертикально центрирован, а текст внутри <div> находится в верхней строке.

Я попытался выяснить, какое правило CSS имеет значение, но не удалось.

div,
button {
  width: 4em;
  height: 4em;
  background-color: red;
  padding: 0;
  border: 0;
  margin: 1em;
  font-size: 1em;
  font-family: Arial;
}

div {
  text-align: center;
  display: inline-block;
  cursor: default;
  box-sizing: border-box;
}
<div>text text</div>
<button>text text</button>

<div>text text text text</div>
<button>text text text text</button>

<div>text text text text text text</div>
<button>text text text text text text</button>

Ответы

Ответ 1

Если вы посмотрите на исходный код Chrome, вы можете увидеть, как он работает, по крайней мере для Chrome. Кажется, есть анонимная гибкая коробка, созданная с использованием определенного стиля. Это не так просто - по крайней мере, не для меня, но все же вы можете определить, какой стиль применяется к этому анонимному элементу. Вы можете посмотреть здесь: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/layout/LayoutButton.cpp?sq=package:chromium

Интересная часть:

void LayoutButton::updateAnonymousChildStyle(const LayoutObject& child,
                                             ComputedStyle& childStyle) const {
  ASSERT(!m_inner || &child == m_inner);

  childStyle.setFlexGrow(1.0f);
  // min-width: 0; is needed for correct shrinking.
  childStyle.setMinWidth(Length(0, Fixed));
  // Use margin:auto instead of align-items:center to get safe centering, i.e.
  // when the content overflows, treat it the same as align-items: flex-start.
  childStyle.setMarginTop(Length());
  childStyle.setMarginBottom(Length());
  childStyle.setFlexDirection(style()->flexDirection());
  childStyle.setJustifyContent(style()->justifyContent());
  childStyle.setFlexWrap(style()->flexWrap());
  // TODO (lajava): An anonymous box must not be used to resolve children auto
  // values.
  childStyle.setAlignItems(style()->alignItems());
  childStyle.setAlignContent(style()->alignContent());
}

Это дает что-то вроде этого:

div span {
  display: flex;
  text-align: center; 
  min-width: 0px;
  flex-grow: 1;
  justify-content: center;
  cursor: default;
  margin: 0 auto;
  height: 100%;
  align-items: center;
  align-content: center;
}

Затем вам просто нужно обернуть содержимое div в этом диапазоне и применить стиль. Все эти правила, вероятно, не все необходимы или точны, но результат выглядит нормально:

div,
button {
  width: 4em;
  height: 4em;
  background-color: red;
  padding: 0;
  border: 0;
  margin: 1em;
  font-size: 1em;
  font-family: Arial;
  float: left;
}
div span {
  display: flex;
  text-align: center;
  min-width: 0px;
  flex-grow: 1;
  justify-content: center;
  cursor: default;
  margin: 0 auto;
  width: 100%;
  height: 100%;
  align-items: center;
  align-content: center;
}
<div><span>text text</span>
</div>
<button>text text</button>

<div><span>text text text text</span>
</div>
<button>text text text text</button>

<div><span>text text text text text text</span>
</div>
<button>text text text text text text</button>

Ответ 2

Поскольку вы используете inline-block, вам нужно использовать vertical-align, поскольку по умолчанию baseline:

Магический CSS:

vertical-align: middle;

Вышеуказанное это исправит:

div,
button {
  width: 4em;
  height: 4em;
  background-color: red;
  padding: 0;
  border: 0;
  margin: 1em;
  font-size: 1em;
  font-family: Arial;
  vertical-align: middle;
}

div {
  text-align: center;
  display: inline-block;
  cursor: default;
  box-sizing: border-box;
}
<div>text</div>
<button>text</button>

Ответ 3

Я думаю, вы можете рассмотреть одно из следующих решений:

Решение № 1

Добавьте их в стиль div

display: table-cell;

vertical-align: middle;

Если вам все еще нужно использовать отображение встроенного блока, вы можете использовать вложенный div, родительский div будет отображаться как (встроенный блок), дочерний div будет отображаться как (table-cell) и тот, где вы находитесь текст.

Решение №2

Вы можете установить динамическое расширение div и высоту строки с помощью jQuery.. и это будет сделано во время выполнения и будет скорректировано в зависимости от размера содержимого внутри div. вы можете проверить этот вопрос jquery set line-height, равный высоте родительского контейнера