Способы горизонтальной центровки элементов и сжатия их ширины по контенту.

Перевод статьи:  How to shrinkwrap and center elements horizontally.
Автор:  Roger Johansson.

Если средствами CSS вы смещаете элемент, значение ширины которого не задано явно, то его ширина примет значение shrink-to-fit. Это удобно в тех случаях, когда необходимо добиться обтекания элементов, определенно не зная какой ширины они должны быть. Очень распространенным примером таких ситуаций является оформление навигационных меню, когда вам зачастую требуется чтобы значение ширины пунктов такого меню варьировалось и зависело от размера размещенного в нем текста.

Кроме того, не зная точной ширины элемента достаточно сложно выровнять его по горизонтали. Возьмите, к примеру, все туже навигационную панель. Что если в нее входят лишь несколько элементов, ширина которых ужимается (shrink-to-fit) по их контенту, но вам также необходимо сжать ширину самой навигационной панели согласно объему, занимаемому ее пунктами, а также выровнять ее по горизонтали. Добиться сжатия ширины не сложно, нужно лишь применить свойство float, но то, что касается центровки, то здесь не все так просто. Вы можете попытаться применить margin:0 auto, но поскольку для элемента, реализующего навигационное, меню ширина не задана явно, то это не даст желаемого эффекта. В этом и заключается проблема – вы не знаете точной ширины навигационного меню.

Неплохим выходом из данной ситуации была бы установка свойства float: center, но к сожалению на данный момент у нас такой возможности нет. Тем не менее, существует несколько путей решения этой проблемы. И мне удалось найти не менее пяти способов, каждый их которых использован при создании демонстрационной страницы сжатия ширины элемента и его горизонтальной центровки. Вы можете открыть ее исходный код для изучения HTML и CSS. Какой из вариантов выберите вы, зависит исключительно от вашей разметки, к тому же если хотите, можете изменить его, адаптировав под вашу ситуацию, учитывая при этом поддержку выбранного вами способа различными браузерами.

display: inline-block

Если элемент, реализующий навигационное меню имеет предка, которому вы можете назначить свойство text-align: center, то достичь желаемой цели можно применив display: inline-block. Вот необходимая для такого случая разметка:

<div class="navbar">
<ul>
<li><a href="/">Home</a></li>

</ul>
</div>

и соответствующие стили:

.navbar {
text-align:center;
}
.navbar ul {
display:inline-block;
}
.navbar li {
float:left;
}
.navbar li + li {
margin-left:20px;
}

В зависимости от конкретного дизайнерского решения вам может понадобиться дополнительно применить свойство text-align: left (или right) для правила с селектором .navbar ul.

Поддержка браузерами.

Этот подход работает практически везде. Применительно к IE, он поддерживается в IE8+ без необходимости использования хаков, и даже в IE7, если вы активируете свойство hasLayout, а для свойства display вместо значения inline-block примените inline:

.navbar ul {
display:inline;
zoom:1;
}

Для того чтобы задействовать это правило только в IE7 используйте условные комментарии или CSS хаки, по вашему усмотрению.

position: relative

Другой метод (на который указал мой коллега @martinjansson) подразумевает использование небольшого трюка, связанного со свойством position: relative, который заключается в применении двух родительских элементов. Один для позиционирования и второй для предотвращения появления горизонтальной полосы прокрутки. HTML код:

<div class="navbar">
<div>
<ul>
<li><a href="/">Home</a></li>

</ul>
</div>
</div>

и CSS код:

.navbar {
overflow:hidden;
}
.navbar > div {
position:relative;
left:50%;
float:left;
}
.navbar ul {
position:relative;
left:-50%;
float:left;
}
.navbar li {
float:left;
}
.navbar li + li {
margin-left:20px;
}

Хитрость заключается в следующем: внутренний контейнер делаем плавающим, что заставляет сузить его ширину до размера, достаточного для вмещения контента; применив относительное позиционирование, сдвигаем его вправо на 50% ширины внешнего контейнера .navbar (*то есть центруем); далее также с помощью относительного позиционирования и установки отрицательного значения -50% для свойства left возвращаем на место левую грань элемента списка. Но если ширина окна браузера будет меньше чем удвоенная ширина навигационного меню, то использование относительного позиционирования в данном случае вызовет появление горизонтального скроллбара. Для решения этой проблемы внешнему контейнеру, который предназначен для содержания плавающего дива, назначается свойство overflow: hidden.

Поддержка браузерами.

Также как и в предыдущем случае с display: inline-block, этот метод тоже работает практически везде, но для IE7 снова нужны дополнительные меры, на этот раз с целью обеспечения нормальной работы свойства overflow: hidden:

.navbar {
position:relative;
}

display: table

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

<ul class="navbar">
<li><a href="/">Home</a></li>

</ul>

Таблицам свойственно автоматически подстраивать свою ширину под объем контента, а их центровка с помощью значения auto для полей возможна без явного указания значения ширины таблицы. Вот соответствующий CSS код:

.navbar {
display:table;
margin:0 auto;
}
.navbar li {
display:table-cell;
}
.navbar li + li {
padding-left:20px;
}
Поддержка браузерами.

Этот метод (собственно, как и все остальные, связанные с установкой display: table) не работает в IE7 и ниже, но работает в остальных браузерах. В крайнем случае, можно как-нибудь смириться с дефектами отображения шаблона сайта в IE7- или обойти данную проблему с помощью плавающих <ul> и <li> элементов, форматируемых в рамках целевых CSS правил для IE7 и ниже.

width: fit-content/intrinsic

Следующий способ, о котором писал Каталин Росу в своей статье Выравнивание по горизонтали с помощью CSS свойства fit-content, подразумевает использование установки width: fit-content.

Ключевое слово fit-content описано в разделе CSS Intrinsic & Extrinsic Sizing Module Level 3 (*Модуль внутренних и внешних размеров. Уровень 3.) спецификации.

Как и в случае с display: table, этот способ тоже не нуждается в дополнительном элементе контейнере:

<ul class="navbar">
<li><a href="/">Home</a></li>

</ul>

Подгонка ширины по контенту добивается путем установки ширины элемента списка <ul> в значение fit-content (с вендорными префиксами для Firefox и Chrome). В Safari для этих целей используется нестандартное ключевое слово intrinsic, что, возможно, тоже должно быть учтено в вашем коде. Определив ширину элемента согласно его контента, установкой для левого и правого поля значения auto добиваемся центровки элемента по горизонтали:

.navbar {
width:intrinsic; /* для Safari, детали на https://developer.mozilla.org/en-US/docs/CSS/width */
width:-moz-fit-content;
width:-webkit-fit-content;
width:fit-content;
margin:0 auto;
overflow:hidden; /* для содержания плавающего li элемента */
}
.navbar > li {
float:left; /* в качестве альтернативы здесь вы можете использовать display: inline-block */
}
.navbar li + li {
margin-left:20px;
}
Поддержка браузерами.

На данный момент достойной поддержки для этого метода нет, единственное, на что вы можете рассчитывать, так это на его работу в Firefox, Safari и последних версиях Chrome. Насколько мне известно, поддержки в IE и Opera пока нет.

display:inline-flex

И последний способ подразумевает использование модуля flex layout, а точнее значения display: inline-flex. Этот метод довольно схож с одним из описанных выше, использующим определение display: inline-block и поэтому необходимый для них HTML код одинаков:

<div class="navbar">
<ul>
<li><a href="/">Home</a></li>

</ul>
</div>

CSS код (с вендорными префиксами и комбинацией старого и нового flexbox синтаксиса):

.navbar {
text-align:center;
}
.navbar > ul {
display:-webkit-inline-box;
display:-moz-inline-box;
display:-ms-inline-flexbox;
display:-webkit-inline-flex;
display:inline-flex;
}
.navbar li + li {
margin-left:20px;
}
Поддержка браузерами.

Этот подход также подразумевает повышенные требования к браузеру, но тем не менее, поддержка этого способа несколько лучше чем в случае с fit-content. Все же при его использовании на данный момент необходимо применять вендорные префиксы во всех браузерах за исключением Opera 12.1, он так же не работает в IE9 и ниже. Вы можете взглянуть на детальную информацию касательно поддержки модуля Flexible Box Layout различными браузерами.

Какой из способов выбрать?

Глядя на такое разнообразие вариантов трудно определиться с выбором. Хотя вы, вероятно, знаете ответ – все зависит от обстоятельств. Тем не менее, метод, использующий конструкцию display:inline-block, на мой взгляд, является наиболее предпочтительным с точки зрения поддержки браузерами и с учетом того, что при этом вы можете воспользоваться свойством white-space для контроля переноса содержания навигационного меню на следующую строку, в случае если его ширина превосходит доступную ширину окна браузера. Для решения затрагиваемой в статье проблемы вы можете воспользоваться конструкцией flex-wrap: wrap, но в этом случае не рассчитывайте на такой же уровень поддержки браузерами.

Если вы все еще не определились, то, по крайней мере, у вас есть из чего выбирать (и этот список может быть расширен). Надеюсь, что один из представленных здесь способов поможет в вашем конкретном случае.

* Примечание переводчика.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *