Към съдържанието
wannacode

Flexbox: ред и колона

Накратко: Flexbox подрежда елементите в ред или колона по главната ос, подравнява ги по напречната и дели свободното място с flex-grow.

Проблем

Шапката на три реда

Новата шапка на магазина трябва да е един ред: логото вляво, менюто до него, кошницата вдясно. На компютър обаче тя е на три реда един под друг.

HTML, CSS, JS

В CSS няма грешка. <nav> е блоков елемент, а блоковите елементи застават един под друг и всеки взима цял ред. Връзките са редови елементи и стоят на един ред с текста около тях. Затова логото е на първия ред, менюто на втория, а кошницата на третия.

Идеята

Контейнер и елементи

Нужен е друг начин да се нареждат децата на шапката. Той е display: flex на родителя:

header {
display: flex;
}
  • Елементът с display: flex е flex контейнер. Децата му (само преките деца) са flex елементи.
  • Елементите застават един до друг по главната ос. По подразбиране тя е отляво надясно. flex-direction: column я обръща отгоре надолу.
  • Перпендикулярно на нея е напречната ос.

Подреждането се казва на контейнера, а не на децата:

  • justify-content подрежда по главната ос: flex-start (в началото), center, flex-end, space-between (първият в началото, последният в края, разстоянието е между тях).
  • align-items подравнява по напречната ос: stretch (по подразбиране, всички са високи колкото реда), center, flex-start, flex-end.
  • gap слага еднакво разстояние между елементите, без отстъп преди първия и след последния.

Един елемент може да е и flex елемент, и flex контейнер. nav { display: flex; gap: 12px; } нарежда връзките в менюто, а самото меню е елемент на шапката.

Пробвай

Логото вляво, кошницата вдясно

Направи шапката на един ред: логото в левия край, кошницата в десния, менюто между тях. Ползвай justify-content. Проверката мери на колко реда са децата на <header>.

HTML, CSS, JS

Пробвай

Намери грешката

Шапката е в ред, но кошницата не отива вдясно. Защо?

Избери реда с грешката.

Идеята

Свободното място

В шапката има и поле за търсене. То трябва да взима всичкото място между логото и кошницата, колкото и широк да е екранът. Тук помагат три свойства на flex елемента:

  • flex-basis е основата: ширината на елемента, преди да се дели каквото и да е. По подразбиране е auto: ширината му (width) или колкото е съдържанието.
  • flex-grow казва колко дяла от свободното място взима елементът. По подразбиране е 0: не расте.
  • flex-shrink казва колко се свива, ако мястото не стига. По подразбиране е 1.

Браузърът смята така:

  1. Слага всеки елемент с основата му.
  2. Свободното място е ширината на контейнера минус основите и gap-овете.
  3. Дели свободното място по flex-grow и всеки елемент расте със своя дял.

Свойството flex пише трите наведнъж. flex: 1 е flex-grow: 1, flex-shrink: 1 и flex-basis: 0%: елементът расте и основата му е нула. Затова три елемента с flex: 1 стават еднакво широки, колкото и да е текстът в тях.

Виж го

Виж как се дели мястото

Лента от 600px с три елемента. Гледай сметката отгоре и зеленото свободно място.

.bar {
display: flex;
width: 600px;
gap: 20px;
}
.logo { flex-basis: 120px; }
.search { flex-basis: 100px; flex-grow: 2; }
.cart { flex-basis: 100px; flex-grow: 1; }
Стъпка по стъпка, с думи
  1. .bar е flex контейнер, широк 600px. Децата му са flex елементи: застават в ред по главната ос, отляво надясно.
  2. Първо всеки елемент получава своя flex-basis: 120, 100 и 100px. Това е ширината му, преди да се дели каквото и да е.
  3. Между три елемента има два gap по 20px. Заети са 120 + 100 + 100 + 2 × 20 = 360px.
  4. Това, което остава, е свободното място: 600 − 360 = 240px.
  5. flex-grow казва по колко дяла взима всеки: logo 0, search 2, cart 1, общо три. Един дял е 240 : 3 = 80px.
  6. Всеки расте със своите дялове: search с 160px, cart с 80px, а logo остава същото. Ширините са 120, 260 и 180px.
  7. 120 + 20 + 260 + 20 + 180 = 600: редът е пълен. Браузърът дава точно тези ширини. search не е два пъти по-широк от cart: 2 : 1 се дели само свободното място.

search е с flex-grow: 2, а cart с 1, но search не е два пъти по-широк: 260 срещу 180. Дели се само свободното място, а основите остават. Затова, когато искаш еднакви колони, основата трябва да е нула: flex: 1.

Пробвай

Търсачката взима остатъка

Логото е 120px, кошницата 110px, а шапката е до 640px. Направи полето за търсене да взима цялото място между тях. Проверката мери ширината му в пиксели: 640 − 2 × 16 (padding) − 120 − 110 − 2 × 16 (gap) = 346px.

HTML, CSS, JS

Пробвай

Едно нещо вдясно

Понякога искаш логото и менюто вляво, а само кошницата вдясно. space-between не става: тогава менюто отива в средата. Има свойство на самия елемент: margin със стойност auto взима цялото свободно място от своята страна и бута елемента.

header { display: flex; gap: 16px; }
.cart { margin-left: ; }

Пробвай

Нов ред, когато не се събират

Flex контейнерът по подразбиране държи всички елементи на един ред (flex-wrap: nowrap). Ако не се събират, той ги свива, а когато вече не може, редът излиза извън екрана. С flex-wrap: wrap елементите, които не се събират, минават на нов ред.

На телефон (360px) четирите продукта са смачкани в един ред и страницата се плъзга встрани. Направи ги по два на ред, всеки поне 150px, а двата в реда да са еднакво широки. Проверката брои редовете и колоните и мери ширината на картите.

HTML, CSS, JS

Идеята

Името, което не се свива

В кошницата името на продукта е до картинката, а до него са бройката и цената. Името е дълго. Искаме да се реже с „…“ на един ред: white-space: nowrap, overflow: hidden и text-overflow: ellipsis. Блокът с името е с flex: 1. На телефон обаче редът излиза извън екрана, а цената е смачкана:

HTML, CSS, JS

Причината е едно правило. Flex елементът не се свива под най-тясното си съдържание: min-width по подразбиране е auto, а не 0. За .info най-тясното съдържание е цялото име на един ред. min-width: 0 на flex елемента маха тази граница. Тогава .info се свива, а заглавието вътре реже текста.

Някой е добавил min-width: 0, но името пак не се реже. Кой ред е грешен?

По-точно, за любопитните

Свиване. Ако основите и gap-овете са повече от контейнера, свободното място е отрицателно и елементите се свиват. Делът не е само по flex-shrink, а по flex-shrink × основата: широкият елемент се свива повече. Лентата от сцената, но широка 280px: 120 + 100 + 100 + 40 = 360, липсват 80px. Теглата са 120, 100 и 100. logo губи 80 × 120 : 320 = 30px, а другите по 25px: 90, 75 и 75px. Елемент с flex-shrink: 0 не се свива.

Стойностите на flex. flex: 1 е 1 1 0%. flex: auto е 1 1 auto: расте, но от ширината на съдържанието си. flex: none е 0 0 auto: нито расте, нито се свива. flex: 0 0 64px е елемент с точно 64px.

Кой не се свива. Картинки и полета имат своя ширина и min-width: auto ги пази от свиване. Затова в кошницата се смачква цената (<strong>), а не картинката.

Друг начин. overflow: hidden на самия flex елемент също маха границата: елемент, който реже съдържанието си, може да се свие до 0.

Един елемент иначе. align-self подравнява само един елемент по напречната ос. order сменя мястото му на екрана, но не и в дървото: клавиатурата и екранният четец вървят по дървото. Затова не местим с order неща, които се натискат.

Редовете при wrap. align-content подрежда самите редове по напречната ос, когато контейнерът е по-висок от тях. display: inline-flex прави контейнер, който стои в текста като дума.

Упражнение

Ред в кошницата

Подреди реда в кошницата на телефон (360px): картинката, името, бройката и цената в ред, центрирани по височина, с 12px между тях. Картинката остава 64px, бройката 56px, цената 72px. Името взима останалото място (тук 108px) и е на един ред, а ако е дълго, се реже с „…“. Страницата не се плъзга встрани.

HTML, CSS, JS

Тест

Провери се

1. Искаш три продукта един до друг. На кой елемент пишеш display: flex?
2. Лента от 500px с gap: 20px има два елемента с flex-basis: 100px. Първият е с flex-grow: 1, вторият с flex-grow: 3. Колко са широки?
3. Контейнерът е с flex-direction: column. По коя ос работи justify-content?
4. Името в .info { flex: 1 } е с white-space: nowrap и text-overflow: ellipsis, но не се реже и редът излиза извън екрана. Какво липсва?

Създаден от Иво Гергов като част от кампанията на Evo Tech за достъпно обучение по програмиране ·