Flexbox tips

Подводные камни и хитрости Flexbox: проблема min-width: 0, разница flex-basis vs width, трюк с auto margins, адаптивность без media queries. Эти знания отличают новичка от уверенного разработчика.

Зачем нужно

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

Предпосылки


Проблема min-width: 0

По умолчанию flex-элемент не может быть уже своего контента (min-width: auto). Это ломает text-overflow: ellipsis.

/* ПРОБЛЕМА: текст вылезает за пределы */
.container { display: flex; width: 300px; }
.sidebar { flex: 0 0 100px; }
.content { flex: 1; }
.content p {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Не работает! Flex-элемент растягивается по контенту */
}

/* РЕШЕНИЕ: min-width: 0 */
.content {
  flex: 1;
  min-width: 0; /* Разрешить сжатие меньше контента */
}

Правило: если текст не обрезается в flex-элементе — добавь min-width: 0.

Аналог для column direction

/* При flex-direction: column */
.item {
  min-height: 0; /* Разрешить сжатие по высоте */
}

flex-basis vs width

/* flex-basis определяет размер ДО распределения пространства */
.item { flex-basis: 200px; } /* По главной оси */

/* width — всегда горизонтальный размер */
.item { width: 200px; }

/* При flex-direction: row — flex-basis ≈ width */
/* При flex-direction: column — flex-basis ≈ height */

Приоритет

  1. flex-basis (если != auto)
  2. width / height (по соответствующей оси)
  3. Контент
.item {
  width: 100px;
  flex-basis: 200px; /* Победит: 200px */
}

.item {
  width: 100px;
  flex-basis: auto; /* Используется width: 100px */
}

Auto Margins trick

margin: auto в Flexbox поглощает свободное пространство:

/* Прижать элемент вправо */
.nav { display: flex; align-items: center; }
.nav .logout { margin-left: auto; } /* Всё свободное место слева */

/* Центрирование */
.container { display: flex; }
.item { margin: auto; } /* Центр по обеим осям */

/* Разделить на группы */
.nav { display: flex; gap: 8px; }
.nav .separator { margin-left: auto; } /* Всё после — справа */
<nav class="nav">
  <a>Home</a>
  <a>About</a>
  <a class="separator">Profile</a>  <!-- margin-left: auto -->
  <a>Settings</a>
  <a>Logout</a>
</nav>
<!-- Результат: [Home About ............ Profile Settings Logout] -->

Адаптивность без media queries

/* Карточки: минимум 300px, растут, переносятся */
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}
.card {
  flex: 1 1 300px; /* Минимум 300px, растёт пропорционально */
}

/* RAM — Repeat, Auto, Minmax (лучше с Grid) */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
}

Изображения в Flexbox

/* ПРОБЛЕМА: картинка растягивается или сжимается */
.container { display: flex; }
img { /* Ведёт себя непредсказуемо */ }

/* РЕШЕНИЕ */
.container { display: flex; align-items: flex-start; }
img {
  flex-shrink: 0;    /* Не сжимать */
  max-width: 100%;   /* Не шире контейнера */
  height: auto;      /* Пропорции */
}

Gap vs Margin

/* Gap — лучше для отступов между элементами */
.container {
  display: flex;
  gap: 16px; /* Только МЕЖДУ элементами */
}

/* Margin — влияет на внешние края */
.item { margin: 8px; } /* Отступ С КАЖДОЙ стороны каждого элемента */

/* Gap + Margin: gap между, padding контейнера для внешних */
.container {
  display: flex;
  gap: 16px;
  padding: 16px;
}

Flex и абсолютное позиционирование

/* Absolute-элемент внутри flex-контейнера НЕ участвует в flex */
.container {
  display: flex;
  position: relative; /* Контекст для absolute */
}

.flex-item { flex: 1; }

.overlay {
  position: absolute; /* Выходит из flex-потока */
  inset: 0;
  background: rgba(0, 0, 0, 0.3);
}

flex: 1 vs flex: auto vs flex: none

/* flex: 1 = flex: 1 1 0 */
/* Элементы получают РАВНУЮ ширину (basis = 0) */
.equal > * { flex: 1; }

/* flex: auto = flex: 1 1 auto */
/* Элементы делят место ПРОПОРЦИОНАЛЬНО контенту */
.proportional > * { flex: auto; }

/* flex: none = flex: 0 0 auto */
/* Элемент фиксирован по контенту */
.fixed > .icon { flex: none; }
Контейнер: [====================]

flex: 1   → [======][======][======]  (равные)
flex: auto → [===][=========][====]   (по контенту + доля)
flex: none → [==][============][===]  (только по контенту)

Debugging tips

/* Визуализация flex-элементов */
.container > * {
  outline: 2px dashed red;
}

/* Chrome DevTools: кликнуть на flex-badge рядом с display: flex */
/* Firefox: Layout → Flexbox overlay */

Частые ошибки

  1. Забыт min-width: 0 — текст не обрезается, элемент растягивает контейнер

  2. flex: 1 на всех, но размеры разные — если контент разный, используйте flex: 1 1 0 для действительно равных размеров

  3. Не тот flex shorthandflex: 1 это 1 1 0, НЕ 1 1 auto

  4. order ломает доступность — tab-навигация идёт по DOM, не по visual order

  5. flex-wrap: wrap без flex-basis — элементы не переносятся, потому что basis = 0:

    /* НЕ РАБОТАЕТ как ожидается */
    .item { flex: 1; } /* basis = 0, элемент может быть шириной 0 */
    
    /* РАБОТАЕТ */
    .item { flex: 1 1 300px; } /* Минимум 300px, потом перенос */
    

Практика

  • Воспроизвести проблему min-width: 0 и решить
  • Разделить навбар на две группы через margin-left: auto
  • Создать responsive карточки без media queries (flex: 1 1 300px)
  • Сравнить flex: 1 vs flex: auto визуально

Связанные темы

Ресурсы