Пользователь
0,0
рейтинг
28 сентября 2014 в 21:43

Разработка → Выравниваем блок по центру страницы

HTML*, CSS*
Очень часто стоит задача выровнять блок по центру страницы / экрана, да ещё и так, чтобы без ява-скрипта, без задания жёстких размеров или отрицательных отступов, ещё чтобы и скроллбары работали у родителя, если блок превышает его размеры. В сети ходят достаточно много однообразных примеров как выровнять блок по центру экрана. Как правило большинство из них основаны на одних принципах.

Ниже представлены основные способы решения задачи, их плюсы и минусы. Чтобы понимать суть примеров, рекомендую уменьшить высоту / ширину окошка Result в примерах по указанным ссылкам.

Вариант 1. Отрицательный отступ.


Позиционируем блок атрибутами top и left на 50%, и заранее зная высоту и ширину блока, задаём отрицательный margin, который равен половине размера блока. Огромным минусом данного варианта является то, что нужно подсчитывать отрицательные отступы. Так же блок не совсем корректно ведёт себя в окружении скроллбаров — он попросту обрезается так как имеет отрицательные отступы.

Пример: jsfiddle.net/serdidg/pphzjh25/1.

<div class="parent">
    <div class="block">
        <img src="1450829233933958453855" alt=""/>
    </div>
</div>


.parent {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    overflow: auto;
}

.block {
    width: 250px;
    height: 250px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin: -125px 0 0 -125px;
    
    img {
        max-width: 100%;
        height: auto;
        display: block;
        margin: 0 auto;
        border: none;
    }
}


Вариант 2. Автоматический отступ.


Менее распространённый, но схожий с первым. Для блока задаём ширину и высоту, позиционируем атрибутами top right bottom left на 0, и задаём margin auto. Плюсом данного варианта являются рабочие скроллбары у родителя, если у последнего задана 100% ширина и высота. Минусом данного способ является жёсткое задание размеров.

Пример: jsfiddle.net/serdidg/sg0xbw88/1.

<div class="parent">
    <div class="block">
        <img src="1450829233933958453855" alt=""/>
    </div>
</div>


.parent {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    overflow: auto;
}

.block {
    width: 250px;
    height: 250px;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin: auto;
    
    img {
        max-width: 100%;
        height: auto;
        display: block;
        margin: 0 auto;
        border: none;
    }
}


Вариант 3. Таблица.


Задаём родителю табличные стили, ячейке родителя устанавливаем выравнивание текста по центру. А блоку задаём модель строчного блока. Минусами мы получаем не рабочие скроллбары, и в целом не эстетичность «эмуляции» таблицы.

Пример: jsfiddle.net/serdidg/fk5nqh52/2.

<div class="parent">
    <div class="inner">
        <div class="block">
            <img src="1450829233933958453855" alt=""/>
        </div>
    </div>
</div>


.parent {
    width: 100%;
    height: 100%;
    display: table;
    position: absolute;
    top: 0;
    left: 0;
    
    > .inner {
        display: table-cell;
        text-align: center;
        vertical-align: middle;
    }
}

.block {
    display: inline-block;
    
    img {
        display: block;
        border: none;
    }
}


Чтобы добавить скролл в данный пример, придётся добавить в конструкцию ещё один элемент.
Пример: jsfiddle.net/serdidg/fk5nqh52/3.

Вариант 4. Псевдо-элемент.


Данный вариант лишён всех проблем, перечисленных у предыдущих способов, а так же решает первоначально поставленные задачи. Суть состоит в том, чтобы у родителя задать стили псевдо-элементу before, а именно 100% высоту, выравнивание по центру и модель строчного блока. Так же само и у блока ставится модель строчного блока, выравнивание по центру. Чтобы блок не «падал» под псевдо-элемент, когда размеры первого больше чем родителя, указываем родителю white-space: nowrap и font-size: 0, после чего у блока отменяем эти стили следующими — white-space: normal. В данном примере font-size: 0 нужен для того, чтобы убрать образовавшийся пробел между родителем и блоком в связи с форматированием кода. Пробел можно убрать и иными способами, но лучшим считается просто его не допускать.

Пример: jsfiddle.net/serdidg/nfqg9rza/1.
Примеры без нулевого font-size: jsfiddle.net/serdidg/nfqg9rza/29, jsfiddle.net/serdidg/nfqg9rza/39.

<div class="parent">
    <div class="block">
        <img src="1450829233933958453855" alt=""/>
    </div>
</div>


.parent {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    overflow: auto;
    white-space: nowrap;
    text-align: center;
    font-size: 0;
    
    &:before {
        height: 100%;
        display: inline-block;
        vertical-align: middle;
        content: '';
    }
}

.block {
    display: inline-block;
    white-space: normal;
    vertical-align: middle;
    text-align: left;
    
    img {
        display: block;
        border: none;
    }
}


либо, если вам нужно, чтобы родитель занимал только высоту и ширину окна, а не всей страницы:

.parent {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    overflow: auto;
    white-space: nowrap;
    text-align: center;
    font-size: 0;
    
    &:before {
        height: 100%;
        display: inline-block;
        vertical-align: middle;
        content: '';
    }
}

.block {
    display: inline-block;
    white-space: normal;
    vertical-align: middle;
    text-align: left;
    
    img {
        display: block;
        border: none;
    }
}


Вариант 5. Flexbox.


Одним из самых простых и элегантных способов является использования flexbox. Он не требует лишних телодвижений, достаточно понятно описывает суть происходящего, обладает высокой гибкостью. Единственное, что стоит помнить при выборе данного способа — поддержка IE от 10-й версии включительно. caniuse.com/#feat=flexbox

Пример: jsfiddle.net/serdidg/zyzvsk9d/1.

<div class="parent">
    <div class="block">
        <img src="1450829233933958453855" alt=""/>
    </div>
</div>


.parent {
    width: 100%;
    height: 100%;
    position: fixed;
    top: 0;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: center; 
    overflow: auto;   
}

.block {
    background: #60a839;
    
    img {
        display: block;
        border: none;
    }
}


Вариант 6. Кнопка.


Пользователь azproduction предложил вариант, где блок обрамляется в тег button. Кнопка имеет свойство центрировать всё, что находится у неё внутри, а именно элементы строчной и блочно-строчной (inline-block) модели. На практике использовать не рекомендую.

Пример: jsfiddle.net/serdidg/0bn8wg38.

<button class="parent">
    <div class="block">
        <img src="1450829233933958453855" alt=""/>
    </div>
</button>


.parent {
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
    left: 0;
    overflow: auto;
    background: none;
    border: none;
    outline: none;
}

.block {
    display: inline-block;
    
    img {
        display: block;;
        border: none;
    }
}


Бонус


Используя идею 4-го варианта, можно задавать внешние отступы для блока, и при этом последний будет адекватно отображаться в окружении скроллбаров.
Пример: jsfiddle.net/serdidg/nfqg9rza/2.

Так же можно выравнивать картинку по центру, и в случае если картинка больше родителя, масштабировать её по размеру родителя.
Пример: jsfiddle.net/serdidg/nfqg9rza/3.
Пример c большой картинкой: jsfiddle.net/serdidg/nfqg9rza/386
Serhio Magpie @SerDIDG
карма
11,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (52)

  • 0
    Забавные способы, но можно и проще, используя calc и единицы vh/vw.
    • +5
      Если уж и использовать современные фичи, то с flexbox это делается куда проще. А главное — результат получится гораздо гибче.
      • +2
        IE9…
        • 0
          Ну а для IE9 костыль jsfiddle.net/zzmm8481/
          • +1
            Этот вариант не решает проблемы, когда нужен скролл у родителя, если блок больше его.
            • +1
              И про это есть порно костыль jsfiddle.net/zzmm8481/3/
              • +4
                Ну так для чего это всё, если можно взять просто 4й вариант )
                • 0
                  Чтобы не терять размер шрифта при каждом центрировании блока.
                  • 0
                    Вы можете не ставить font-size: 0, он нужен для того, чтобы убрать пробел между родителем и блоком, допущенный при форматировании кода. Можно сделать вёрстку без пробела, либо убрать его другим способом. jsfiddle.net/serdidg/nfqg9rza/29/
                    • +3
                      font-size: 0 — самое плохое, что тут можно придумать. Верстка без пробела лучше, но не очень удобно. Самый приятный вариант, на мой взгляд — закоментировать пробелы:

                      <div class="parent"><!--
                       --><div class="block">
                              <img src="http://habrastorage.org/files/50f/7b2/1cc/" alt=""/>
                          </div>
                      </div>
                      
                      • +1
                        Где-то даже был спор как у инлайновых элементов лучше убирать отступ. Так что я не буду рекомендовать вообще ничего по этому поводу. Пусть каждый делает как ему больше нравится. ) Ваш вариант приму на заметку.

                        ПС. На больших проектах не использую наследования шрифтов, так что не испытываю проблем с font-size: 0. Всё разбито на модули, стили шрифтов в миксинах и тд.
                        • 0
                          В теории font-size: 0 вообще не должен работать, потому что у каждого браузера есть настройка, минимального размера шрифта. Но видимо этот хак настолько распространен, что разработчикам движков пришлось сделать ноль специальным случаем.
  • +10
    Есть еще CSS3 метод в три строки:
    .v-align {
    position: absolute;
    top: 50%;
    transfrom: translateY(-50%);
    }

    Устанавливаем позиционирование относитель родительского элемента, устанавливаем положение посередине (50%) и затем translateY (2D преобразование) поднимает элемент на 50% от высоты оного вверх.

    И, чтобы избежать размытия из-за расположения на «half-pixel», родительскому элементу устанавливаем параметр сохранения размеров: .parent { transform-style: preserve-3d; }
    • +4
      А как потом считать координаты внутри такого блока, например drag'n'drop и тд? На них ведь сдвиг не влияет?
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        Верно, при анимации может быть размытие. Но мы же не собираемся анимировать то, как мы центрируем блок? Это же «хак». :)
        • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            Хм, я понял что вы имеете ввиду. Если не сложно, то не могли бы поделиться более подробной информацией насчет этого бага? Буду премного благодарен.

            Я вот попытался воспроизвести описанную вами проблему (в меру своего понимания оной) и у меня все вроде бы ок — jsfiddle.net/nick_v6/d05deaw9/1/
            • НЛО прилетело и опубликовало эту надпись здесь
  • НЛО прилетело и опубликовало эту надпись здесь
    • +3
      Да, можно. Мне просто не нравится вариант с эмуляцией таблицы в принцыпе.
      • +3
        Дополнил статью примером.
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          Кому как. Из варианта 4 делается отличный миксин, и применяет по всему проекту если нужно. А таблица требует уже нужное количество нодов. К тому же часто нужно сделать вот так — jsfiddle.net/serdidg/nfqg9rza/3/, когда картинка масштабируется при уменьшении родительского блока.
  • +8
    А какого из вышепредставленных способов ещё не было на Хабре?
    (про интернет (рунет) даже спрашивать стесняюсь)
    habrahabr.ru/sandbox/62257/
    habrahabr.ru/post/189696/
    habrahabr.ru/post/73113/
    habrahabr.ru/post/71236/
    • 0
      Варианта #4, больше всего на него похож habrahabr.ru/sandbox/62257/, вот только не задача, он абсолютно не ищется по поиску.
      • +4
        Странно, а я именно в поисковике (в гугле) нашел (скрин).

        Перефразирую вопрос: Зачем плодить то, чего уже 100500 раз писалось в сети и даже на текущем ресурсе? Вот описал бы варианты из комментариев про flex, calc или transfrom, их вроде не было на Хабре.
        • +4
          Представленный вариант семантически лучше и правильнее, чем пример из песочницы.

          Плюс, здесь как-никак разжеваны стили в общих чертах, а не как в примере из песочницы: «Используем эти стили xxx:yyy.», а затем: «Та да! Магия!»
          Скажете, что знающий человек разберется — полностью соглашусь, но такие пояснения в двух словах лишними не будут.
          • 0
            Поэтому надо писать целую статью дублей, вместо простого коммита в комментариях?
            • +2
              Если рассматривать отдельно 4й вариант, то статья, увы, в песочнице и там нет комментариев, чтобы довести решение до ума.
              Варианты 1, 2, 3 добавлены для сравнения, как я понимаю.

              Я фанат дублей, но порой обсуждение тех или иных вопросов в старых статьях затухает на неопределенных моментах, а подобные дубли возобновляют обсуждение вопросов с учетом новых появившихся технологий и подходов.
              • 0
                Сорри, про комменты ступил.

                В остально несогласен в данном контексте, но холиварить думаю не стоит дальше.
                И так в оффтоп длинный.
  • +4
    css-tricks.com/centering-css-complete-guide/ — вот этой ссылки должно хватит всем. Если нет, шлите Крису PR.
    • +1
      Думаю, будет недостаточно.
      Вот обсуждение примера такого же как на css-tricks (3 вариант с неизвестными размерами) и его последствия.
    • 0
      И вот что будет, если по такому принципу сделано диалоговое окно, в котором, например, есть кастомные селекты или дейтпикеры. screencloud.net/v/cp6P
  • 0
  • –2
    Добро пожаловать в интернет.
  • +1
    Думал будет что то новое, но и не все старое есть.
  • +3
    Самый badass способ :)
    <button>
        <h1 contenteditable>Pewpew</h1>
    </button>
    

    jsfiddle.net/m8kr4o8w/
  • –2
    оффтоп:
    Вот от этого «Минусом данного способ есть ...» плачу кровью. Есть можно руками или ложкой, но не минусом.
    • +1
      Но ведь всегда можно воспользоваться личкой, если конечно смысл не показать своё превосходство в знании языка, который для меня является иностранным.
      • 0
        ок, учту
  • 0
    Так же можно выравнивать картинку по центру, и в случае если картинка больше родителя, масштабировать её по размеру родителя. Пример: jsfiddle.net/serdidg/nfqg9rza/3/.

    Странный пример. Во-первых, там картинка не больше родителя (width: auto; max-width: 100%;). Во-вторых, там почему-то у родителя стоит position: absolute; в итоге он на реальной странице оказывается наверху, а не там где надо.

    И самое печальное, попытался сделать чтобы картинка была больше родителя, но выравнять по центру не удалось. Она выравнивается по левому краю.

    Можно этот пример подправить? Чтобы посмотреть, как выравниваться, если картинка больше родителя? Например при условии, что родитель будет обрезать картинку.
    • 0
      Странный пример. Во-первых, там картинка не больше родителя (width: auto; max-width: 100%;).

      Можно уменьшить область просмотра, чтобы увидеть эффект. Начальное состояние — screencloud.net/v/7F6u, уменьшенное — screencloud.net/v/h7Wz. Обновил статью и добавил ещё пример с большой картинкой — jsfiddle.net/serdidg/nfqg9rza/386.

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

      Да, примеры сделаны не для начинающих. Если нужно на всю страницу растягивать — нужно ставить min-height: 100% на body, либо position: fixed на контейнер выравниваемого блока, тогда родитель будет занимать только область окна, а не страницы.

      И самое печальное, попытался сделать чтобы картинка была больше родителя, но выравнять по центру не удалось. Она выравнивается по левому краю.

      Если использовать стили с этого примера, любые прописанные размеры в стилях / аттрибутах для картинки могут лишить её правильных пропорций при масштабировании родителя — jsfiddle.net/serdidg/nfqg9rza/387, попробуйте окошко просмотра уменьшить по высоте и поймёте о чём я.

      Можно этот пример подправить? Чтобы посмотреть, как выравниваться, если картинка больше родителя? Например при условии, что родитель будет обрезать картинку.

      Сделал другой пример — jsfiddle.net/serdidg/nfqg9rza/386, родитель в данном примере картинку не обрезает, картинка будет пропорционально масштабироваться. А с обрезаниями, это уже совсем другая история, где используется object-fit: cover и тд.
  • –1
    а так не проще ли:
    <div id='loading' style='width: 100%; height: 100%;'>
      <div style='width: 100px; height: 40px; overflow:visible; position:absolute; left:50%; top:50%; margin-left:-50px; margin-top:-20px; text-align: center;'>
        <img src='load.gif' width='100px' height='100px'><br />Загрузка...
      </div>
    </div>
    
    Источник: bashev.ru/articles/vyravnivaem_blok_div_po_centru_ekrana
    • 0
      А вы статью читали? Там описан такой метод (Вариант 1), и почему он не подходит в ряде ситуаций, так как предполагает статически заданные размеры.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.