Въведение в модерния CSS Layout

CSS Grid и Flexbox революционизираха начина, по който създаваме layouts в уеб разработката. Тези две технологии решиха проблеми, които мъчиха разработчиците с десетилетия - от хакове с floats до таблици за layout. В тази статия ще научите кога и как да използвате всяка от тях.

CSS Layout

Flexbox vs Grid: Кога кое да използваме?

┌─────────────────────────────────────────────────────────────────────────────┐
│                    FLEXBOX vs GRID - КОГА КОЕ?                               │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│                    FLEXBOX                      GRID                        │
│              (1 измерение)              (2 измерения)                       │
│                                                                             │
│    ┌───┬───┬───┬───┬───┐         ┌───┬───┬───┬───┐                         │
│    │ 1 │ 2 │ 3 │ 4 │ 5 │         │ 1 │ 2 │ 3 │ 4 │                         │
│    └───┴───┴───┴───┴───┘         ├───┼───┼───┼───┤                         │
│    Един ред или колона           │ 5 │ 6 │ 7 │ 8 │                         │
│                                   ├───┼───┼───┼───┤                         │
│    ┌───┐                          │ 9 │10 │11 │12 │                         │
│    │ 1 │                          └───┴───┴───┴───┘                         │
│    ├───┤                          Редове И колони                           │
│    │ 2 │                                                                    │
│    ├───┤                                                                    │
│    │ 3 │                                                                    │
│    └───┘                                                                    │
│                                                                             │
│  ИЗПОЛЗВАЙ FLEXBOX ЗА:           ИЗПОЛЗВАЙ GRID ЗА:                        │
│  ✓ Navigation меню               ✓ Page layout                             │
│  ✓ Buttons с икона               ✓ Card grids                              │
│  ✓ Центриране на елемент         ✓ Form layouts                            │
│  ✓ Footer с распределени items   ✓ Dashboard layouts                       │
│  ✓ Toolbar с actions             ✓ Complex magazine layouts                │
│                                                                             │
│  Накратко: Flexbox за компоненти, Grid за layout                           │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

CSS Flexbox в детайли

Основни концепции

┌─────────────────────────────────────────────────────────────────────────────┐
│                        FLEXBOX AXES                                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  flex-direction: row (default)                                              │
│                                                                             │
│        Main Axis (justify-content) ──────────────────────►                 │
│                                                                             │
│    ┌─────────────────────────────────────────────────────────┐             │
│    │                                                         │  ▲          │
│  C │  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐   │  │          │
│  r │  │  Item   │  │  Item   │  │  Item   │  │  Item   │   │  │ Cross    │
│  o │  │    1    │  │    2    │  │    3    │  │    4    │   │  │ Axis     │
│  s │  └─────────┘  └─────────┘  └─────────┘  └─────────┘   │  │          │
│  s │                                                         │  │ (align-  │
│    └─────────────────────────────────────────────────────────┘  ▼ items)   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Container свойства

.flex-container {
  display: flex; /* или inline-flex */
  
  /* Посока на main axis */
  flex-direction: row;           /* → (default) */
  flex-direction: row-reverse;   /* ← */
  flex-direction: column;        /* ↓ */
  flex-direction: column-reverse;/* ↑ */
  
  /* Обвиване при нужда */
  flex-wrap: nowrap;   /* всичко на един ред (default) */
  flex-wrap: wrap;     /* обвий на нов ред */
  flex-wrap: wrap-reverse; /* обвий нагоре */
  
  /* Shorthand */
  flex-flow: row wrap;
  
  /* Подравняване по main axis */
  justify-content: flex-start;    /* ├──────────────────────── */
  justify-content: flex-end;      /* ──────────────────────┤ */
  justify-content: center;        /* ─────────┼─────────── */
  justify-content: space-between; /* ├────────┼────────┤ */
  justify-content: space-around;  /* ──├────┼────┼────┼────├── */
  justify-content: space-evenly;  /* ├──┼──┼──┼──┼──┤ */
  
  /* Подравняване по cross axis */
  align-items: stretch;    /* разтегли (default) */
  align-items: flex-start; /* горе */
  align-items: flex-end;   /* долу */
  align-items: center;     /* център */
  align-items: baseline;   /* по baseline на текста */
  
  /* Gap между items */
  gap: 16px;         /* еднакъв gap */
  gap: 16px 24px;    /* row-gap column-gap */
}

Item свойства

.flex-item {
  /* Растеж - колко от свободното пространство да заеме */
  flex-grow: 0;   /* не расте (default) */
  flex-grow: 1;   /* расте пропорционално */
  flex-grow: 2;   /* расте 2x повече от flex-grow: 1 */
  
  /* Свиване - колко да се свие ако няма място */
  flex-shrink: 1;  /* свива се (default) */
  flex-shrink: 0;  /* не се свива никога */
  
  /* Базов размер преди flex */
  flex-basis: auto;  /* използва width/height */
  flex-basis: 200px; /* започва от 200px */
  flex-basis: 0;     /* игнорира съдържанието */
  
  /* Shorthand */
  flex: 0 1 auto;  /* grow shrink basis (default) */
  flex: 1;         /* flex: 1 1 0% - равномерно растене */
  flex: auto;      /* flex: 1 1 auto */
  flex: none;      /* flex: 0 0 auto - твърд размер */
  
  /* Индивидуално подравняване */
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
  
  /* Пренареждане */
  order: 0;   /* default */
  order: -1;  /* преди останалите */
  order: 1;   /* след останалите */
}

Практически примери с Flexbox

1. Navigation меню

.nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
}

.nav__logo {
  flex-shrink: 0;
}

.nav__links {
  display: flex;
  gap: 2rem;
}

.nav__actions {
  display: flex;
  gap: 1rem;
}

2. Card с footer винаги долу

.card {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.card__content {
  flex: 1; /* заема останалото пространство */
}

.card__footer {
  /* винаги остава долу */
  margin-top: auto;
}

3. Перфектно центриране

.centered {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

CSS Grid в детайли

Основни концепции

┌─────────────────────────────────────────────────────────────────────────────┐
│                          CSS GRID ANATOMY                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│     Column 1    Column 2    Column 3    Column 4                           │
│        │           │           │           │                                │
│    ┌───▼───────────▼───────────▼───────────▼───┐  ◄── Grid Line 1         │
│    │       │       │       │       │       │   │                           │
│ R  │   1   │   2   │   3   │   4   │  ←Track   │  ◄── Grid Line 2         │
│ o  │       │       │       │       │   (ред)   │                           │
│ w  ├───────┼───────┼───────┼───────┼───────────┤  ◄── Grid Line 3         │
│    │       │               │       │           │                           │
│ 1  │   5   │    Grid       │   7   │           │                           │
│    │       │    Area       │       │           │                           │
│    ├───────┤   (6 заема    ├───────┤           │  ◄── Grid Line 4         │
│ R  │       │   2 клетки)   │       │           │                           │
│ o  │   8   │               │   9   │    10     │                           │
│ w  │       │               │       │  (spans   │                           │
│    └───────┴───────────────┴───────┴──2 rows)──┘  ◄── Grid Line 5         │
│ 2  │                                                                       │
│    ▲       ▲               ▲       ▲           ▲                           │
│  Line 1  Line 2         Line 3  Line 4      Line 5                         │
│                                                                             │
│  Gap ────────────►  ◄────── Cell (клетка)                                  │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

Container свойства

.grid-container {
  display: grid; /* или inline-grid */
  
  /* Дефиниране на колони */
  grid-template-columns: 200px 200px 200px;      /* 3 колони по 200px */
  grid-template-columns: 1fr 1fr 1fr;             /* 3 равни колони */
  grid-template-columns: 1fr 2fr 1fr;             /* средната е 2x */
  grid-template-columns: repeat(3, 1fr);          /* shorthand за 3 равни */
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* responsive! */
  
  /* Дефиниране на редове */
  grid-template-rows: 100px auto 100px;  /* header, content, footer */
  
  /* Автоматични редове (за items извън template) */
  grid-auto-rows: minmax(100px, auto);
  
  /* Gap */
  gap: 16px;           /* еднакъв gap */
  row-gap: 16px;       /* само между редове */
  column-gap: 24px;    /* само между колони */
  
  /* Подравняване на items в клетките */
  justify-items: start | end | center | stretch;
  align-items: start | end | center | stretch;
  place-items: center; /* shorthand */
  
  /* Подравняване на целия grid в контейнера */
  justify-content: start | end | center | space-between | space-around;
  align-content: start | end | center | space-between | space-around;
  place-content: center; /* shorthand */
}

Grid Template Areas

.page-layout {
  display: grid;
  grid-template-columns: 250px 1fr 300px;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header  header  header"
    "sidebar content aside"
    "footer  footer  footer";
  min-height: 100vh;
  gap: 20px;
}

.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.aside   { grid-area: aside; }
.footer  { grid-area: footer; }

Визуализация:

┌─────────────────────────────────────────────────────────┐
│                        HEADER                           │
├──────────────┬─────────────────────────┬───────────────┤
│              │                         │               │
│   SIDEBAR    │        CONTENT          │    ASIDE      │
│   (250px)    │         (1fr)           │   (300px)     │
│              │                         │               │
├──────────────┴─────────────────────────┴───────────────┤
│                        FOOTER                           │
└─────────────────────────────────────────────────────────┘

Item свойства

.grid-item {
  /* Позициониране по линии */
  grid-column-start: 1;
  grid-column-end: 3;     /* от линия 1 до линия 3 */
  grid-column: 1 / 3;     /* shorthand */
  grid-column: 1 / span 2; /* от 1, span 2 колони */
  grid-column: 1 / -1;    /* от първата до последната */
  
  grid-row-start: 1;
  grid-row-end: 3;
  grid-row: 1 / 3;
  
  /* Shorthand за двете */
  grid-area: 1 / 1 / 3 / 3; /* row-start / col-start / row-end / col-end */
  grid-area: header;         /* или named area */
  
  /* Индивидуално подравняване */
  justify-self: start | end | center | stretch;
  align-self: start | end | center | stretch;
  place-self: center; /* shorthand */
}

Responsive Grid без Media Queries

/* Магията на auto-fit и minmax */
.responsive-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 24px;
}

/*
  Как работи:
  - auto-fit: създава колкото колони се събират
  - minmax(300px, 1fr): минимум 300px, максимум 1fr
  
  Резултат:
  - На широк екран: 4+ колони
  - На среден екран: 2-3 колони
  - На мобилен: 1 колона
  
  Всичко това БЕЗ media queries!
*/

Subgrid (CSS Grid Level 2)

.parent-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}

.child-that-spans {
  grid-column: span 2;
  
  display: grid;
  /* Наследява линиите от родителя */
  grid-template-columns: subgrid;
}

Комбиниране на Grid и Flexbox

/* Grid за page layout */
.page {
  display: grid;
  grid-template-columns: 1fr min(65ch, 100%) 1fr;
  grid-template-rows: auto 1fr auto;
}

.page > * {
  grid-column: 2;
}

/* Flexbox за header вътре в grid */
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Grid за card grid */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 24px;
}

/* Flexbox за card вътре в grid */
.card {
  display: flex;
  flex-direction: column;
}

.card__content {
  flex: 1;
}

.card__footer {
  margin-top: auto;
  display: flex;
  justify-content: space-between;
}

Performance съображения

  1. Grid и Flexbox са hardware-accelerated
  2. Избягвайте layout thrashing при анимации
  3. Използвайте will-change внимателно
  4. contain: layout може да помогне за изолация

Заключение

CSS Grid и Flexbox са мощни инструменти, които се допълват взаимно. Използвайте Grid за двумерни layouts и Flexbox за едномерни подравнявания. Комбинирайте ги за максимална гъвкавост.


Брой думи: 3,198