Главная » Статьи » Что такое flex-grow, flex-shrink и flex-basis

Что такое flex-grow, flex-shrink и flex-basis

Что такое flex-grow, flex-shrink и flex-basis

От автора: когда вы применяете свойство CSS к элементу, происходит множество вещей, невидимых на первый взгляд.

Например, допустим, у нас есть такой HTML:

<div class="parent"> <div class="child">Child</div> <div class="child">Child</div> <div class="child">Child</div>
</div>

А потом мы пишем CSS …

.parent { display: flex;
}

Технически это не один стиль, который мы применяем, когда пишем одну строку CSS выше. Фактически, здесь к элементам .child будет применен целый набор свойств, как если бы мы сами написали эти стили:

.child { flex: 0 1 auto; /* Default flex value */
}

Это странно! Почему к этим элементам применены эти дополнительные стили, хотя мы не писали этот код? Дело в том, что некоторые свойства имеют значения по умолчанию, которые мы должны изменить. И если мы случайно не знаем, что эти стили применяются при написании CSS, то наши макеты могут стать чертовски запутанными и сложными в управлении.

Свойство flex выше известно как сокращенное свойство CSS. На самом деле это всего лишь установка трех отдельных свойств CSS одновременно. То, что мы написали выше, совпадает с написанием этого:

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

Итак, сокращенное свойство объединяет множество различных свойств CSS, чтобы упростить запись нескольких свойств одновременно, точно так же, как свойство background, в котором мы можем написать что-то вроде этого:

body { background: url(sweettexture.jpg) top center no-repeat fixed padding-box content-box red; }

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

Кроме того, стили по умолчанию — это хорошо, потому что нам не нужно знать, что эти свойства flexbox делают в 90% случаев. Например, когда я использую flexbox, я обычно пишу что-то вроде этого:

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

Мне даже не нужно заботиться о дочерних элементах или о том, какие стили к ним применены, и это здорово! В этом случае мы выравниваем дочерние элементы бок о бок, а затем равномерно распределяем их в контейнере. Две строки CSS дают вам здесь много возможностей, и это лучшая особенность flexbox и этих унаследованных стилей — вам не нужно понимать всю сложность под капотом, если вы просто хотите делать то же самое в 90% случаев. Это замечательно умно, потому что вся эта сложность скрыта из виду.

Но что, если мы хотим понять, как Flexbox — в том числе свойства flex-grow, flex-shrink и flex-basis — на самом деле работают? И какие крутые вещи мы можем с ними делать?

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

.child { flex: 0 1 auto;
}

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

/* This is just how I think about the rule above in my head */ .child { flex: [flex-grow] [flex-shrink] [flex-basis];
} /* or... */ .child { flex: [max] [min] [ideal size];
}

Это первое значение равно flex-grow, 0 потому что по умолчанию мы вообще не хотим, чтобы наши элементы расширялись (большую часть времени). Вместо этого мы хотим, чтобы каждый элемент зависел от размера содержимого в нем. Вот пример:

.parent { display: flex; }

Я добавил свойство contenteditable к каждому элементу .child выше, чтобы вы могли щелкнуть по нему и ввести еще больше содержимого. Посмотрите, как он отреагирует? Это поведение элемента flexbox по умолчанию: для flex-grow установлено значение 0, потому что мы хотим, чтобы элемент увеличивался в зависимости от содержимого внутри него.

Но! Если бы мы изменили значение свойства flex-grow по умолчанию с 0 на 1, как, например…

.child { flex: 1 1 auto;
}

Затем все элементы вырастут и займут равную часть элемента .parent:

Это то же самое, что написать…

.child { flex-grow: 1;
}

… И игнорировать другие значения, потому что они все равно были установлены по умолчанию. Я думаю, что это смущало меня, когда я начал работать с гибкими макетами. Я бы увидел код, который бы просто добавил flex-grow и задался вопросом, откуда берутся другие стили. Это было похоже на приводящую в бешенство тайну убийства, которую я просто не мог разгадать.

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

.child-three { flex: 3 1 auto;
} /* or we could just write... */ .child-three { flex-grow: 3;
}

Стоит ли рассматривать этот странный код даже через десять лет после того, как flexbox появился в браузерах? Это определенно так для меня. Когда я читаю сокращенное свойство, мне нужны дополнительные усилия, чтобы сказать: «А, максимум, минимум, идеальный размер», но со временем это становится легче. В любом случае, в приведенном выше примере первые два дочерних элемента будут занимать пропорционально одинаковое количество места, но этот третий элемент будет пытаться увеличиться в три раза больше по сравнению с другими.

Здесь все становится странно, потому что все зависит от содержимого дочерних элементов. Даже если мы установим для flex-grow 3, как мы это делали в примере выше, а затем добавим больше контента, макет будет делать что-то необычное и своеобразное:

Этот второй столбец теперь занимает слишком много места! Мы вернемся к этому позже, а пока просто важно помнить, что содержимое flex-элемента влияет на то как flex-grow, flex-shrink, и flex-basis работают вместе. Хорошо, а теперь flex-shrink. Помните, что это второе значение в сокращении:

.child { flex: 0 1 auto; /* flex-shrink = 1 */
}

flex-shrink сообщает браузеру, каким должен быть минимальный размер элемента. Значение по умолчанию 1: «Всегда занимайте одинаковое количество места». Тем не менее! Если бы мы установили это значение 0 так:

.child { flex: 0 0 auto;
}

… Тогда мы говорим этому элементу, чтобы он вообще не сжимался. Оставайся того же размера, проклятый элемент! По сути, то, что говорит этот CSS, и именно это он будет делать. Мы вернемся к этому свойству чуть позже, когда посмотрим на окончательное значение в этом сокращении.

Flex-basis — это последнее значение, которое по умолчанию добавляется в сокращение flex, и именно так мы указываем элементу придерживаться идеального размера. По умолчанию установлено auto, что означает «Используй мою высоту или ширину». Итак, когда мы устанавливаем для родительского элемента display: flex…

.parent { display: flex;
} .child { flex: 0 1 auto;
}

Мы получим это по умолчанию в браузере:

Обратите внимание, что все элементы по умолчанию имеют ширину своего содержимого? Это потому, что auto говорит, что идеальный размер нашего элемента определяется его содержимым. Для того, чтобы все элементы занимали все пространство родителя, мы можем установить для дочерних элементов width: 100%, или мы можем установить для flex-basis 100%, или мы можем установить для flex-grow 1.

Имеет ли это смысл? Это странно, да! Да, если подумать. Каждое из этих сокращенных значений влияет на другое, и поэтому рекомендуется в первую очередь записать это сокращение, а не устанавливать эти значения независимо друг от друга. Хорошо, идем дальше. Когда мы пишем что-то вроде этого…

.child-three { flex: 0 1 1000px;
}

Здесь мы говорим браузеру установить значение flex-basis 1000px или: «пожалуйста, пожалуйста, просто попробуйте занять место 1000px». Если это невозможно, то элемент будет занимать столько места пропорционально другим элементам.

Вы могли заметить, что на маленьких экранах этот третий элемент на самом деле не имеет ширину 1000px! Это потому, что это действительно предложение. Мы применили flex-shrink, когда элемент сокращается до того же размера, что и другие элементы.

Кроме того, добавление большего количества контента к другим дочерним элементам по-прежнему будет иметь значение здесь:

Теперь, если бы мы хотели предотвратить сжатие этого элемента, мы могли бы написать что-то вроде этого:

.child-three { flex: 0 0 1000px;
}

Помните, что flex-shrink это второе значение здесь, и, устанавливая его на 0, мы говорим: «Никогда не сжимайся». И он не будет. Элемент даже выйдет из родительского элемента, потому что он никогда не станет короче ширины 1000px:

Теперь все это изменится, если мы установим для родительского элемента flex-wrap:

.parent { display: flex; flex-wrap: wrap;
} .child-three { flex: 0 0 1000px;
}

Мы увидим что-то вроде этого:

Это потому, что по умолчанию flex-элементы будут пытаться уместиться в одну строку, но flex-wrap: wrap полностью игнорируют это. Теперь, если эти элементы не могут уместиться в том же пространстве, они перейдут на новую строку.

В любом случае, это лишь некоторые из способов, которыми свойства flex работают друг с другом, и почему чертовски важно понимать, как эти свойства работают под капотом. Каждое из этих свойств может влиять на другое, и если вы не понимаете, как работает одно свойство, тогда вы, как бы не понимаете, как оно вообще работает — что определенно смутило меня, прежде чем я начал копаться в этом! Но подведем итог:

Попробуйте использовать сокращение flex;

При этом помните максимальный, минимальный и идеальный размер;

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

Автор: Robin Rendle

Источник: css-tricks.com

Редакция: Команда webformyself.