المشروع الختامي: بناء صفحة هبوط متجاوبة
نظرة عامة على المشروع
مرحبًا بك في الدرس الختامي لدورة CSS. في هذا المشروع الشامل، ستبني صفحة هبوط متجاوبة كاملة بجودة إنتاجية من الصفر، مطبقًا كل تقنية تعلمتها خلال الدورة. هذا ليس تمرينًا بسيطًا -- إنه مشروع كامل يجمع بين إعادة تعيين CSS والخصائص المخصصة وتنقل Flexbox وتخطيطات Grid وصور الخلفية مع طبقات التدرج وانتقالات التحويم ودعم الوضع الداكن وأفضل ممارسات إمكانية الوصول والتصميم المتجاوب بأسلوب الجوال أولاً في صفحة واحدة متماسكة.
صفحة الهبوط التي ستبنيها تتضمن سبعة أقسام متميزة: رأس متجاوب مع تنقل، وقسم بطل مع صورة خلفية وطبقة تدرج، وقسم ميزات ببطاقات Grid، وقسم شهادات، وجدول أسعار، وقسم دعوة لاتخاذ إجراء، وتذييل متعدد الأعمدة. يقدم كل قسم أنماط وتقنيات CSS محددة ستواجهها في المشاريع الحقيقية.
الخطوة 1: إعداد المشروع -- إعادة التعيين والخصائص المخصصة والأنماط الأساسية
يبدأ كل مشروع احترافي بأساس متين. نبدأ بإعادة تعيين افتراضيات المتصفح، وتعريف رموز التصميم كخصائص CSS مخصصة، وتأسيس أنماط الخطوط والتخطيط الأساسية. هذا الإعداد يضمن الاتساق عبر المتصفحات ويجعل التصميم بأكمله سهل الصيانة والتعديل.
إعادة تعيين CSS والخصائص المخصصة
/* ============================================
إعادة تعيين CSS -- توحيد افتراضيات المتصفح
============================================ */
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 16px;
scroll-behavior: smooth;
-webkit-text-size-adjust: 100%;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, sans-serif;
line-height: 1.6;
color: var(--text-primary);
background-color: var(--bg-primary);
transition: background-color 0.3s ease, color 0.3s ease;
}
img {
max-width: 100%;
height: auto;
display: block;
}
a {
text-decoration: none;
color: inherit;
}
ul, ol {
list-style: none;
}
button {
font: inherit;
cursor: pointer;
border: none;
background: none;
}
/* ============================================
رموز التصميم -- الخصائص المخصصة
============================================ */
:root {
/* اللوحة الأساسية */
--color-primary: #4f46e5;
--color-primary-light: #818cf8;
--color-primary-dark: #3730a3;
/* اللوحة المحايدة */
--color-white: #ffffff;
--color-gray-50: #f9fafb;
--color-gray-100: #f3f4f6;
--color-gray-200: #e5e7eb;
--color-gray-300: #d1d5db;
--color-gray-500: #6b7280;
--color-gray-700: #374151;
--color-gray-800: #1f2937;
--color-gray-900: #111827;
/* الألوان الدلالية (افتراضيات الوضع الفاتح) */
--bg-primary: var(--color-white);
--bg-secondary: var(--color-gray-50);
--bg-card: var(--color-white);
--text-primary: var(--color-gray-900);
--text-secondary: var(--color-gray-500);
--text-heading: var(--color-gray-800);
--border-color: var(--color-gray-200);
/* التمييز */
--color-accent: #f59e0b;
--color-success: #10b981;
--color-danger: #ef4444;
/* مقياس المسافات */
--space-xs: 0.25rem;
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 1.5rem;
--space-xl: 2rem;
--space-2xl: 3rem;
--space-3xl: 4rem;
--space-4xl: 6rem;
/* مقياس الخطوط */
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
--text-4xl: 2.25rem;
--text-5xl: 3rem;
/* التخطيط */
--container-max: 1200px;
--header-height: 72px;
--border-radius: 8px;
--border-radius-lg: 16px;
/* الظلال */
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.08);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.12);
--shadow-xl: 0 20px 48px rgba(0, 0, 0, 0.15);
/* الانتقالات */
--transition-fast: 150ms ease;
--transition-base: 300ms ease;
--transition-slow: 500ms ease;
}
/* ============================================
فئات الأدوات الأساسية
============================================ */
.container {
width: 100%;
max-width: var(--container-max);
margin: 0 auto;
padding: 0 var(--space-lg);
}
.section-title {
font-size: var(--text-3xl);
font-weight: 700;
color: var(--text-heading);
text-align: center;
margin-bottom: var(--space-md);
}
.section-subtitle {
font-size: var(--text-lg);
color: var(--text-secondary);
text-align: center;
max-width: 600px;
margin: 0 auto var(--space-3xl);
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0.75rem 1.75rem;
font-size: var(--text-base);
font-weight: 600;
border-radius: var(--border-radius);
transition: transform var(--transition-fast),
box-shadow var(--transition-fast),
background-color var(--transition-fast);
}
.btn:active {
transform: translateY(1px) scale(0.98);
}
.btn-primary {
background-color: var(--color-primary);
color: var(--color-white);
}
.btn-primary:hover {
background-color: var(--color-primary-dark);
box-shadow: var(--shadow-md);
transform: translateY(-2px);
}
.btn-outline {
border: 2px solid var(--color-primary);
color: var(--color-primary);
background: transparent;
}
.btn-outline:hover {
background-color: var(--color-primary);
color: var(--color-white);
transform: translateY(-2px);
}
الخطوة 2: الرأس والتنقل المتجاوب مع Flexbox
يستخدم الرأس Flexbox لمحاذاة الشعار وروابط التنقل أفقيًا. على الأجهزة المحمولة، ينهار التنقل إلى قائمة همبرغر يتم تبديلها بخدعة مربع الاختيار (CSS نقي، بدون JavaScript). يستخدم الرأس أيضًا موضعًا ثابتًا لذا يظل مرئيًا أثناء تمرير المستخدم.
HTML: بنية الرأس
<header class="header">
<div class="container header__inner">
<a href="#" class="header__logo">
<span class="logo-icon"></></span>
<span class="logo-text">DevLand</span>
</a>
<!-- خدعة مربع الاختيار لتبديل القائمة المحمولة -->
<input type="checkbox" id="nav-toggle" class="nav-toggle" aria-hidden="true">
<label for="nav-toggle" class="nav-toggle-label" aria-label="تبديل التنقل">
<span class="hamburger"></span>
</label>
<nav class="header__nav" aria-label="التنقل الرئيسي">
<ul class="nav-list">
<li><a href="#features" class="nav-link">الميزات</a></li>
<li><a href="#testimonials" class="nav-link">الشهادات</a></li>
<li><a href="#pricing" class="nav-link">الأسعار</a></li>
<li><a href="#cta" class="nav-link nav-link--cta">ابدأ الآن</a></li>
</ul>
</nav>
</div>
</header>
CSS: الرأس والتنقل
/* ============================================
الرأس -- تنقل ثابت مع Flexbox
============================================ */
.header {
position: sticky;
top: 0;
z-index: 1000;
height: var(--header-height);
background-color: var(--bg-primary);
border-bottom: 1px solid var(--border-color);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
background-color: rgba(255, 255, 255, 0.85);
}
.header__inner {
display: flex;
align-items: center;
justify-content: space-between;
height: 100%;
}
.header__logo {
display: flex;
align-items: center;
gap: var(--space-sm);
font-size: var(--text-xl);
font-weight: 700;
color: var(--text-heading);
z-index: 10;
}
.logo-icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
background-color: var(--color-primary);
color: var(--color-white);
border-radius: var(--border-radius);
font-size: var(--text-sm);
font-family: monospace;
}
.nav-list {
display: flex;
align-items: center;
gap: var(--space-xl);
}
.nav-link {
font-size: var(--text-base);
font-weight: 500;
color: var(--text-secondary);
transition: color var(--transition-fast);
position: relative;
}
.nav-link::after {
content: '';
position: absolute;
bottom: -4px;
left: 0;
width: 0;
height: 2px;
background-color: var(--color-primary);
transition: width var(--transition-base);
}
.nav-link:hover {
color: var(--color-primary);
}
.nav-link:hover::after {
width: 100%;
}
.nav-link--cta {
background-color: var(--color-primary);
color: var(--color-white) !important;
padding: 0.5rem 1.25rem;
border-radius: var(--border-radius);
transition: background-color var(--transition-fast),
transform var(--transition-fast);
}
.nav-link--cta::after {
display: none;
}
.nav-link--cta:hover {
background-color: var(--color-primary-dark);
transform: translateY(-1px);
}
.nav-toggle {
display: none;
}
.nav-toggle-label {
display: none;
cursor: pointer;
z-index: 10;
}
.hamburger,
.hamburger::before,
.hamburger::after {
display: block;
width: 24px;
height: 2px;
background-color: var(--text-primary);
transition: transform var(--transition-base),
opacity var(--transition-fast);
}
.hamburger {
position: relative;
}
.hamburger::before,
.hamburger::after {
content: '';
position: absolute;
left: 0;
}
.hamburger::before { top: -7px; }
.hamburger::after { top: 7px; }
/* التنقل المحمول */
@media (max-width: 768px) {
.nav-toggle-label {
display: flex;
align-items: center;
justify-content: center;
width: 44px;
height: 44px;
}
.header__nav {
position: fixed;
top: var(--header-height);
left: 0;
width: 100%;
height: calc(100vh - var(--header-height));
background-color: var(--bg-primary);
transform: translateX(100%);
transition: transform var(--transition-base);
}
.nav-list {
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--space-2xl);
height: 100%;
padding: var(--space-2xl);
}
.nav-link {
font-size: var(--text-2xl);
}
.nav-toggle:checked ~ .header__nav {
transform: translateX(0);
}
.nav-toggle:checked ~ .nav-toggle-label .hamburger {
background-color: transparent;
}
.nav-toggle:checked ~ .nav-toggle-label .hamburger::before {
top: 0;
transform: rotate(45deg);
}
.nav-toggle:checked ~ .nav-toggle-label .hamburger::after {
top: 0;
transform: rotate(-45deg);
}
}
<input type="checkbox"> مخفيًا مقترنًا بـ <label> لإنشاء آلية تبديل بدون JavaScript. المحدد الشقيق في CSS .nav-toggle:checked ~ .header__nav يستهدف عنصر التنقل عندما يكون مربع الاختيار محددًا. هذا نمط مستخدم على نطاق واسع للقوائم المحمولة القابلة للوصول. خاصية aria-label على التسمية تضمن أن قارئات الشاشة تعلن عن غرض التبديل.الخطوة 3: قسم البطل مع صورة خلفية وطبقة تدرج
ينشئ قسم البطل انطباعًا أوليًا دراماتيكيًا باستخدام صورة خلفية بعرض كامل مع طبقة تدرج شبه شفافة. المحتوى مركز عموديًا وأفقيًا باستخدام Flexbox. تضمن طبقة التدرج بقاء النص مقروءًا بغض النظر عن صورة الخلفية.
CSS: قسم البطل
/* ============================================
قسم البطل -- عرض كامل مع طبقة تدرج
============================================ */
.hero {
position: relative;
min-height: calc(100vh - var(--header-height));
display: flex;
align-items: center;
justify-content: center;
background: var(--color-gray-900) url('hero-bg.jpg')
center / cover no-repeat;
overflow: hidden;
}
.hero__overlay {
position: absolute;
inset: 0;
background: linear-gradient(
135deg,
rgba(17, 24, 39, 0.92) 0%,
rgba(79, 70, 229, 0.75) 100%
);
z-index: 1;
}
.hero__content {
position: relative;
z-index: 2;
text-align: center;
padding: var(--space-4xl) 0;
max-width: 800px;
}
.hero__title {
font-size: var(--text-5xl);
font-weight: 800;
color: var(--color-white);
line-height: 1.1;
margin-bottom: var(--space-lg);
text-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
}
.hero__subtitle {
font-size: var(--text-xl);
color: var(--color-gray-300);
margin-bottom: var(--space-2xl);
line-height: 1.7;
}
.hero__actions {
display: flex;
gap: var(--space-md);
justify-content: center;
flex-wrap: wrap;
}
.btn--lg {
padding: 1rem 2.25rem;
font-size: var(--text-lg);
}
@media (max-width: 768px) {
.hero__title {
font-size: var(--text-3xl);
}
.hero__subtitle {
font-size: var(--text-base);
}
.hero__content {
padding: var(--space-2xl) 0;
}
}
الخطوة 4: قسم الميزات مع بطاقات CSS Grid
يستخدم قسم الميزات CSS Grid لترتيب بطاقات الميزات في تخطيط متجاوب. تتكيف الشبكة تلقائيًا من ثلاثة أعمدة على سطح المكتب إلى عمود واحد على الجوال باستخدام كلمة auto-fit مع minmax(). تتضمن كل بطاقة تأثيرات تحويم مع انتقالات سلسة.
CSS: شبكة الميزات والبطاقات
/* ============================================
قسم الميزات -- تخطيط شبكة مع بطاقات
============================================ */
.features {
padding: var(--space-4xl) 0;
background-color: var(--bg-secondary);
}
.features__grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--space-xl);
}
.feature-card {
background-color: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: var(--border-radius-lg);
padding: var(--space-2xl);
text-align: center;
transition: transform var(--transition-base),
box-shadow var(--transition-base);
}
.feature-card:hover {
transform: translateY(-8px);
box-shadow: var(--shadow-lg);
}
.feature-card__icon {
font-size: 2.5rem;
margin-bottom: var(--space-lg);
display: inline-flex;
align-items: center;
justify-content: center;
width: 72px;
height: 72px;
border-radius: 50%;
background-color: rgba(79, 70, 229, 0.1);
}
.feature-card__title {
font-size: var(--text-xl);
font-weight: 700;
color: var(--text-heading);
margin-bottom: var(--space-sm);
}
.feature-card__desc {
font-size: var(--text-base);
color: var(--text-secondary);
line-height: 1.7;
}
@media (max-width: 640px) {
.features__grid {
grid-template-columns: 1fr;
}
}
الخطوة 5: قسم الشهادات
يستخدم قسم الشهادات Grid لترتيب اقتباسات العملاء. تتضمن كل بطاقة شهادة عنصر زخرفي لعلامة الاقتباس مُنشأ بعنصر زائف وتنسيق دقيق.
CSS: الشهادات
/* ============================================
قسم الشهادات
============================================ */
.testimonials {
padding: var(--space-4xl) 0;
background-color: var(--bg-primary);
}
.testimonials__grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--space-xl);
}
.testimonial-card {
background-color: var(--bg-secondary);
border-radius: var(--border-radius-lg);
padding: var(--space-2xl);
position: relative;
transition: transform var(--transition-base);
}
.testimonial-card:hover {
transform: translateY(-4px);
}
.testimonial-card::before {
content: '\201C';
position: absolute;
top: var(--space-md);
right: var(--space-xl);
font-size: 4rem;
line-height: 1;
color: var(--color-primary-light);
opacity: 0.3;
font-family: Georgia, serif;
}
.testimonial-card__text {
font-size: var(--text-base);
color: var(--text-primary);
line-height: 1.8;
margin-bottom: var(--space-xl);
padding-top: var(--space-lg);
font-style: italic;
}
.testimonial-card__author {
display: flex;
align-items: center;
gap: var(--space-md);
}
.author-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
background-color: var(--color-primary);
color: var(--color-white);
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: var(--text-sm);
flex-shrink: 0;
}
.author-name {
display: block;
font-style: normal;
font-weight: 600;
color: var(--text-heading);
}
.author-role {
font-size: var(--text-sm);
color: var(--text-secondary);
}
الخطوة 6: جدول الأسعار مع Grid وتأثيرات التحويم
قسم الأسعار هو واحد من أكثر المكونات تعقيدًا. يستخدم CSS Grid لمحاذاة ثلاث مستويات أسعار، مع إبراز المستوى "الشائع" الأوسط بصريًا عن طريق التحجيم وحد ملون وشارة. تستجيب كل بطاقة للتحويم برفع دقيق وتحسين ظل.
CSS: جدول الأسعار
/* ============================================
قسم الأسعار -- شبكة مع بطاقة مميزة
============================================ */
.pricing {
padding: var(--space-4xl) 0;
background-color: var(--bg-secondary);
}
.pricing__grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--space-xl);
align-items: start;
}
.pricing-card {
background-color: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: var(--border-radius-lg);
padding: var(--space-2xl);
text-align: center;
position: relative;
transition: transform var(--transition-base),
box-shadow var(--transition-base);
}
.pricing-card:hover {
transform: translateY(-6px);
box-shadow: var(--shadow-lg);
}
.pricing-card--popular {
border: 2px solid var(--color-primary);
transform: scale(1.05);
box-shadow: var(--shadow-xl);
z-index: 1;
}
.pricing-card--popular:hover {
transform: scale(1.05) translateY(-6px);
box-shadow: var(--shadow-xl);
}
.pricing-card__badge {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
background-color: var(--color-primary);
color: var(--color-white);
font-size: var(--text-sm);
font-weight: 600;
padding: 0.25rem 1rem;
border-radius: 50px;
white-space: nowrap;
}
.pricing-card__name {
font-size: var(--text-xl);
font-weight: 600;
color: var(--text-heading);
margin-bottom: var(--space-md);
}
.pricing-card__price {
margin-bottom: var(--space-xl);
display: flex;
align-items: baseline;
justify-content: center;
gap: 2px;
}
.price-currency {
font-size: var(--text-xl);
font-weight: 600;
color: var(--text-secondary);
}
.price-amount {
font-size: var(--text-5xl);
font-weight: 800;
color: var(--text-heading);
line-height: 1;
}
.price-period {
font-size: var(--text-base);
color: var(--text-secondary);
}
.pricing-card__features {
margin-bottom: var(--space-xl);
text-align: right;
}
.pricing-card__features li {
padding: 0.6rem 0;
color: var(--text-primary);
border-bottom: 1px solid var(--border-color);
font-size: var(--text-base);
}
.pricing-card__features li::before {
content: '\2713';
margin-left: var(--space-sm);
color: var(--color-success);
font-weight: 700;
}
.pricing-card__features li.feature--disabled {
color: var(--text-secondary);
text-decoration: line-through;
opacity: 0.5;
}
.pricing-card__features li.feature--disabled::before {
content: '\2717';
color: var(--text-secondary);
}
.pricing-card__btn {
width: 100%;
}
@media (max-width: 900px) {
.pricing__grid {
grid-template-columns: 1fr;
max-width: 450px;
margin: 0 auto;
}
.pricing-card--popular {
transform: scale(1);
order: -1;
}
.pricing-card--popular:hover {
transform: translateY(-6px);
}
}
الخطوة 7: قسم الدعوة لاتخاذ إجراء مع خلفية متدرجة
يستخدم قسم الدعوة لاتخاذ إجراء خلفية متدرجة جريئة لجذب الانتباه وتشجيع التحويل. التخطيط بسيط ومركز، يستخدم Flexbox لتوسيط المحتوى.
CSS: قسم الدعوة لاتخاذ إجراء
/* ============================================
قسم الدعوة لاتخاذ إجراء -- خلفية متدرجة
============================================ */
.cta {
padding: var(--space-4xl) 0;
background: linear-gradient(
135deg,
var(--color-primary-dark) 0%,
var(--color-primary) 50%,
var(--color-primary-light) 100%
);
text-align: center;
}
.cta__content {
max-width: 700px;
}
.cta__title {
font-size: var(--text-4xl);
font-weight: 800;
color: var(--color-white);
margin-bottom: var(--space-md);
}
.cta__text {
font-size: var(--text-lg);
color: rgba(255, 255, 255, 0.85);
margin-bottom: var(--space-2xl);
line-height: 1.7;
}
.btn-white {
background-color: var(--color-white);
color: var(--color-primary);
font-weight: 700;
}
.btn-white:hover {
background-color: var(--color-gray-100);
transform: translateY(-2px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
}
@media (max-width: 768px) {
.cta__title {
font-size: var(--text-2xl);
}
}
الخطوة 8: التذييل مع شبكة CSS متعددة الأعمدة
يستخدم التذييل CSS Grid لإنشاء تخطيط متعدد الأعمدة مع عمود شعار وروابط تنقل وروابط اجتماعية. على الجوال، تنهار الشبكة إلى تخطيط متراص.
CSS: التذييل
/* ============================================
التذييل -- تخطيط شبكة متعدد الأعمدة
============================================ */
.footer {
padding: var(--space-4xl) 0 var(--space-xl);
background-color: var(--color-gray-900);
color: var(--color-gray-300);
}
.footer__grid {
display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr;
gap: var(--space-2xl);
margin-bottom: var(--space-3xl);
}
.footer__brand {
max-width: 300px;
}
.footer__brand .logo-text {
color: var(--color-white);
}
.footer__desc {
font-size: var(--text-sm);
line-height: 1.7;
color: var(--color-gray-500);
}
.footer__heading {
font-size: var(--text-base);
font-weight: 600;
color: var(--color-white);
margin-bottom: var(--space-lg);
}
.footer__links li {
margin-bottom: var(--space-sm);
}
.footer__links a {
font-size: var(--text-sm);
color: var(--color-gray-500);
transition: color var(--transition-fast);
}
.footer__links a:hover {
color: var(--color-white);
}
.footer__bottom {
padding-top: var(--space-xl);
border-top: 1px solid rgba(255, 255, 255, 0.1);
text-align: center;
font-size: var(--text-sm);
color: var(--color-gray-500);
}
@media (max-width: 768px) {
.footer__grid {
grid-template-columns: 1fr 1fr;
gap: var(--space-2xl);
}
.footer__brand {
grid-column: 1 / -1;
max-width: 100%;
}
}
@media (max-width: 480px) {
.footer__grid {
grid-template-columns: 1fr;
}
}
الخطوة 9: الوضع الداكن مع الخصائص المخصصة
يتم تنفيذ الوضع الداكن عن طريق إعادة تعريف الخصائص المخصصة الدلالية داخل محدد [data-theme="dark"]. لأن التصميم بأكمله يستخدم الخصائص المخصصة للألوان، فإن تبديل السمات يتطلب تغيير قيم المتغيرات فقط. يبقى CSS البنيوي دون تغيير تمامًا.
CSS: سمة الوضع الداكن
/* ============================================
الوضع الداكن -- تجاوز المتغيرات الدلالية
============================================ */
[data-theme="dark"] {
--bg-primary: var(--color-gray-900);
--bg-secondary: var(--color-gray-800);
--bg-card: var(--color-gray-800);
--text-primary: var(--color-gray-100);
--text-secondary: var(--color-gray-500);
--text-heading: var(--color-white);
--border-color: rgba(255, 255, 255, 0.1);
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.5);
--shadow-xl: 0 20px 48px rgba(0, 0, 0, 0.6);
}
[data-theme="dark"] .header {
background-color: rgba(17, 24, 39, 0.85);
}
[data-theme="dark"] .feature-card__icon {
background-color: rgba(129, 140, 248, 0.15);
}
/* احترام تفضيل النظام مع prefers-color-scheme */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--bg-primary: var(--color-gray-900);
--bg-secondary: var(--color-gray-800);
--bg-card: var(--color-gray-800);
--text-primary: var(--color-gray-100);
--text-secondary: var(--color-gray-500);
--text-heading: var(--color-white);
--border-color: rgba(255, 255, 255, 0.1);
}
}
الخطوة 10: أفضل ممارسات إمكانية الوصول
إمكانية الوصول ليست إضافة اختيارية؛ إنها متطلب أساسي لتطوير الويب الاحترافي. أنماط CSS التالية تضمن أن صفحة الهبوط قابلة للاستخدام من قبل الجميع، بما في ذلك الأشخاص الذين يتنقلون بلوحة المفاتيح أو يستخدمون قارئات الشاشة أو لديهم حساسية للحركة.
CSS: تحسينات إمكانية الوصول
/* ============================================
إمكانية الوصول -- التركيز والحركة والتباين
============================================ */
/* أنماط تركيز مرئية للتنقل بلوحة المفاتيح */
*:focus-visible {
outline: 3px solid var(--color-primary);
outline-offset: 2px;
border-radius: 2px;
}
/* إزالة الحد الخارجي لمستخدمي الفأرة */
*:focus:not(:focus-visible) {
outline: none;
}
/* رابط تخطي التنقل لقارئات الشاشة */
.skip-link {
position: absolute;
top: -100%;
left: var(--space-md);
padding: var(--space-sm) var(--space-md);
background-color: var(--color-primary);
color: var(--color-white);
font-weight: 600;
border-radius: var(--border-radius);
z-index: 9999;
transition: top var(--transition-fast);
}
.skip-link:focus {
top: var(--space-md);
}
/* احترام تفضيلات تقليل الحركة */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
/* ضمان تباين كافٍ على العناصر التفاعلية */
.nav-link:focus-visible {
color: var(--color-primary);
background-color: rgba(79, 70, 229, 0.1);
padding: 0.25rem 0.5rem;
border-radius: var(--border-radius);
}
/* فئة أداة لقارئ الشاشة فقط */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* دعم وضع التباين العالي */
@media (forced-colors: active) {
.btn-primary,
.btn-outline,
.btn-white {
border: 2px solid ButtonText;
}
.pricing-card--popular {
border: 3px solid Highlight;
}
}
:focus-visible ضرورية لإمكانية الوصول الحديثة في الويب. تطبق أنماط التركيز فقط عندما يتنقل المستخدم بلوحة المفاتيح (مفتاح Tab)، وليس عند النقر بالفأرة. هذا يمنح مستخدمي لوحة المفاتيح مؤشرات بصرية واضحة لمكانهم في الصفحة دون إضافة حدود مشتتة لكل نقرة فأرة. مع prefers-reduced-motion: reduce، تشكل هاتان الميزتان الحد الأدنى لخط أساس إمكانية الوصول الذي يجب أن يتضمنه كل موقع.الخطوة 11: أفضل ممارسات الأداء
يجب أن تكون صفحة الهبوط المصممة بشكل جيد عالية الأداء أيضًا. ممارسات CSS التالية تضمن تحميلًا سريعًا ورسومًا متحركة سلسة وعرضًا فعالًا.
CSS: تحسينات الأداء
/* ============================================
الأداء -- أنماط CSS فعالة
============================================ */
/* استخدم will-change باعتدال، فقط على العناصر المتحركة */
.feature-card,
.pricing-card,
.testimonial-card {
will-change: transform;
}
/* استخدم content-visibility للأقسام أسفل الطية */
.features,
.testimonials,
.pricing,
.cta {
content-visibility: auto;
contain-intrinsic-size: 0 600px;
}
/* فضّل transform و opacity للرسوم المتحركة (مسرّعة بـ GPU) */
/* تجنب تحريك: width, height, top, left, margin, padding */
/* فضّل تحريك: transform, opacity, filter */
/* حالات تحويم فعالة باستخدام translate بدل margin */
.feature-card:hover {
transform: translateY(-8px);
}
/* تقليل مساحة الرسم مع contain */
.feature-card {
contain: layout style;
}
بنية مستند HTML الكاملة
إليك مستند HTML الكامل الذي يربط جميع الأقسام معًا مع عناصر دلالية صحيحة ووسوم meta ورابط التخطي للتنقل لإمكانية الوصول.
بنية HTML الكاملة
<!DOCTYPE html>
<html lang="ar" dir="rtl" data-theme="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="أتقن CSS الحديث وابنِ مواقع ويب متجاوبة جميلة">
<title>DevLand - أتقن CSS الحديث</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<a href="#main-content" class="skip-link">تخطي إلى المحتوى الرئيسي</a>
<header class="header">
<!-- ... محتوى الرأس من الخطوة 2 ... -->
</header>
<main id="main-content">
<section class="hero">
<!-- ... محتوى البطل من الخطوة 3 ... -->
</section>
<section class="features" id="features">
<!-- ... محتوى الميزات من الخطوة 4 ... -->
</section>
<section class="testimonials" id="testimonials">
<!-- ... محتوى الشهادات من الخطوة 5 ... -->
</section>
<section class="pricing" id="pricing">
<!-- ... محتوى الأسعار من الخطوة 6 ... -->
</section>
<section class="cta" id="cta">
<!-- ... محتوى الدعوة لاتخاذ إجراء من الخطوة 7 ... -->
</section>
</main>
<footer class="footer">
<!-- ... محتوى التذييل من الخطوة 8 ... -->
</footer>
</body>
</html>
<header>، <main>، <section>، <article>، <nav>، <footer>، <blockquote>، و <cite>. هذه العناصر تنقل المعنى لقارئات الشاشة ومحركات البحث. خصائص aria-label على التنقل وزر التبديل توفر سياقًا إضافيًا للتقنيات المساعدة. رابط التخطي يسمح لمستخدمي لوحة المفاتيح بالقفز متجاوزين التنقل مباشرة إلى المحتوى الرئيسي.التمرين الختامي
ابنِ صفحة الهبوط هذه بالكامل من الصفر باتباع الخطوات في هذا الدرس. اكتب كل سطر CSS بنفسك لبناء الذاكرة العضلية. بعد إكمال التنفيذ الأساسي، وسّع المشروع بالتحديات التالية: (1) أضف رسمًا متحركًا سلسًا لظهور تدريجي عند التمرير لكل قسم باستخدام @keyframes و animation (مع احترام prefers-reduced-motion). (2) أنشئ زر تبديل سمة في الرأس يتبدل بين الوضع الفاتح والداكن عن طريق تبديل خاصية data-theme على عنصر <html>. (3) أضف زر "العودة للأعلى" عائمًا يظهر عندما يمرر المستخدم متجاوزًا قسم البطل، باستخدام position: fixed وانتقال translate سلس. (4) أنشئ نسخة شريط جانبي بديلة للتنقل متوافقة مع الجوال باستخدام تحويلات CSS. (5) أضف تأثير تمرير متباين دقيق لصورة خلفية البطل باستخدام background-attachment: fixed. (6) نفّذ قسم أسئلة شائعة بأكورديون CSS فقط أسفل جدول الأسعار. (7) اختبر الصفحة الكاملة في أدوات المطورين لـ Chrome و Firefox و Safari، مع التحقق من تخطيطات Grid و Flexbox بمفتشيها المخصصين، وفحص جميع نسب تباين الألوان، وتأكيد أن الرسوم المتحركة تعمل بمعدل 60 إطارًا في الثانية باستخدام لوحة الأداء. (8) شغّل فحص Lighthouse وحسّن حتى تحصل على درجة أعلى من 95 في إمكانية الوصول والأداء. وثّق كل قرار تصميم وتقنيات CSS التي استخدمتها لكل قسم.