לדלג לתוכן

1.5 פלקסבוקס הרצאה

פלקסבוקס - Flexbox

פלקסבוקס (Flexible Box Layout) הוא מודל layout חד-ממדי ב-CSS שמקל מאוד על סידור אלמנטים בשורה או בעמודה. לפני Flexbox, סידור אלמנטים היה סיוט עם float-ים, inline-block ושאר פתרונות מסורבלים. היום Flexbox הוא הכלי העיקרי ל-layout בCSS.

הרעיון הבסיסי: ציר ראשי וציר משני

בפלקסבוקס יש שני צירים:
- ציר ראשי - main axis - הכיוון שבו האלמנטים מסודרים (ברירת מחדל: אופקי, שמאל לימין)
- ציר משני - cross axis - הכיוון הניצב לציר הראשי (ברירת מחדל: אנכי, למעלה למטה)

כל Flexbox מורכב משני חלקים:
- קונטיינר - flex container - ההורה שמגדירים עליו display: flex
- פריטים - flex items - הילדים הישירים של הקונטיינר

<div class="container">    <!-- flex container -->
    <div class="item">1</div>  <!-- flex item -->
    <div class="item">2</div>  <!-- flex item -->
    <div class="item">3</div>  <!-- flex item -->
</div>
.container {
    display: flex; /* this activates flexbox */
}

ברגע שמוסיפים display: flex, כל הילדים הישירים הופכים לflex items ומסתדרים בשורה אחת אופקית. זה כל מה שצריך כדי להתחיל.

מאפייני הקונטיינר

כיוון - flex-direction

קובע את כיוון הציר הראשי:

.container {
    display: flex;
    flex-direction: row;            /* default: horizontal, left to right */
}

.container-column {
    display: flex;
    flex-direction: column;         /* vertical, top to bottom */
}

.container-reverse {
    display: flex;
    flex-direction: row-reverse;    /* horizontal, right to left */
}

.container-column-reverse {
    display: flex;
    flex-direction: column-reverse; /* vertical, bottom to top */
}
  • row (ברירת מחדל) - שורה אופקית
  • column - עמודה אנכית
  • row-reverse - שורה אופקית הפוכה
  • column-reverse - עמודה אנכית הפוכה

יישור על הציר הראשי - justify-content

שולט איך הפריטים מתפלגים על הציר הראשי:

.start {
    display: flex;
    justify-content: flex-start;    /* default: items at the start */
}

.center {
    display: flex;
    justify-content: center;        /* items centered */
}

.end {
    display: flex;
    justify-content: flex-end;      /* items at the end */
}

.between {
    display: flex;
    justify-content: space-between; /* first item at start, last at end, equal space between */
}

.around {
    display: flex;
    justify-content: space-around;  /* equal space around each item */
}

.evenly {
    display: flex;
    justify-content: space-evenly;  /* equal space between all items and edges */
}

נדמיין שורה אופקית עם שלושה פריטים (A, B, C):
- flex-start: [A B C ]
- center: [ A B C ]
- flex-end: [ A B C]
- space-between: [A B C]
- space-around: [ A B C ]
- space-evenly: [ A B C ]

ההבדל בין around ל-evenly: ב-around, הרווח בצדדים הוא חצי מהרווח בין הפריטים. ב-evenly, כל הרווחים שווים.

יישור על הציר המשני - align-items

שולט איך הפריטים מיושרים על הציר המשני (אנכי כשהכיוון הוא row):

.stretch {
    display: flex;
    align-items: stretch;       /* default: items stretch to fill container height */
}

.top {
    display: flex;
    align-items: flex-start;    /* items at the top */
}

.middle {
    display: flex;
    align-items: center;        /* items vertically centered */
}

.bottom {
    display: flex;
    align-items: flex-end;      /* items at the bottom */
}

.baseline {
    display: flex;
    align-items: baseline;      /* items aligned by text baseline */
}
  • stretch (ברירת מחדל) - הפריטים נמתחים למלא את כל הגובה של הקונטיינר
  • flex-start - הפריטים למעלה
  • center - הפריטים באמצע
  • flex-end - הפריטים למטה
  • baseline - הפריטים מיושרים לפי קו הבסיס של הטקסט (שימושי כשלפריטים גדלי טקסט שונים)

שבירת שורות - flex-wrap

.no-wrap {
    display: flex;
    flex-wrap: nowrap;   /* default: all items in one line, may overflow */
}

.wrap {
    display: flex;
    flex-wrap: wrap;     /* items wrap to next line when needed */
}

.wrap-reverse {
    display: flex;
    flex-wrap: wrap-reverse; /* wraps in reverse direction */
}
  • nowrap (ברירת מחדל) - כל הפריטים בשורה אחת, גם אם הם צריכים להתכווץ
  • wrap - פריטים שלא נכנסים עוברים לשורה הבאה
  • בדרך כלל נרצה wrap כשיש הרבה פריטים

קיצור - flex-flow

שילוב של flex-direction ו-flex-wrap:

.container {
    display: flex;
    flex-flow: row wrap; /* same as flex-direction: row; flex-wrap: wrap; */
}

יישור שורות מרובות - align-content

כשיש flex-wrap ומספר שורות, align-content שולט על הפילוג האנכי של השורות:

.container {
    display: flex;
    flex-wrap: wrap;
    height: 500px;
    align-content: flex-start;    /* lines packed at top */
}

.container-center {
    display: flex;
    flex-wrap: wrap;
    height: 500px;
    align-content: center;        /* lines centered vertically */
}

.container-between {
    display: flex;
    flex-wrap: wrap;
    height: 500px;
    align-content: space-between; /* first line at top, last at bottom */
}
  • align-content עובד רק כשיש מספר שורות (flex-wrap: wrap)
  • הערכים דומים ל-justify-content: flex-start, center, flex-end, space-between, space-around, space-evenly, stretch

מרווח - gap

.container {
    display: flex;
    gap: 20px;          /* 20px gap between all items */
}

.container-custom {
    display: flex;
    row-gap: 15px;      /* gap between rows */
    column-gap: 25px;   /* gap between columns */
}

.container-shorthand {
    display: flex;
    gap: 15px 25px;     /* row-gap column-gap */
}
  • gap מגדיר מרווח בין הפריטים (לא בצדדים)
  • הרבה יותר נוח מ-margin על כל פריט
  • עובד גם ב-Flexbox וגם ב-Grid

מאפייני הפריטים

המאפיינים הבאים מוגדרים על הפריטים עצמם (הילדים), לא על הקונטיינר.

סדר - order

משנה את סדר ההצגה של פריט בלי לשנות את ה-HTML:

.item-a { order: 3; }
.item-b { order: 1; }
.item-c { order: 2; }
/* display order: B, C, A */
  • ברירת מחדל: 0 לכל הפריטים
  • מספר נמוך = מוצג קודם
  • אפשר להשתמש במספרים שליליים

גדילה - flex-grow

קובע כמה פריט יכול לגדול ביחס לאחרים כשיש מקום פנוי:

.item-a { flex-grow: 1; } /* gets 1 share of extra space */
.item-b { flex-grow: 2; } /* gets 2 shares of extra space */
.item-c { flex-grow: 1; } /* gets 1 share of extra space */
  • ברירת מחדל: 0 (לא גדל)
  • אם לכולם flex-grow: 1, כולם מתחלקים שווה בשווה במקום הפנוי
  • אם לאחד flex-grow: 2 ולשאר 1, הוא מקבל פי 2 מהמקום הפנוי

דוגמה מעשית - שדה חיפוש שתופס את כל הרוחב הפנוי:

<div class="search-bar">
    <input class="search-input" type="text" placeholder="Search...">
    <button class="search-btn">Search</button>
</div>
.search-bar {
    display: flex;
    gap: 10px;
}

.search-input {
    flex-grow: 1; /* takes all available space */
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 4px;
}

.search-btn {
    padding: 10px 20px;
    /* doesn't grow - stays at its natural size */
}

כיווץ - flex-shrink

קובע כמה פריט יכול להתכווץ כשאין מספיק מקום:

.item-a { flex-shrink: 1; } /* default: can shrink */
.item-b { flex-shrink: 0; } /* won't shrink at all */
.item-c { flex-shrink: 2; } /* shrinks twice as much */
  • ברירת מחדל: 1 (מתכווץ)
  • flex-shrink: 0 = הפריט לא יתכווץ בשום מקרה

גודל בסיסי - flex-basis

מגדיר את הגודל ההתחלתי של פריט לפני שflex-grow ו-flex-shrink נכנסים לפעולה:

.item {
    flex-basis: 200px; /* starts at 200px wide */
}

.item-auto {
    flex-basis: auto; /* default: uses width/content */
}

.item-zero {
    flex-basis: 0; /* starts at 0, size determined by flex-grow */
}
  • auto (ברירת מחדל) - משתמש ב-width של הפריט, או גודל התוכן
  • ערך ספציפי (px, %, rem) - מגדיר גודל בסיסי

קיצור - flex

שילוב של flex-grow, flex-shrink ו-flex-basis:

.item {
    flex: 0 1 auto; /* default: don't grow, can shrink, auto basis */
}

.item-grow {
    flex: 1;        /* same as: flex: 1 1 0 */
    /* grow=1, shrink=1, basis=0 (splits space equally) */
}

.item-fixed {
    flex: 0 0 200px; /* don't grow, don't shrink, 200px */
}

.item-half {
    flex: 1 1 50%;  /* grow and shrink, start at 50% */
}

ערכים נפוצים:
- flex: 1 - פריט גמיש שתופס חלק שווה מהמקום (הכי נפוץ)
- flex: none = flex: 0 0 auto - פריט קשיח שלא גדל ולא מתכווץ
- flex: auto = flex: 1 1 auto - פריט גמיש שמתחיל מהגודל הטבעי שלו

יישור עצמי - align-self

דורס את align-items של הקונטיינר עבור פריט ספציפי:

.container {
    display: flex;
    align-items: flex-start; /* all items at top */
}

.special-item {
    align-self: flex-end;    /* this one goes to bottom */
}

.center-item {
    align-self: center;      /* this one centered vertically */
}

דפוסים נפוצים

<nav class="navbar">
    <div class="navbar-logo">Logo</div>
    <div class="navbar-links">
        <a href="#">Home</a>
        <a href="#">About</a>
        <a href="#">Services</a>
        <a href="#">Contact</a>
    </div>
</nav>
.navbar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 15px 30px;
    background-color: #2c3e50;
}

.navbar-logo {
    color: white;
    font-size: 20px;
    font-weight: bold;
}

.navbar-links {
    display: flex;
    gap: 10px;
}

.navbar-links a {
    color: white;
    text-decoration: none;
    padding: 8px 16px;
}
  • space-between שם את הלוגו בצד אחד והקישורים בצד השני
  • align-items: center מיישר הכל אנכית במרכז

מרכוז מושלם

.center-both {
    display: flex;
    justify-content: center; /* horizontal center */
    align-items: center;     /* vertical center */
    height: 100vh;           /* full viewport height */
}

שלוש שורות וזה עובד. זה כל מה שצריך למרכוז מושלם.

רשת כרטיסים - card grid

<div class="card-grid">
    <div class="card">Card 1</div>
    <div class="card">Card 2</div>
    <div class="card">Card 3</div>
    <div class="card">Card 4</div>
    <div class="card">Card 5</div>
    <div class="card">Card 6</div>
</div>
.card-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
}

.card {
    flex: 1 1 300px; /* grow, shrink, minimum 300px */
    background: white;
    border: 1px solid #ddd;
    border-radius: 8px;
    padding: 20px;
}
  • flex: 1 1 300px אומר: כל כרטיס מינימום 300px רוחב, ואם יש מקום - כולם גדלים שווה
  • flex-wrap: wrap מעביר כרטיסים לשורה הבאה כשאין מספיק מקום
  • התוצאה: רשת שמתאימה את עצמה למסך
<footer class="footer">
    <div class="footer-col">
        <h4>About</h4>
        <p>We build great websites.</p>
    </div>
    <div class="footer-col">
        <h4>Links</h4>
        <a href="#">Home</a>
        <a href="#">Blog</a>
        <a href="#">Contact</a>
    </div>
    <div class="footer-col">
        <h4>Contact</h4>
        <p>email@example.com</p>
        <p>+972-50-1234567</p>
    </div>
</footer>
.footer {
    display: flex;
    justify-content: space-between;
    gap: 30px;
    padding: 40px 30px;
    background-color: #2c3e50;
    color: white;
}

.footer-col {
    flex: 1;
}

.footer-col h4 {
    margin-bottom: 15px;
    font-size: 18px;
}

.footer-col a {
    display: block;
    color: #bdc3c7;
    text-decoration: none;
    margin-bottom: 8px;
}

.footer-col p {
    color: #bdc3c7;
    margin-bottom: 8px;
}

Holy Grail Layout

הlayout הקלאסי של אתרים: header, footer, ובאמצע sidebar + content + sidebar:

<div class="layout">
    <header class="layout-header">Header</header>
    <div class="layout-body">
        <aside class="layout-sidebar">Sidebar Left</aside>
        <main class="layout-content">Main Content</main>
        <aside class="layout-sidebar">Sidebar Right</aside>
    </div>
    <footer class="layout-footer">Footer</footer>
</div>
.layout {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

.layout-header {
    background-color: #2c3e50;
    color: white;
    padding: 20px;
}

.layout-body {
    display: flex;
    flex: 1; /* takes all remaining vertical space */
}

.layout-sidebar {
    flex: 0 0 200px; /* fixed 200px wide, won't grow or shrink */
    background-color: #ecf0f1;
    padding: 20px;
}

.layout-content {
    flex: 1; /* takes all remaining horizontal space */
    padding: 20px;
}

.layout-footer {
    background-color: #2c3e50;
    color: white;
    padding: 20px;
    text-align: center;
}
  • הlayout החיצוני הוא flex column (אנכי)
  • ה-body הוא flex row (אופקי)
  • flex: 1 על body ועל content גורם להם לתפוס את כל המקום הפנוי
  • flex: 0 0 200px על sidebars שומר אותם ב-200px קבועים

דוגמה מסכמת

נבנה דף שלם שמשלב הרבה מהדפוסים:

<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
    <meta charset="UTF-8">
    <title>Flexbox Layout</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <nav class="nav">
        <div class="nav-logo">FlexSite</div>
        <div class="nav-links">
            <a href="#">Home</a>
            <a href="#">Products</a>
            <a href="#">About</a>
            <a href="#">Contact</a>
        </div>
    </nav>

    <section class="hero">
        <h1>Build Layouts with Flexbox</h1>
        <p>The modern way to create responsive CSS layouts</p>
    </section>

    <main class="main">
        <h2 class="section-title">Our Products</h2>
        <div class="products">
            <div class="product-card">
                <h3>Product A</h3>
                <p>Amazing product description</p>
                <span class="price">$29</span>
            </div>
            <div class="product-card">
                <h3>Product B</h3>
                <p>Another great product</p>
                <span class="price">$49</span>
            </div>
            <div class="product-card">
                <h3>Product C</h3>
                <p>Premium quality item</p>
                <span class="price">$99</span>
            </div>
        </div>
    </main>

    <footer class="footer">
        <div class="footer-section">
            <h4>Company</h4>
            <p>Building great products since 2020</p>
        </div>
        <div class="footer-section">
            <h4>Links</h4>
            <a href="#">Privacy</a>
            <a href="#">Terms</a>
        </div>
        <div class="footer-section">
            <h4>Contact</h4>
            <p>hello@example.com</p>
        </div>
    </footer>
</body>
</html>
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: Arial, sans-serif;
    color: #333;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

/* navbar */
.nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 15px 30px;
    background-color: #2c3e50;
}

.nav-logo {
    color: white;
    font-size: 22px;
    font-weight: bold;
}

.nav-links {
    display: flex;
    gap: 5px;
}

.nav-links a {
    color: white;
    text-decoration: none;
    padding: 8px 16px;
    border-radius: 4px;
}

/* hero - centered content */
.hero {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    padding: 80px 20px;
    background-color: #34495e;
    color: white;
}

.hero h1 {
    font-size: 2.5rem;
    margin-bottom: 10px;
}

.hero p {
    font-size: 1.2rem;
    opacity: 0.8;
}

/* main content */
.main {
    flex: 1; /* pushes footer to bottom */
    max-width: 1000px;
    margin: 0 auto;
    padding: 40px 20px;
    width: 100%;
}

.section-title {
    margin-bottom: 25px;
    font-size: 1.8rem;
    color: #2c3e50;
}

/* product cards grid */
.products {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
}

.product-card {
    flex: 1 1 250px;
    background: white;
    border: 1px solid #ddd;
    border-radius: 10px;
    padding: 25px;
    display: flex;
    flex-direction: column;
}

.product-card h3 {
    margin-bottom: 10px;
    color: #2c3e50;
}

.product-card p {
    color: #777;
    flex: 1; /* pushes price to bottom */
    margin-bottom: 15px;
}

.price {
    font-size: 24px;
    font-weight: bold;
    color: #27ae60;
    align-self: flex-start;
}

/* footer */
.footer {
    display: flex;
    justify-content: space-between;
    gap: 30px;
    padding: 30px;
    background-color: #2c3e50;
    color: white;
}

.footer-section {
    flex: 1;
}

.footer-section h4 {
    margin-bottom: 10px;
}

.footer-section a {
    display: block;
    color: #bdc3c7;
    text-decoration: none;
    margin-bottom: 5px;
}

.footer-section p {
    color: #bdc3c7;
}

שימו לב לטריק ב-product-card: שמנו flex: 1 על הפסקה כדי שהיא תתפוס את כל המקום הפנוי, ובכך המחיר נדחף לתחתית הכרטיס. ככה כל הכרטיסים מסודרים אחיד גם אם התיאור באחד קצר יותר.

סיכום

  • display: flex מפעיל פלקסבוקס על הקונטיינר
  • flex-direction קובע את כיוון הציר: row (אופקי) או column (אנכי)
  • justify-content מיישר על הציר הראשי: center, space-between, space-evenly
  • align-items מיישר על הציר המשני: center, stretch, flex-start, flex-end
  • flex-wrap: wrap מאפשר שבירת שורות
  • gap מגדיר מרווח בין פריטים
  • flex: 1 על פריט = תופס מקום פנוי שווה
  • flex: 0 0 200px = גודל קבוע ללא גדילה/כיווץ
  • align-self דורס את align-items לפריט ספציפי
  • למרכוז מושלם: display: flex; justify-content: center; align-items: center;
  • פלקסבוקס פותר כמעט כל בעיית layout חד-ממדית - השתמשו בו בלי פחד