לדלג לתוכן

1.7 עיצוב רספונסיבי הרצאה

מה זה עיצוב רספונסיבי - Responsive Design

עיצוב רספונסיבי הוא גישה שבה האתר מתאים את עצמו לכל גודל מסך - טלפון, טאבלט, מחשב נייד, ומסך גדול.

למה זה חשוב? כי היום יותר מ-60% מהתנועה באינטרנט מגיעה ממכשירים ניידים. אם האתר שלכם לא נראה טוב בטלפון - איבדתם את רוב הקהל.

בנוסף, גוגל מדרג אתרים לפי הביצועים שלהם בנייד (mobile-first indexing). אתר לא רספונסיבי פשוט לא יופיע בתוצאות חיפוש גבוהות.


תגית viewport

כשפותחים אתר בטלפון בלי תגית viewport, הדפדפן מנסה להציג את האתר כאילו הוא מסך רחב ומקטין הכל - מה שגורם לטקסט זעיר שלא ניתן לקרוא.

התגית הזו צריכה להיות בכל עמוד HTML:

<meta name="viewport" content="width=device-width, initial-scale=1.0">

מה היא עושה:
- width=device-width - רוחב העמוד יהיה לפי רוחב המכשיר האמיתי
- initial-scale=1.0 - מונע זום אוטומטי

בלי התגית הזו, כל ה-CSS הרספונסיבי שנכתוב פשוט לא יעבוד כמו שצריך במובייל.


גישת Mobile-First מול Desktop-First

יש שתי גישות לכתיבת CSS רספונסיבי:

גישת Desktop-First

כותבים את ה-CSS לדסקטופ קודם, ואז משתמשים ב-max-width כדי להתאים למסכים קטנים:

/* default: desktop styles */
.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}

/* tablet and below */
@media (max-width: 768px) {
  .container {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* mobile */
@media (max-width: 480px) {
  .container {
    grid-template-columns: 1fr;
  }
}

גישת Mobile-First (מומלצת)

כותבים את ה-CSS למובייל קודם, ואז משתמשים ב-min-width כדי להוסיף סגנונות למסכים גדולים:

/* default: mobile styles */
.container {
  display: grid;
  grid-template-columns: 1fr;
}

/* tablet and above */
@media (min-width: 768px) {
  .container {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* desktop */
@media (min-width: 1024px) {
  .container {
    grid-template-columns: repeat(3, 1fr);
  }
}

למה mobile-first עדיפה?
- מובייל הוא המקרה הפשוט ביותר (עמודה אחת, פחות מרכיבים מורכבים)
- קל יותר להוסיף מורכבות מאשר לגרוע אותה
- מתאים לאיך שגוגל מדרג אתרים
- מאלץ אותנו לחשוב על מה באמת חשוב באתר


שאילתות מדיה - Media Queries

שאילתות מדיה מאפשרות להחיל CSS שונה בהתאם לתנאים - בדרך כלל רוחב המסך.

תחביר בסיסי

@media (min-width: 768px) {
  /* styles applied when screen is 768px or wider */
  .sidebar {
    display: block;
  }
}

שילוב תנאים

/* between 600px and 1024px */
@media (min-width: 600px) and (max-width: 1024px) {
  .container {
    padding: 20px;
  }
}

/* portrait orientation */
@media (orientation: portrait) {
  .hero {
    height: 50vh;
  }
}

נקודות שבירה נפוצות - breakpoints

אין "נקודות שבירה נכונות" אוניברסליות, אבל הנה ערכים נפוצים:

/* mobile (small) */
/* up to 599px - default mobile-first styles, no media query needed */

/* tablet */
@media (min-width: 600px) { }

/* laptop */
@media (min-width: 768px) { }

/* desktop */
@media (min-width: 1024px) { }

/* large desktop */
@media (min-width: 1440px) { }

הטיפ הכי חשוב: אל תבחרו breakpoints לפי מכשירים ספציפיים. בחרו breakpoints לפי איפה ה-layout שלכם "נשבר" - כלומר איפה העיצוב מפסיק להיראות טוב.


שילוב media queries עם פלקסבוקס וגריד

דוגמה עם פלקסבוקס

.nav {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

@media (min-width: 768px) {
  .nav {
    flex-direction: row;
    justify-content: space-between;
  }
}

במובייל - תפריט אנכי. בדסקטופ - תפריט אופקי.

דוגמה עם גריד

.page {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-areas:
    "header"
    "main"
    "sidebar"
    "footer";
}

@media (min-width: 768px) {
  .page {
    grid-template-columns: 250px 1fr;
    grid-template-areas:
      "header  header"
      "sidebar main"
      "footer  footer";
  }
}

ה-layout כולו משתנה - במובייל הכל בעמודה אחת, בדסקטופ sidebar + main.


תמונות רספונסיביות

תמונות צריכות טיפול מיוחד כדי להיראות טוב בכל מסך.

הבסיס - max-width

img {
  max-width: 100%;
  height: auto;
}

זה הכלל הכי חשוב - התמונה לא תהיה רחבה יותר מהמיכל שלה, ותשמור על היחס.

תגית picture - תמונות שונות לגדלים שונים

<picture>
  <source media="(min-width: 1024px)" srcset="hero-large.jpg">
  <source media="(min-width: 600px)" srcset="hero-medium.jpg">
  <img src="hero-small.jpg" alt="hero image">
</picture>

הדפדפן יטען את התמונה המתאימה לגודל המסך - מה שחוסך bandwidth במובייל.

תכונת srcset

<img
  src="photo-400.jpg"
  srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
  sizes="(min-width: 1024px) 33vw, (min-width: 600px) 50vw, 100vw"
  alt="responsive photo"
>
  • srcset - רשימת תמונות עם הרוחב שלהן
  • sizes - אומר לדפדפן מה יהיה רוחב התמונה בתצוגה
  • הדפדפן בוחר אוטומטית את התמונה הכי מתאימה

טיפוגרפיה רספונסיבית

הבעיה

גודל פונט קבוע לא עובד בכל המסכים. כותרת של 48px מושלמת בדסקטופ אבל עצומה בטלפון.

הפתרון הישן - media queries

h1 {
  font-size: 24px;
}

@media (min-width: 768px) {
  h1 {
    font-size: 36px;
  }
}

@media (min-width: 1024px) {
  h1 {
    font-size: 48px;
  }
}

הפתרון המודרני - clamp

h1 {
  font-size: clamp(1.5rem, 4vw, 3rem);
}

clamp(minimum, preferred, maximum) - הפונט יגדל ויקטן בצורה חלקה:
- לא יהיה קטן מ-1.5rem (24px)
- ינסה להיות 4vw (4% מרוחב המסך)
- לא יהיה גדול מ-3rem (48px)

שורה אחת של CSS במקום 3 media queries, והתוצאה חלקה יותר.

מערכת טיפוגרפיה רספונסיבית שלמה

:root {
  --text-xs: clamp(0.75rem, 1.5vw, 0.875rem);
  --text-sm: clamp(0.875rem, 1.8vw, 1rem);
  --text-base: clamp(1rem, 2vw, 1.125rem);
  --text-lg: clamp(1.125rem, 2.5vw, 1.5rem);
  --text-xl: clamp(1.5rem, 3vw, 2rem);
  --text-2xl: clamp(1.75rem, 4vw, 2.5rem);
  --text-3xl: clamp(2rem, 5vw, 3.5rem);
}

h1 { font-size: var(--text-3xl); }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
p  { font-size: var(--text-base); }

שאילתות מיכל - Container Queries

Container queries הם פיצ'ר חדש יחסית שמאפשר לעצב רכיב לפי גודל המיכל שלו, ולא לפי גודל המסך.

.card-container {
  container-type: inline-size;
  container-name: card;
}

@container card (min-width: 400px) {
  .card {
    display: flex;
    flex-direction: row;
  }
}

@container card (max-width: 399px) {
  .card {
    display: flex;
    flex-direction: column;
  }
}

למה זה שימושי? כי media queries מסתכלות על גודל המסך כולו. אבל אם יש כרטיס שמופיע גם ב-sidebar צר וגם ב-main רחב - הוא צריך להתנהג אחרת בכל מקום, גם באותו גודל מסך.

container queries פותרות בדיוק את הבעיה הזו - הרכיב מתאים את עצמו לפי הגודל של המיכל שלו.


תבנית תפריט המבורגר - Hamburger Menu

בדסקטופ הניווט מוצג אופקית. במובייל, הניווט מוחלף בכפתור (שלושה קווים) שפותח תפריט.

המבנה הבסיסי ב-CSS בלבד (בלי JavaScript):

.nav-links {
  display: none;
}

.hamburger {
  display: block;
  font-size: 1.5rem;
  background: none;
  border: none;
  cursor: pointer;
}

@media (min-width: 768px) {
  .nav-links {
    display: flex;
    gap: 20px;
  }

  .hamburger {
    display: none;
  }
}

הכפתור מוצג רק במובייל, והקישורים רק בדסקטופ.
כדי שהכפתור ממש יפתח ויסגור את התפריט - צריך JavaScript (נלמד בהמשך).
אבל אפשר גם לעשות את זה עם טריק של checkbox ב-CSS בלבד:

<nav>
  <input type="checkbox" id="menu-toggle" class="menu-checkbox">
  <label for="menu-toggle" class="hamburger">&#9776;</label>
  <ul class="nav-links">
    <li><a href="#">home</a></li>
    <li><a href="#">about</a></li>
    <li><a href="#">contact</a></li>
  </ul>
</nav>
.menu-checkbox {
  display: none;
}

.nav-links {
  display: none;
  flex-direction: column;
  gap: 10px;
}

.menu-checkbox:checked ~ .nav-links {
  display: flex;
}

@media (min-width: 768px) {
  .hamburger {
    display: none;
  }

  .nav-links {
    display: flex;
    flex-direction: row;
  }
}

הטריק: כשלוחצים על ה-label, ה-checkbox נבחר, והסלקטור ~ מפעיל את הצגת התפריט.


טבלאות רספונסיביות

טבלאות הן אחד הדברים הקשים ביותר להפוך לרספונסיביים כי הן מעצם טבען רחבות.

אסטרטגיה 1 - גלילה אופקית

.table-wrapper {
  overflow-x: auto;
}

table {
  min-width: 600px;
  width: 100%;
}

פשוט עוטפים את הטבלה ב-div עם overflow-x: auto. אם הטבלה רחבה מהמסך, תהיה גלילה אופקית.

אסטרטגיה 2 - שינוי layout

@media (max-width: 600px) {
  table, thead, tbody, tr, th, td {
    display: block;
  }

  thead {
    display: none;
  }

  td {
    padding: 8px;
    text-align: right;
  }

  td::before {
    content: attr(data-label);
    float: left;
    font-weight: bold;
  }
}
<tr>
  <td data-label="Name">John</td>
  <td data-label="Email">john@example.com</td>
  <td data-label="Phone">050-1234567</td>
</tr>

במובייל, כל שורה הופכת לכרטיס - כל תא בשורה נפרדת עם label.


תבניות ניווט רספונסיביות

ניווט אופקי שנהפך לאנכי

.nav {
  display: flex;
  flex-direction: column;
  background: #333;
}

.nav a {
  color: white;
  padding: 15px 20px;
  text-decoration: none;
}

@media (min-width: 768px) {
  .nav {
    flex-direction: row;
  }

  .nav a {
    padding: 15px 25px;
  }
}

ניווט עם לוגו ותפריט

.navbar {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  padding: 10px 20px;
  background: #1a1a2e;
}

.logo {
  color: white;
  font-size: 1.5rem;
  font-weight: bold;
}

.nav-links {
  display: flex;
  gap: 20px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.nav-links a {
  color: white;
  text-decoration: none;
}

@media (max-width: 768px) {
  .nav-links {
    flex-basis: 100%;
    flex-direction: column;
    gap: 10px;
    padding-top: 15px;
  }
}

בדיקה ב-DevTools Device Mode

כלי הפיתוח של הדפדפן מאפשרים לבדוק איך האתר נראה בגדלי מסך שונים.

כדי לפתוח Device Mode:
- לחצו F12 או Ctrl + Shift + I כדי לפתוח את DevTools
- לחצו על אייקון הטלפון/טאבלט (או Ctrl + Shift + M)
- בחרו מכשיר מהרשימה, או גררו את הידיות כדי לשנות גודל

מה שימושי ב-Device Mode:
- בדיקת breakpoints שונים
- סימולציה של מכשירים ספציפיים (iPhone, iPad, Pixel)
- בדיקת touch events
- בדיקת performance בסימולציה של מעבד איטי

טיפ: תמיד בדקו את האתר גם בטלפון אמיתי. הסימולציה של DevTools טובה אבל לא מושלמת.


יחידות CSS לעיצוב רספונסיבי

אחוזים - %

יחסי לאלמנט ההורה:

.child {
  width: 50%; /* half of parent's width */
}

יחידות viewport - vw, vh

.hero {
  height: 100vh; /* full viewport height */
  width: 100vw;  /* full viewport width */
}

.title {
  font-size: 5vw; /* 5% of viewport width */
}

rem

יחסי לגודל הפונט של html (ברירת מחדל 16px):

html {
  font-size: 16px;
}

h1 {
  font-size: 2rem; /* 32px */
  margin-bottom: 1.5rem; /* 24px */
}

rem מצוין לריווחים ולפונטים - הכל מתנהג באופן עקבי ואפשר לשנות את הגודל הבסיסי ב-media query.

הפונקציה clamp

.container {
  width: clamp(300px, 80%, 1200px);
  /* minimum 300px, prefers 80%, maximum 1200px */

  padding: clamp(10px, 3vw, 40px);
  /* minimum 10px, prefers 3vw, maximum 40px */
}

clamp() הוא הכלי הכי טוב לרספונסיביות - ערך אחד שמתאים לכל הגדלים.

min ו-max

.container {
  width: min(90%, 1200px);
  /* the smaller of 90% and 1200px */
}

.sidebar {
  width: max(200px, 20%);
  /* the larger of 200px and 20% */
}

משתני CSS לערכים רספונסיביים

אפשר לשלב CSS variables עם media queries ליצירת מערכת רספונסיבית מאורגנת:

:root {
  --spacing-sm: 8px;
  --spacing-md: 16px;
  --spacing-lg: 24px;
  --container-width: 100%;
  --columns: 1;
}

@media (min-width: 768px) {
  :root {
    --spacing-sm: 12px;
    --spacing-md: 24px;
    --spacing-lg: 40px;
    --container-width: 750px;
    --columns: 2;
  }
}

@media (min-width: 1024px) {
  :root {
    --spacing-lg: 60px;
    --container-width: 960px;
    --columns: 3;
  }
}

.container {
  max-width: var(--container-width);
  margin: 0 auto;
  padding: var(--spacing-md);
}

.grid {
  display: grid;
  grid-template-columns: repeat(var(--columns), 1fr);
  gap: var(--spacing-md);
}

section {
  padding: var(--spacing-lg) 0;
}

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


סיכום

הנקודות החשובות ביותר בעיצוב רספונסיבי:
- תמיד הוסיפו את תגית viewport ב-HTML
- העדיפו גישת mobile-first - כתבו CSS למובייל קודם, והוסיפו min-width media queries
- השתמשו ב-clamp() לטיפוגרפיה ולמרחקים רספונסיביים
- הגדירו max-width: 100% על תמונות
- השתמשו ביחידות יחסיות (%, rem, vw) במקום פיקסלים קבועים
- בדקו את האתר ב-DevTools Device Mode ובמכשירים אמיתיים
- container queries הם הפיצ'ר הבא - מאפשרים לרכיבים להתאים למיכל שלהם
- שלבו CSS variables עם media queries למערכת רספונסיבית מאורגנת