1.9 טכניקות מתקדמות פתרון
פתרון תרגול טכניקות מתקדמות¶
תרגיל 1 - מערכת צבעים עם משתני CSS¶
:root {
/* colors */
--color-primary: #3498db;
--color-primary-light: #5dade2;
--color-primary-dark: #2471a3;
--color-secondary: #2ecc71;
--color-secondary-light: #58d68d;
--color-accent: #f39c12;
--color-danger: #e74c3c;
/* text colors */
--color-text: #333;
--color-text-light: #666;
--color-text-on-dark: #ffffff;
/* background colors */
--color-bg: #ffffff;
--color-bg-secondary: #f5f5f5;
/* border */
--color-border: #ddd;
/* spacing */
--space-xs: 4px;
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
--space-xl: 40px;
/* border radius */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 16px;
/* shadows */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 10px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 30px rgba(0, 0, 0, 0.15);
}
body {
font-family: Arial, sans-serif;
background: var(--color-bg);
color: var(--color-text);
padding: var(--space-xl);
}
h1, h2, h3 {
color: var(--color-text);
margin-bottom: var(--space-md);
}
p {
color: var(--color-text-light);
margin-bottom: var(--space-md);
}
/* buttons */
.btn {
padding: var(--space-sm) var(--space-md);
border: none;
border-radius: var(--radius-sm);
cursor: pointer;
font-size: 1rem;
color: var(--color-text-on-dark);
}
.btn--primary { background: var(--color-primary); }
.btn--primary:hover { background: var(--color-primary-dark); }
.btn--secondary { background: var(--color-secondary); }
.btn--danger { background: var(--color-danger); }
/* card */
.card {
background: var(--color-bg);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
padding: var(--space-lg);
box-shadow: var(--shadow-sm);
margin-bottom: var(--space-lg);
}
/* input */
.input {
padding: var(--space-sm) var(--space-md);
border: 1px solid var(--color-border);
border-radius: var(--radius-sm);
font-size: 1rem;
color: var(--color-text);
background: var(--color-bg);
}
.input:focus {
outline: none;
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2);
}
- כל ערך צבע, ריווח, radius וצל מוגדר כמשתנה
- אין ערכים "קשיחים" בשום סלקטור - הכל דרך
var() - קל לשנות את כל ערכת הצבעים על ידי שינוי ה-
:root
תרגיל 2 - מצב כהה/בהיר - Dark/Light Mode¶
/* light mode (default) */
:root {
--color-text: #333;
--color-text-light: #666;
--color-text-on-dark: #ffffff;
--color-bg: #ffffff;
--color-bg-secondary: #f5f5f5;
--color-border: #ddd;
--color-card: #ffffff;
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
--shadow-md: 0 4px 10px rgba(0, 0, 0, 0.1);
}
/* dark mode */
[data-theme="dark"] {
--color-text: #e0e0e0;
--color-text-light: #aaa;
--color-text-on-dark: #ffffff;
--color-bg: #1a1a2e;
--color-bg-secondary: #16213e;
--color-border: #2c2c4e;
--color-card: #1f1f3a;
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 10px rgba(0, 0, 0, 0.3);
}
/* auto dark mode based on system preference */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--color-text: #e0e0e0;
--color-text-light: #aaa;
--color-bg: #1a1a2e;
--color-bg-secondary: #16213e;
--color-border: #2c2c4e;
--color-card: #1f1f3a;
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 10px rgba(0, 0, 0, 0.3);
}
}
/* smooth transition */
body {
background: var(--color-bg);
color: var(--color-text);
transition: background 0.3s ease, color 0.3s ease;
}
.card {
background: var(--color-card);
border-color: var(--color-border);
transition: background 0.3s ease, border-color 0.3s ease;
}
/* theme toggle button */
.theme-toggle {
position: fixed;
top: 20px;
right: 20px;
padding: 10px 20px;
background: var(--color-bg-secondary);
color: var(--color-text);
border: 1px solid var(--color-border);
border-radius: 8px;
cursor: pointer;
}
[data-theme="dark"]דורס את המשתנים ב-:root- ה-
prefers-color-schememedia query מזהה העדפת מערכת הפעלה transitionעל body ו-card יוצר מעבר חלק בין המצבים- הסלקטור
:root:not([data-theme="light"])מבטיח שהעדפת מערכת לא תדרוס בחירה ידנית של light
תרגיל 3 - checkboxes מותאמים אישית¶
<label class="custom-checkbox">
<input type="checkbox">
<span class="custom-checkbox__mark"></span>
Option 1
</label>
<label class="custom-checkbox">
<input type="checkbox">
<span class="custom-checkbox__mark"></span>
Option 2
</label>
<label class="custom-checkbox">
<input type="checkbox" checked>
<span class="custom-checkbox__mark"></span>
Option 3 (pre-checked)
</label>
.custom-checkbox {
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
padding: 8px 0;
font-size: 1rem;
user-select: none;
}
.custom-checkbox input {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.custom-checkbox__mark {
width: 22px;
height: 22px;
border: 2px solid #ccc;
border-radius: 4px;
position: relative;
flex-shrink: 0;
transition: background 0.2s ease, border-color 0.2s ease;
}
/* checkmark (hidden by default) */
.custom-checkbox__mark::after {
content: "";
position: absolute;
top: 3px;
left: 7px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
opacity: 0;
transition: opacity 0.2s ease;
}
/* checked state */
.custom-checkbox input:checked + .custom-checkbox__mark {
background: #3498db;
border-color: #3498db;
}
.custom-checkbox input:checked + .custom-checkbox__mark::after {
opacity: 1;
}
/* hover */
.custom-checkbox:hover .custom-checkbox__mark {
border-color: #3498db;
}
/* focus-visible */
.custom-checkbox input:focus-visible + .custom-checkbox__mark {
outline: 3px solid rgba(52, 152, 219, 0.3);
outline-offset: 2px;
}
- ה-checkbox המקורי מוסתר עם
opacity: 0ו-position: absolute - ה-
::afterשל ה-mark יוצר את סימן ה-V עם border trick input:checked + .mark- הסלקטור+בוחר את האלמנט הבא אחרי ה-inputuser-select: noneמונע סימון טקסט בלחיצה כפולה
תרגיל 4 - tooltips עם פסאודו-אלמנטים¶
<button class="tooltip tooltip--top" data-tooltip="This is a tooltip">Hover me (top)</button>
<button class="tooltip tooltip--bottom" data-tooltip="Bottom tooltip">Hover me (bottom)</button>
<button class="tooltip tooltip--left" data-tooltip="Left tooltip">Hover me (left)</button>
<button class="tooltip tooltip--right" data-tooltip="Right tooltip">Hover me (right)</button>
.tooltip {
position: relative;
padding: 10px 20px;
background: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1rem;
margin: 40px;
}
/* tooltip bubble */
.tooltip::after {
content: attr(data-tooltip);
position: absolute;
background: #333;
color: white;
padding: 6px 12px;
border-radius: 4px;
font-size: 0.8rem;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease, transform 0.3s ease;
}
/* tooltip arrow */
.tooltip::before {
content: "";
position: absolute;
border: 6px solid transparent;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease, transform 0.3s ease;
}
/* show on hover */
.tooltip:hover::after,
.tooltip:hover::before {
opacity: 1;
}
/* TOP (default) */
.tooltip--top::after {
bottom: calc(100% + 10px);
left: 50%;
transform: translateX(-50%) translateY(5px);
}
.tooltip--top:hover::after {
transform: translateX(-50%) translateY(0);
}
.tooltip--top::before {
bottom: calc(100% - 2px);
left: 50%;
transform: translateX(-50%);
border-top-color: #333;
}
/* BOTTOM */
.tooltip--bottom::after {
top: calc(100% + 10px);
left: 50%;
transform: translateX(-50%) translateY(-5px);
}
.tooltip--bottom:hover::after {
transform: translateX(-50%) translateY(0);
}
.tooltip--bottom::before {
top: calc(100% - 2px);
left: 50%;
transform: translateX(-50%);
border-bottom-color: #333;
}
/* LEFT */
.tooltip--left::after {
right: calc(100% + 10px);
top: 50%;
transform: translateY(-50%) translateX(5px);
}
.tooltip--left:hover::after {
transform: translateY(-50%) translateX(0);
}
.tooltip--left::before {
right: calc(100% - 2px);
top: 50%;
transform: translateY(-50%);
border-left-color: #333;
}
/* RIGHT */
.tooltip--right::after {
left: calc(100% + 10px);
top: 50%;
transform: translateY(-50%) translateX(-5px);
}
.tooltip--right:hover::after {
transform: translateY(-50%) translateX(0);
}
.tooltip--right::before {
left: calc(100% - 2px);
top: 50%;
transform: translateY(-50%);
border-right-color: #333;
}
::afterמכיל את טקסט ה-tooltip (מ-attr(data-tooltip))::beforeיוצר חץ עם border trickpointer-events: noneמונע מה-tooltip לחסום hover על אלמנטים אחרים- כל כיוון (top/bottom/left/right) ממקם את ה-tooltip בהתאם
תרגיל 5 - שימוש ב-has לעיצוב הורה¶
<!-- form validation -->
<div class="form-group">
<label>Email</label>
<input type="email" required placeholder="enter email">
</div>
<!-- card with/without image -->
<div class="card-has">
<img src="https://picsum.photos/300/200" alt="photo">
<h3>Card with image</h3>
<p>This card has an image.</p>
</div>
<div class="card-has">
<h3>Card without image</h3>
<p>This card has no image.</p>
</div>
<!-- checklist -->
<div class="checklist">
<label class="check-item">
<input type="checkbox"> Buy groceries
</label>
<label class="check-item">
<input type="checkbox" checked> Clean house
</label>
<label class="check-item">
<input type="checkbox"> Call dentist
</label>
</div>
<!-- search with has -->
<div class="search-bar">
<input type="text" placeholder="Search...">
<button>Search</button>
</div>
/* form group - red border when input is invalid */
.form-group {
padding: 15px;
border: 2px solid #ddd;
border-radius: 8px;
margin-bottom: 15px;
transition: border-color 0.3s ease;
}
.form-group:has(input:invalid:not(:placeholder-shown)) {
border-color: #e74c3c;
background: #fdf0ef;
}
.form-group:has(input:valid:not(:placeholder-shown)) {
border-color: #2ecc71;
}
/* card with/without image */
.card-has {
border: 1px solid #ddd;
border-radius: 8px;
overflow: hidden;
margin-bottom: 15px;
}
.card-has:has(img) {
/* card has an image - no padding on top */
}
.card-has:not(:has(img)) {
padding: 20px;
border-left: 4px solid #3498db;
}
.card-has img {
width: 100%;
height: 200px;
object-fit: cover;
}
.card-has h3, .card-has p {
padding: 0 20px;
}
/* checklist - green background when checked */
.check-item {
display: block;
padding: 12px 15px;
border-bottom: 1px solid #eee;
cursor: pointer;
transition: background 0.2s ease;
}
.check-item:has(input:checked) {
background: #eafaf1;
text-decoration: line-through;
color: #999;
}
/* search bar - button disabled when empty */
.search-bar {
display: flex;
gap: 8px;
}
.search-bar button {
padding: 8px 16px;
background: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: opacity 0.2s ease;
}
.search-bar:has(input:placeholder-shown) button {
opacity: 0.4;
cursor: not-allowed;
}
:has(input:invalid:not(:placeholder-shown))- שדה שנוגעים בו ויש בו ערך לא תקין:not(:has(img))- כרטיס שאין בו תמונה:has(input:checked)- שורה שה-checkbox שלה מסומן:has(input:placeholder-shown)- כשהinput ריק (ה-placeholder עדיין מוצג)
תרגיל 6 - שיפוץ CSS למתודולוגיית BEM¶
<nav class="main-nav">
<div class="main-nav__logo">MyBrand</div>
<ul class="main-nav__links">
<li><a href="#" class="main-nav__link main-nav__link--active">Home</a></li>
<li><a href="#" class="main-nav__link">About</a></li>
<li><a href="#" class="main-nav__link">Contact</a></li>
</ul>
<button class="main-nav__cta">Sign Up</button>
</nav>
<section class="hero">
<h1 class="hero__title">Welcome</h1>
<p class="hero__text">This is the hero section.</p>
<button class="hero__button hero__button--large">Get Started</button>
</section>
<section class="features">
<div class="features__card">
<h3 class="features__title">Feature 1</h3>
<p class="features__text">Description</p>
</div>
<div class="features__card features__card--highlighted">
<h3 class="features__title">Feature 2</h3>
<p class="features__text">Description</p>
</div>
<div class="features__card">
<h3 class="features__title">Feature 3</h3>
<p class="features__text">Description</p>
</div>
</section>
/* ===== Block: main-nav ===== */
.main-nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 30px;
background: #1a1a2e;
}
.main-nav__logo {
color: white;
font-size: 1.5rem;
font-weight: bold;
}
.main-nav__links {
display: flex;
list-style: none;
gap: 20px;
margin: 0;
padding: 0;
}
.main-nav__link {
color: #ccc;
text-decoration: none;
}
.main-nav__link:hover {
color: white;
}
.main-nav__link--active {
color: white;
font-weight: bold;
}
.main-nav__cta {
background: #e74c3c;
color: white;
border: none;
padding: 8px 20px;
border-radius: 5px;
cursor: pointer;
}
/* ===== Block: hero ===== */
.hero {
text-align: center;
padding: 80px 20px;
background: linear-gradient(135deg, #1a1a2e, #16213e);
color: white;
}
.hero__title {
font-size: 3rem;
margin: 0 0 15px;
}
.hero__text {
font-size: 1.2rem;
margin: 0 0 25px;
color: #ccc;
}
.hero__button {
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
background: #3498db;
color: white;
}
.hero__button--large {
padding: 14px 32px;
font-size: 1.2rem;
}
/* ===== Block: features ===== */
.features {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
padding: 60px 30px;
}
.features__card {
background: white;
padding: 30px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
text-align: center;
}
.features__card--highlighted {
border: 2px solid #3498db;
transform: scale(1.05);
}
.features__title {
margin: 0 0 10px;
}
.features__text {
color: #666;
margin: 0;
}
גרסה עם CSS nesting:
.main-nav {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 30px;
background: #1a1a2e;
& .main-nav__logo {
color: white;
font-size: 1.5rem;
font-weight: bold;
}
& .main-nav__links {
display: flex;
list-style: none;
gap: 20px;
margin: 0;
padding: 0;
}
& .main-nav__link {
color: #ccc;
text-decoration: none;
&:hover { color: white; }
&--active { color: white; font-weight: bold; }
}
& .main-nav__cta {
background: #e74c3c;
color: white;
border: none;
padding: 8px 20px;
border-radius: 5px;
cursor: pointer;
}
}
תרגיל 7 - ערכים רספונסיביים עם calc ו-clamp¶
:root {
--sidebar-width: 250px;
--gap: 20px;
}
body {
margin: 0;
font-family: Arial, sans-serif;
}
.page {
display: flex;
min-height: 100vh;
}
.sidebar {
width: var(--sidebar-width);
flex-shrink: 0;
background: #1a1a2e;
color: white;
padding: clamp(15px, 3vw, 30px);
}
.main {
width: calc(100% - var(--sidebar-width) - var(--gap));
margin-left: var(--gap);
padding: clamp(15px, 3vw, 40px);
}
.container {
width: min(90%, 1200px);
margin: 0 auto;
}
.hero-section {
height: max(50vh, 400px);
background: linear-gradient(135deg, #3498db, #2ecc71);
display: grid;
place-items: center;
color: white;
text-align: center;
padding: clamp(20px, 5vw, 60px);
}
.hero-section h1 {
font-size: clamp(1.8rem, 5vw, 3.5rem);
margin-bottom: clamp(10px, 2vw, 20px);
}
.hero-section p {
font-size: clamp(1rem, 2vw, 1.3rem);
}
.content-section {
padding: clamp(30px, 5vw, 80px) 0;
}
.content-section h2 {
font-size: clamp(1.3rem, 3vw, 2rem);
margin-bottom: clamp(15px, 3vw, 30px);
}
.content-section p {
font-size: clamp(0.9rem, 1.5vw, 1.1rem);
line-height: 1.7;
max-width: min(100%, 70ch);
}
- אין אף media query - הכל מתאים את עצמו אוטומטית
calc()מחשב את רוחב ה-main על פי רוחב ה-sidebar וה-gapclamp()מגביל padding, font-size ו-spacing בין מינימום למקסימוםmin()מגביל את רוחב ה-containermax()מבטיח גובה מינימלי ל-hero70ch- רוחב מקסימלי של 70 תווים לטקסט - אידיאלי לקריאות