В CSS есть ключевое слово auto, которое можно использовать при работе с различными свойствами элементов. Это — свойства, влияющие на позицию, высоту, ширину элементов. Это — свойства, предназначенные для настройки отступов элементов и других их характеристик. У меня появилось желание где-нибудь записать всё то, что я знаю об auto. Например — оформить это всё в виде материала, который мог бы стать справочником для тех, кто интересуется тонкостями использования этого ключевого слова.

Ключевое слово auto имеет особый смысл при использовании его с различными CSS-свойствами. Мы разберём особенности auto, касающиеся применения этого значения к различным свойствам.



Здесь, в первую очередь, нас будут интересовать технические детали работы auto. Поговорим мы и о том, как извлечь максимум пользы из применения этого свойства. Тут вы найдёте и заметки о сценариях использования auto, и примеры.

Свойство width: auto


Исходной шириной блочных элементов, таких, как <div> или <p>, является значение auto. Это приводит к тому, что такие элементы занимают всё горизонтальное пространство содержащего их блока.

«Ширина блока, содержащего элемент» — это, в соответствии со спецификацией CSS, значение, вычисляемое по следующей формуле:

‘margin-left’ + ‘border-left-width’ + ‘padding-left’ + ‘width’ + ‘padding-right’ + ‘border-right-width’ + ‘margin-right’

Когда ширина элемента задана значением auto, у него могут быть настроены такие свойства, как margin, padding, border, и он, при этом, не будет больше своего род��тельского элемента. Шириной блока, ограничивающего содержимое блочного элемента, будет размер содержимого за вычетом ширины его частей, задаваемых свойствами margin (поле, внешний отступ), padding (внутренний отступ) и border (граница).


Сравнение width: auto и width: 100%

Рассмотрим, в качестве примера, особенности устройства вышеприведённых макетов.

Вот HTML-разметка:

<div class="wrapper">
  <div class="item"></div>
</div>

Вот CSS-код:

* {
    box-sizing: border-box;
}

.wrapper {
      max-width: 600px;
      margin: 2rem auto 0;
      padding: 1rem;
}

.item {
      padding: 1rem;
      margin: 0 50px;
      border: 15px solid #1f2e17;
}

Тут всё выглядит как надо, содержимое ограничено родительским элементом.


Элемент находится в пределах родительского элемента

А что произойдёт в том случае, если указать, что ширина элемента (width) должна быть задана не в виде значения auto, а как 100%? При таком подходе элемент займёт 100% ширины родительского элемента, к которой будет добавлено пространство, отводимое на правое и левое поля. Вот соответствующий стиль:

.item {
      width: 100%;
      padding: 1rem;
      margin: 0 50px;
      border: 15px solid #1f2e17;
}

А вот что получится после его применения к элементу.


Элемент выходит за пределы родительского элемента (направление текста — ltr)

Ширина элемента составляет 568px. Она вычисляется так:

‘border-left-width’ + ‘padding-left’ + ‘width’ + ‘padding-right’ + ‘border-right-width’ = 15 + 16 + 506 + 16 + 15 = 568px

Если свойство direction установлено в значение ltr, то значение margin-right будет полностью игнорироваться. В нашем случае именно это и происходит. Однако если в direction записано rtl, игнорироваться будет margin-left.


Элемент выходит за пределы родительского элемента (направление текста — rtl)

Здесь можно поэкспериментировать с кодом примера.

▍Сценарии использования width: auto


Для того чтобы как следует разобраться со значением auto, недостаточно рассказа об основах. Поэтому я провёл некоторые изыскания, направленные на то, чтобы показать сценарии практического использования свойства width: auto.

Разная ширина элементов в мобильной и настольной версиях страницы



Мобильный и настольный варианты приложения

Имеется группа кнопок. Нужно, чтобы в мобильной версии приложения они были бы расположены рядом друг с другом (элемент, заключающий в себе кнопку, должен занимать 50% родительского элемента). В настольной версии приложения каждая кнопка должна занимать всю ширину контейнера-родителя. Как это сделать?

Вот HTML-разметка:

<div class="group">
    <div class="group__item">
        <button class="c-button">Sign In</button>
    </div>
    <div class="group__item">
        <button class="c-button c-button--ghost">Register</button>
    </div>
</div>

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

.group {
    display: flex;
}

.group__item {
    width: 50%;
}

В настольной версии мне нужно, чтобы кнопки занимали бы всю ширину родительского элемента. Тут может возникнуть соблазн использовать конструкцию width: 100%. Правда? Но есть и более удачное решение:

@media (min-width: 800px) {
    /* Преобразуем обёртку из flexbox-элемента в блочный элемент */
    .group {
        display: block;
    }

    .group__item {
        width: auto;
    }
}

Так как .group__item — это блочный элемент, использование width: auto приводит к тому, что этот элемент отлично заполняет собой место, доступное в его родительском элементе.

Вот рабочий вариант этого примера.

Свойство height: auto


Если рассматривать работу со свойством height, задающим высоту элементов, то всё выглядит иначе. Высота элемента, при применении значения auto, соответствует высоте содержимого элемента.

Рассмотрим следующий пример:

<div class="wrapper">
  <div class="item">What's my height?</div>
</div>

Для того чтобы элемент с классом .item занял бы всю высоту контейнера, можно воспользоваться одним из следующих приёмов:

  1. Можно задать элементу с классом .wrapper фиксированную высоту, а затем добавить к стилю элемента .item свойство height: 100%.
  2. Можно воспользоваться для элемента .wrapper flexbox-макетом, благодаря чему дочерний элемент .item будет, по умолчанию, растянут до размеров родительского элемента.

Вот CSS-код:

.wrapper {
    height: 200px;
}

.item {
    height: 100%;
}


Родительский и дочерний элементы

Поля и ключевое слово auto


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

Рассмотрим пример.


Элемент, который надо выровнять по центру

Синий прямоугольник нуждается в горизонтальном выравнивании по центру. Для этой цели можно воспользоваться следующим стилем:

.element {
    margin-left: auto;
    margin-right: auto;
}

Обратимся к спецификации CSS:

Если свойства ‘margin-left’ и ‘margin-right’ установлены в значение ‘auto’, ширина полей оказывается одинаковой. Это приводит к горизонтальной центровке элемента относительно краёв включающего его в себя блока.


Поля элемента имеют одинаковую ширину

Вот демонстрация этого примера.

▍Использование свойства margin: auto для абсолютно позиционированных элементов



Центрованный элемент

Ещё один, менее распространённый, сценарий применения значения auto заключается в центровке абсолютно позиционированных элементов с использованием конструкции margin: auto. Если имеется элемент, который нужно отцентровать внутри родительского элемента и по горизонтали, и по вертикали, может показаться, что для этого надо воспользоваться свойством translateX или translateY.

Для того чтобы свойство margin: auto позволило бы нам соответствующим образом выровнять элемент, нужно, чтобы были бы выполнены следующие условия:

  1. Заданы ширина и высота элемента.
  2. Задано свойство элемента position: absolute.

Вот HTML-разметка:

<div class="wrapper">
  <div class="item">I am centered.</div>
</div>

Вот код стилей:

.wrapper {
    position: relative;
}

.item {
    width: 200px;
    height: 100px;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}

Вот демонстрация этой методики выравнивания элементов.

Flexbox-макеты и автоматическая настро��ка полей


Использование автоматически настраиваемых полей может, в некоторых случаях, оказаться весьма полезным приёмом. Если дочерний элемент имеет поле, размеры которого заданы с использованием значения auto, он, в родительском элементе, будет максимально смещён в сторону, противоположную настроенному полю. Например, если flex-элементу назначено свойство margin-left: auto, он будет максимально смещён вправо.

Посмотрим на следующий макет. Тут есть два прямоугольных дочерних элемента, находящихся в родительском flexbox-элементе.


Пара элементов во flexbox-контейнере

Нам нужно, чтобы элемент №2 был бы перемещён к правой границе контейнера. Для этого отлично подходит использование значения auto для свойства margin-left:

.wrapper {
    display: flex;
}

.item-2 {
    margin-left: auto;
}

Вот что получилось после применения такого стиля.


Элемент №2 перемещён к правому краю контейнера

Надо отметить, что этот приём работает и при вертикальном выравнивании элементов. Применим в данном примере следующий стиль элемента №2:

.item-2 {
    margin-top: auto;
}

Вот что получится.


Элемент №2 перемещён к нижнему краю контейнера

Кроме того, если имеется лишь один дочерний элемент, то для того, чтобы выровнять его и по горизонтали, и по вертикали, можно воспользоваться свойством margin: auto. Предположим, в контейнере имеется лишь элемент №1, который нужно выровнять именно так. Для этого воспользуемся таким стилем:

.item-1 {
    margin: auto;
}

Этого достаточно для центровки элемента.


Элемент №1 выровнен по центру контейнера

▍Свойство flex и значение auto


При разработке flexbox-макетов можно пользоваться, для дочерних элементов, свойством flex: auto. Что означает подобная конструкция? Дело в том, что когда у дочернего элемента имеется свойство flex: auto, это равносильно тому, что элементу назначен стиль flex: 1 1 auto, аналогичный следующей конструкции:

    .item {
        flex-grow: 1;
        flex-shrink: 1;
        flex-basis: auto;
    }

Вот что об этом сказано на MDN: «Размеры элемента определяются в соответствии с его свойствами width и height, но элемент может растягивается, занимая дополнительное свободное пространство, доступное во flex-контейнере. Элемент, для того, чтобы поместиться в контейнер, может и сжимается до своего минимального размера. Это аналогично установке стиля flex: 1 1 auto».

Другими словами, размер элемента со свойством flex: auto будет задан, основываясь на его ширине и высоте. Но этот элемент может растягиваться или сжиматься в зависимости от того, какое пространство доступно ему в контейнере. Я об этом не знал до тех пор, пока не занялся исследованиями для этой статьи.

Как обычно, рассмотрим пример.

Вот разметка:

<div class="wrapper">
  <div class="item item-1">Item</div>
  <div class="item">Item</div>
  <div class="item">Item</div>
</div>

Вот стили:

.wrapper {
    display: flex;
    flex-wrap: wrap;
}

.item {
    width: 120px;
    height: 500px;
}

.item-1 {
    flex: auto;
}

А вот — результат.


Использование flex: auto

Вот рабочий вариант этого примера.

Grid-макеты и значение auto


▍Использование значения auto при настройке столбцов



Использование стиля grid-template-columns: auto 1fr 1fr

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

.wrapper {
    display: grid;
    grid-template-columns: auto 1fr 1fr;
}

▍Grid-макеты и использование значения auto для настройки полей


При использовании Grid-макетов значение auto может быть использовано для настройки полей элементов. Делается это для получения результатов, похожих на те, что достигались при использовании auto во Flexbox-макетах. Если мы работаем с Grid-макетом, и один из элементов сетки имеет, например, стиль margin-left: auto, он будет перемещён в правую часть макета, а его ширина будет подобрана на основе размеров его содержимого.

Рассмотрим следующий пример.


Grid-макет

Нам нужно, чтобы ширина элемента Item 1 зависела бы от его содержимого, а не от доступного ему пространства сетки. Для этого мы можем воспользоваться следующим стилем:

    .item-1 {
        margin-left: auto;
    }

Вот результат применения этого стиля.


Ширина элемента зависит от его содержимого

▍RTL-макеты


Стоит отметить, что использование свойств margin-left: auto или margin-right: auto хорошо показывает себя для LTR-макетов (для макетов, в которых содержимое расположено слева направо), например, для таких, которые используются для вывода текстов, написанных на английском. Но знайте о том, что на многоязычных сайтах эти значения меняются местами. Ещё лучше, и я бы порекомендовал поступать именно так, пользоваться в таких макетах Flexbox- или Grid-свойствами, делая это в тех случаях, когда поставленной цели можно достичь с их помощью. Если этого с помощью таких свойств добиться нельзя, прибегайте к настройке margin-свойств с использованием auto только в крайнем случае. Вместо них лучше применять логические свойства CSS.

Свойство overflow


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

Для решения этой задачи можно попытаться воспользоваться следующим стилем:

.element {
    overflow-y: scroll;
}

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


Элемент, которому назначен стиль overflow-y: scroll

В браузере Chrome на платформе Windows полоса прокрутки выводится всегда. Это — пример неправильного поведения элемента, которое способно запутать пользователя.

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

На MDN об этом сказано следующее: «Зависит от пользовательского агента. Если содержимое помещается в область элемента, соответствующую внутреннему пространству элемента, оно выглядит так же, как содержимое, выводимое в режиме visible, но при этом создаётся новый блочный контекст форматирования. Настольные браузеры выводят полосы прокрутки в том случае, если размеры содержимого превышают размеры элемента».

Свойства, отвечающие за позиционирование элементов


CSS-свойства, отвечающие за позиционирование элементов, такие, как top, right, bottom и left, поддерживают значение auto. То, о чём я хочу сейчас рассказать, я узнал в ходе написания этой статьи.

Рассмотрим следующий макет.


Демонстрационный макет

Здесь имеется родительский элемент с настроенным свойством padding, задающим внутренний отступ. В этом элементе расположен ещё один элемент, дочерний. Дочерний элемент позиционирован абсолютно, но его свойства, отвечающие за позиционирование, не настроены. Вот стили:

.wrapper {
    position: relative;
    padding: 16px;
}

.item {
    position: absolute;
    width: 100px;
    height: 100px;
}

Дело в том, что в CSS у каждого свойства имеется некое исходное значение (значение, задаваемое по умолчанию). Если исследовать дочерний элемент и взглянуть на вычисленные стили, то каким будет значение его свойства left?


Исследование вычисленных стилей дочернего элемента

Значение, задаваемое по умолчанию для свойства left — это 16px. Откуда оно взялось, если мы его даже не задавали? Причина этого заключается в том, что свойства абсолютно позиционированного элемента согласуются с его ближайшем родителем, у которого задано свойство position: relative. У родительского элемента есть свойство padding: 16px. Это приводит к тому, что дочерний элемент размещается в 16 пикселях от верхней и левой сторон родительского элемента. Интересно, правда?

Теперь у вас может появиться вопрос о том, какая нам от этого польза. Предлагаю с этим разобраться.

Представим, что дочерний элемент надо разместить в 100px от левой границы родительского элемента при просмотре страницы на маленьких экранах, а на больших экранах можно разместить элемент там, где он располагался бы при применении значений, задаваемых по умолчанию.

Вот стиль, подходящий для маленьких экранов:

.wrapper {
    position: relative;
}

.item {
    position: absolute;
    left: 100px;
    width: 100px;
    height: 100px;
}

Как сбросить значение свойства left при просмотре страницы на больших экранах? Причём, значение left: 0 тут использовать нельзя, так как это приведёт к тому, что дочерний элемент прижмётся к краю родительского элемента, а нам это не нужно. Взгляните на макет страницы, показанный ниже. Он разъясняет мою мысль.


Дочерний элемент ведёт себя неправильно

Для сброса свойств позиционирования дочернего элемента следует использовать конструкцию left: auto. На MDN об этом говорится следующее: «Элемент размещается по горизонтали так, как он должен был бы быть позиционирован в том случае, если бы был статическим элементом».

Это означает, что при размещении элемента будет учитываться свойство padding родительского элемента, и будет обеспечиваться то, что дочерний элемент не «прилипнет» к краю родительского элемента.

Вот CSS-код:

.item {
    position: absolute;
    left: 100px;
    width: 100px;
    height: 100px;
}

@media (min-width: 800px) {
    .item {
        /* Это - эквивалент left: 16px */
        left: auto;
    }
}

То же самое применимо и к свойству top. Вычисленные значения свойств right и bottom, задаваемые по умолчанию, эквивалентны, соответственно, ширине и высоте элемента.

Вот демонстрационный проект к этому разделу.

Примеры использования значения auto


Сразу скажу, что приведённые здесь примеры не охватывают всех возможностей значения auto, но я надеюсь, что то, о чём я расскажу, вам пригодится.

▍Стрелка всплывающей подсказки


При создании всплывающих подсказок нужно, чтобы у них была бы стрелка, указывающая на тот объект, к которому относится подсказка. Так эти подсказки оказываются более понятными. В том случае, если мы занимаемся разработкой дизайн-системы, нам нужно предусмотреть разные состояния подсказок. Например, подсказки со стрелкой, указывающей налево, и со стрелкой, указывающей направо.


Стрелки подсказок, направленные в разных направлениях

.tooltip:before {
    /* Код стрелки */
    position: absolute;
    left: -15px;
}

/* Версия подсказки со стрелкой, направленной вправо */
.tooltip.to-right:before {
    /* Код стрелки */
    position: absolute;
    left: auto;
    right: -15px;
}

Обратите внимание на то, что я воспользовался свойством left: auto для переопределения свойства left: -15px в исходной реализации. И, чтобы вы знали, подобное используется весьма часто. Поэтому я порекомендовал бы вместо вышеописанного подхода пользоваться следующим:

.tooltip:before {
    position: absolute;
    right: 100%;
}

.tooltip.to-right:before {
    /* Код стрелки */
    position: absolute;
    right: auto;
    left: 100%;
}

Используя значение 100%, мы уходим от применения жёстко заданного значения (ширины стрелки), которое может привести к неправильной работе системы в том случае, если изменится размер стрелки. Это решение лучше приспособлено к возможным будущим изменениям.

▍Компонент-карточка


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


Компонент-карточка со значком, который расположен в разных углах

Используя свойство left: auto можно легко сбросить значение свойства, заданного в его базовой реализации. Вот CSS-код:

.card .icon {
    position: absolute;
    left: 15px;
    top: 15px;
}

.card.is-right .icon {
    left: auto;
    right: 15px;
}

▍Flexbox-макеты и значение auto свойства margin


Flexbox-макеты дают веб-разработчику поистине безграничные возможности. Комбинируя возможности таких макетов с полями, при настройке которых используется значение auto, мы можем создавать весьма мощные макеты.

Рассмотрим следующий пример.


Автоматическая настройка полей элементов

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

Вот разметка:

<div class="item">
    <div class="item-group">
        <!-- Заголовок и описание -->
    </div>
    <button class="item__action">Confirm</button>
</div>

Вот стили:

    .item {
        display: flex;
        flex-wrap: wrap;
        justify-content: space-between;
    }

    .item__action {
        margin-left: auto;
    }

Готово! Использование свойства margin-left: auto позволяет поместить кнопку в правом верхнем углу элемента. А ещё приятнее то, что мы можем воспользоваться логическими CSS-свойствами в том случае, если разрабатываем многоязычный сайт. CSS-код будет примерно таким:

.item__action {
    margin-inline-start: auto;
}

Если вы хотите больше узнать о RTL-стилизации — вот полезный ресурс, посвящённый этой теме.

▍Grid-макеты и значение auto свойства margin


Настраивая поля Grid-элементов, можно задавать фиксированные и процентные значения, а также — можно пользоваться значением auto. Меня особенно интересует значение auto. Взгляните на следующий макет.


Grid-макет

Вот фрагмент разметки:

<p class="input-group">
    <label for="">Full Name</label>
    <input type="email" name="" id="">
</p>

Вот — стили:

.input-group {
  display: grid;
  grid-template-columns: 1fr;
  grid-gap: 1rem;

  @media (min-width: 700px) {
    grid-template-columns: 0.7fr 2fr;
  }
}

Мне хотелось бы выровнять подписи, элементы label, по левому краю полей для ввода данных (элементов input). Для того чтобы это сделать, нужно применить следующий стиль:

.input-group label {
    margin-left: auto;
}

Применение этого стиля приведёт к результату, показанному на следующем рисунке.


Выравнивание подписей по левому краю полей для ввода данных

▍Проектирование модальных окон



Модальное окно

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

.modal-body {
    overflow-y: auto;
}

Благодаря такому стилю полоса прокрутки появится только в том случае, если содержимое окна окажется достаточно большим.

Итоги


В этом материале мы рассмотрели особенности применения ключевого слова auto в CSS. Надеемся, вам пригодится то, о чём вы сегодня прочли.

Уважаемые читатели! В каких ситуациях вы пользуетесь значением auto в CSS?