Центрирование в CSS: Полное руководство

Вещи, связанные с центрированием в CSS, это, пожалуй, олицетворение того, на что чаще всего жалуются пользователи. Это на самом деле должно быть так сложно? — иронично интересуются они.

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

Поэтому давайте создадим дерево решений и, надеюсь, теперь этот вопрос станет для вас проще.
Мне нужно отцентрировать элементы…

Горизонтально

Это элементы inline или inline-* (например, текст или ссылки)?

Вы можете отцентрировать элементы inline горизонтально, в родительском элементе block-level с помощью:

.center-children {
  text-align: center;

HTML:

<header>
  Этот текст отцентрирован.
</header>

<nav role='navigation'>
  <a href="#0">Один</a>
  <a href="#0">Два</a>
  <a href="#0">Три</a>
  <a href="#0">Четыре</a>
</nav>

CSS:

body {
  background: #f06d06;
}

header, nav {
  text-align: center;
  background: white;
  margin: 20px 0;
  padding: 10px;
}

nav a {
  text-decoration: none;
  background: #333;
  border-radius: 5px;
  color: white;
  padding: 3px 8px;
}

Результат

Это будет работать для inline, inline-block, inline-table, inline-flex и т.д.

Это элемент уровня блока?

Вы можете отцентрировать элемент block-level, придав ему margin-left и margin-right или auto (при этом также нужно задать width, в противном случае это будет полная ширина, и центрирование не потребуется). Это часто делается в подобных сокращениях:

.center-me {
  margin: 0 auto;
}

HTML:

<main>
  <div class="center">
    Я элемент block-level и я отцентрирован.
  </div>
</main>

CSS:

body {
  background: #f06d06;
}

main {
  background: white;
  margin: 20px 0;
  padding: 10px;
}

.center {
  margin: 0 auto;
  width: 200px;
  background: black;
  padding: 20px;
  color: white;
}

Результат

Это будет работать независимо от ширины элемента block-level или родительского элемента.
Обратите внимание, что вы не можете использовать привязку к центру float. Хотя, существует способ.

У вас есть более чем один элемент block-level?

Если у вас есть два или более элемента block-level, которые должны быть отцентрированы горизонтально в ряд, скорее всего вам лучше применить для них разные типы display. Вот примеры, как сделать из них inline-block и flexbox:

HTML:

<main class="inline-block-center">
  <div>
    Я элемент блочного типа, у меня есть другие элементы того же уровня, и все мы отцентрированы в ряд.
  </div>
  <div>
    Я элемент блочного типа, у меня есть другие элементы того же уровня, и все мы отцентрированы в ряд. Я содержу больше контента, чем другие элементы моего уровня.
  </div>
  <div>
    Я элемент блочного типа, у меня есть другие элементы того же уровня, и все мы отцентрированы в ряд.
  </div>
</main>

<main class="flex-center">
  <div>
    Я элемент блочного типа, у меня есть другие элементы того же уровня, и все мы отцентрированы в ряд.
  </div>
  <div>
    Я элемент блочного типа, у меня есть другие элементы того же уровня, и все мы отцентрированы в ряд. Я содержу больше контента, чем другие элементы моего уровня.
  </div>
  <div>
    Я элемент блочного типа, у меня есть другие элементы того же уровня, и все мы отцентрированы в ряд.
  </div>
</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

main {
  background: white;
  margin: 20px 0;
  padding: 10px;
}

main div {
  background: black;
  color: white;
  padding: 15px;
  max-width: 125px;
  margin: 5px;
}

.inline-block-center {
  text-align: center;
}
.inline-block-center div {
  display: inline-block;
  text-align: left;
}

.flex-center {
  display: flex;
  justify-content: center;
}

Результат

Если только вы не хотите расположить несколько элементов block-level друг над другом. В этом случае по-прежнему прекрасно работает техника автоматического отступа:

HTML:

<main>
  <div>
    Я элемент блочного типа, у меня есть другие элементы того же уровня, и все мы отцентрированы в ряд.
  </div>
  <div>
    Я элемент блочного типа, у меня есть другие элементы того же уровня, и все мы отцентрированы в ряд. Я содержу больше контента, чем другие элементы моего уровня.
  </div>
  <div>
    Я элемент блочного типа, у меня есть другие элементы того же уровня, и все мы отцентрированы в ряд.
  </div>
</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

main {
  background: white;
  margin: 20px 0;
  padding: 10px;
}

main div {
  background: black;
  margin: 0 auto;
  color: white;
  padding: 15px;
  margin: 5px auto;
}

main div:nth-child(1) {
  width: 200px;
}
main div:nth-child(2) {
  width: 400px;
}
main div:nth-child(3) {
  width: 125px;
}

Результат

Вертикально

Вертикальное центрирование в CSS немного сложнее

Это элементы inline или inline-* (например, текст или ссылки)?

Это одиночная строка?

Иногда линейные / текстовые элементы могут центрироваться по вертикали, просто потому, что отступ снизу и сверху равны:

.link {
  padding-top: 30px;
  padding-bottom: 30px;
}

HTML:

<main>
  <a href="#0">Мы</a>
  <a href="#0">Отцентрированные</a>
  <a href="#0">Фрагменты</a>
  <a href="#0">Текста</a>
</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

main {
  background: white;
  margin: 20px 0;
  padding: 50px;
}

main a {
  background: black;
  color: white;
  padding: 40px 30px;
  text-decoration: none;
}

Результат

Если отступ по некоторым причинам для вас это не вариант, и вы хотите отцентрировать текст, который не будет оборачивать, существует прием, аналогичный тому, что мы делали с line-height:

.center-text-trick {
  height: 100px;
  line-height: 100px;
  white-space: nowrap;
}

HTML:

<main>
  <div>
    Я отцентрированная строка.
  </div>
</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

main {
  background: white;
  margin: 20px 0;
  padding: 40px;
}

main div {
  background: black;
  color: white;
  height: 100px;
  line-height: 100px;
  padding: 20px;
  width: 50%;
  white-space: nowrap;
}

Результат

Это несколько строк?

Аналогично отступ сверху и снизу может задать эффект центрирования для нескольких строк текста. Но иногда это не будет работать, если элемент текста представляет собой ячейку таблицы или для него с помощью CSS задано такое поведение. В этом случае применяется свойство vertical-align, в отличие от общих случаев выравнивания элементов:

HTML:

<table>
  <tr>
    <td>
      Мы - отцентрированные по вертикали несколько строк текст в ячейке таблицы.
    </td>
  </tr>
</table>

<div class="center-table">
  <p> Мы - отцентрированные по вертикали несколько строк текста в созданной через CSS структуре таблицы.</p>
</div>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

table {
  background: white;
  width: 240px;
  border-collapse: separate;
  margin: 20px;
  height: 250px;
}

table td {
  background: black;
  color: white;
  padding: 20px;
  border: 10px solid white;
  /* по умолчанию используется vertical-align: middle; */
}

.center-table {
  display: table;
  height: 250px;
  background: white;
  width: 240px;
  margin: 20px;
}
.center-table p {
  display: table-cell;
  margin: 0;
  background: black;
  color: white;
  padding: 20px;
  border: 10px solid white;
  vertical-align: middle;
}

Результат

Если выравнивание в формате таблицы неприменимо для вас, возможно, вы могли бы использовать flexbox? Один дочерний элемент flex может легко быть отцентрирован внутри родительского элемента flex:

.flex-center-vertically {
  display: flex;
  justify-content: center;
  flex-direction: column;
  height: 400px;
}

HTML:

<div class="flex-center">
  <p>Мы - отцентрированные по вертикали несколько строк текста в контейнере flexbox.</p>
</div>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

div {
  background: white;
  width: 240px;
  margin: 20px;
}

.flex-center {
  background: black;
  color: white;
  border: 10px solid white;
  display: flex;
  flex-direction: column;
  justify-content: center;
  height: 200px;
  resize: vertical;
  overflow: auto;
}
.flex-center p {
  margin: 0;
  padding: 20px;
}

Результат

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

Если оба этих метода неприменимы, вы могли бы использовать технику «призрачного элемента«, в которой внутри контейнера по всей высоте размещается псевдо-элемент и текст вертикально выравнивается с помощью этого элемента:

.ghost-center {
  position: relative;
}
.ghost-center::before {
  content: " ";
  display: inline-block;
  height: 100%;
  width: 1%;
  vertical-align: middle;
}
.ghost-center p {
  display: inline-block;
  vertical-align: middle;
}

HTML:

<div class="ghost-center">
  <p>Мы - отцентрированные по вертикали несколько строк текста в контейнере. Центрирование выполнено внутри псевдо элемента.</p>
</div>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

div {
  background: white;
  width: 240px;
  height: 200px;
  margin: 20px;
  color: white;
  resize: vertical;
  overflow: auto;
  padding: 20px;
}

.ghost-center {
  position: relative;
}
.ghost-center::before {
  content: " ";
  display: inline-block;
  height: 100%;
  width: 1%;
  vertical-align: middle;
}
.ghost-center p {
  display: inline-block;
  vertical-align: middle;
  width: 190px;
  margin: 0;
  padding: 20px;
  background: black;
}

Результат

Это элемент block-level?

Вы знаете высоту элемента?

Довольно часто вы можете не знать высоту в макете веб-страницы по многим причинам: если ширина изменяется, текст адаптивный и может изменять высоту. Высота текста может меняться в зависимости от различных применяемых к нему стилей.

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

Но если вы знаете высоту, вы можете выровнять элемент по центру следующим образом:

.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  height: 100px;
  margin-top: -50px; /* при вычислении отступа и границы не используется  box-sizing: border-box; */
}

HTML:

<main>

  <div>
     Я элемент block-level с фиксированной высотой, отцентрированный вертикально внутри родительского элемента.
  </div>

</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

main {
  background: white;
  height: 300px;
  margin: 20px;
  width: 300px;
  position: relative;
  resize: vertical;
  overflow: auto;
}

main div {
  position: absolute;
  top: 50%;
  left: 20px;
  right: 20px;
  height: 100px;
  margin-top: -70px;
  background: black;
  color: white;
  padding: 20px;
}

Результат

Высота элемента неизвестна?

Его все равно можно отцентрировать, сдвинув его вниз на половину экрана, а затем подвинув вверх на половину высоты элемента:

.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
}

HTML:

<main>

  <div>
     Я элемент block-level с неизвестной высотой, отцентрированный вертикально внутри родительского элемента.
  </div>

</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

main {
  background: white;
  height: 300px;
  margin: 20px;
  width: 300px;
  position: relative;
  resize: vertical;
  overflow: auto;
}

main div {
  position: absolute;
  top: 50%;
  left: 20px;
  right: 20px;
  background: black;
  color: white;
  padding: 20px;
  transform: translateY(-50%);
  resize: vertical;
  overflow: auto;
}

Результат

Можем ли мы использовать flexbox.

В самом деле, с помощью flexbox это делается намного проще:

.parent {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

HTML:

<main>

  <div>
     Я элемент block-level с неизвестной высотой, отцентрированный вертикально внутри родительского элемента.
  </div>

</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
}

main {
  background: white;
  height: 300px;
  width: 200px;
  padding: 20px;
  margin: 20px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  resize: vertical;
  overflow: auto;
}

main div {
  background: black;
  color: white;
  padding: 20px;
  resize: vertical;
  overflow: auto;
}

Результат

Горизонтально и вертикально

Вы можете комбинировать методы, приведенные выше, любым способом, чтобы получить полное центрирование элементов. Но я, как правило, выделяю три основных частных случая.

Это элементы с фиксированной шириной и высотой?

Использование отрицательных полей, равных половине ширины и высоты элемента, после того, как вы абсолютно позиционировали их на 50% / 50% от размеров родительского элемента, будет поддерживаться большинством браузеров:

.parent {
  position: relative;
}

.child {
  width: 300px;
  height: 100px;
  padding: 20px;

  position: absolute;
  top: 50%;
  left: 50%;

  margin: -70px 0 0 -170px;
}

HTML:

<main>

  <div>
     Я элемент block-level с фиксированной высотой и шириной, отцентрированный внутри родительского элемента.
  </div>

</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
  padding: 20px;
}

main {
  position: relative;
  background: white;
  height: 200px;
  width: 60%;
  margin: 0 auto;
  padding: 20px;
  resize: both;
  overflow: auto;
}

main div {
  background: black;
  color: white;
  width: 200px;
  height: 100px;
  margin: -70px 0 0 -120px;
  position: absolute;
  top: 50%;
  left: 50%;
  padding: 20px;
}

Результат

Это элемент с неизвестными шириной и высотой?

Если вы не знаете, ширину или высоту элемента, вы можете использовать свойство преобразования и отрицательный перевод на 50% в обеих плоскостях (этот метод основан на текущей ширине / высоте элемента) в центр:

.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

HTML:

<main>

  <div>
     Я элемент block-level с неизвестной высотой и шириной, отцентрированный внутри родительского элемента.
  </div>

</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
  padding: 20px;
}

main {
  position: relative;
  background: white;
  height: 200px;
  width: 60%;
  margin: 0 auto;
  padding: 20px;
  resize: both;
  overflow: auto;
}

main div {
  background: black;
  color: white;
  width: 50%;
  transform: translate(-50%, -50%);
  position: absolute;
  top: 50%;
  left: 50%;
  padding: 20px;
  resize: both;
  overflow: auto;
}

Результат

Можем мы использовать flexbox?

Чтобы отцентрировать элемент в двух плоскостях с помощью flexbox, нам нужно использовать два свойства центрирования:

.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}

HTML:

<main>

  <div>
     Я элемент block-level с неизвестной высотой и шириной, отцентрированный внутри родительского элемента.
  </div>

</main>

CSS:

body {
  background: #f06d06;
  font-size: 80%;
  padding: 20px;
}

main {
  background: white;
  height: 200px;
  width: 60%;
  margin: 0 auto;
  padding: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
  resize: both;
  overflow: auto;
}

main div {
  background: black;
  color: white;
  width: 50%;
  padding: 20px;
  resize: both;
  overflow: auto;
}

Результат

Заключение

Теперь вы можете центрировать любые элементы с помощью CSS.

Перевод статьи «Centering in CSS: A Complete Guide» был подготовлен дружной командой проекта Сайтостроение от А до Я.