طراحی وب با HTML و CSS فهرست مطالب
فصل ۱۴

پروژه نهایی: سایت دبیرستان دانش

سیزده فصل مفهوم یاد گرفتیم. حالا همه را کنار هم می‌گذاریم و یک سایت هفت‌صفحه‌ای واقعی و واکنش‌گرا می‌سازیم، گام به گام.

در این فصل با این مباحث آشنا می‌شوید
  1. نقشه پروژه
  2. گام ۱: پایه طراحی
  3. گام ۲: صفحه اصلی
  4. گام ۳: صفحه درباره ما و اتصال صفحه‌ها
  5. گام ۴: صفحه رشته‌ها
  6. گام ۵: صفحه دبیران
  7. گام ۶: صفحه گالری
  8. گام ۷: صفحه اخبار
  9. گام ۸: صفحه تماس
  10. گام ۹: پرداخت نهایی
  11. گام ۱۰: بررسی و تحویل

۱. نقشه پروژه

پروژه ما سایت یک دبیرستان خیالی به نام دبیرستان دانش است. هفت صفحه دارد و هر صفحه یک فایل HTML است، اما هر هفت صفحه به یک فایل style.css وصل می‌شوند.

فایلمحتوا
index.htmlصفحه اصلی: هدر بزرگ، امکانات، آمار، پیش‌نمایش اخبار
about.htmlدرباره ما: تاریخچه و اهداف مدرسه
programs.htmlسه رشته تحصیلی
teachers.htmlمعرفی دبیران
gallery.htmlگالری تصاویر
news.htmlاخبار و اطلاعیه‌ها
contact.htmlفرم تماس و اطلاعات ارتباطی

روش کار: ساخت تجمعی

این پروژه را در ده گام می‌سازیم و هر گام یک پوشه کامل و قابل اجراست. یعنی پوشه گام سوم، همه چیز گام دوم را دارد به‌علاوه صفحه تازه. به این صورت اگر جایی گم شدید، می‌توانید پوشه گام قبل را باز کنید و ببینید کد در آن مرحله چه شکلی بوده است.

قانون طلایی این پروژه

در این سایت از هیچ چیزی استفاده نمی‌کنیم که تا فصل سیزدهم یاد نگرفته باشیم. هیچ کتابخانه‌ای، هیچ جاوااسکریپتی و هیچ فایلی از اینترنت. همه چیز دست‌ساز و محلی است.

۲. گام ۱: پایه طراحی

هیچ‌وقت یک پروژه را با نوشتن HTML شروع نکنید. اول باید تصمیم بگیرید رنگ‌ها، قلم، فاصله‌ها و اندازه‌ها چه باشند. به این مجموعه تصمیم‌ها راهنمای سبک می‌گویند.

/* ---------- متغیرهای سایت ---------- */
:root {
    --primary: #2f4f4f;
    --primary-dark: #1c3333;
    --accent: #ff6347;
    --bg-light: #f5f5f5;
    --text: #333333;
    --muted: #666666;
    --border: #dddddd;
    --radius: 10px;
    --shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.06);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.12);
    --shadow-lg: 0 10px 26px rgba(0, 0, 0, 0.16);
}

/* ---------- ریست پایه ---------- */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: Tahoma, sans-serif;
}

html {
    direction: rtl;
    font-size: 16px;
    scroll-behavior: smooth;
}

body {
    color: var(--text);
    line-height: 1.8;
    background-color: #ffffff;
}

a {
    color: inherit;
    text-decoration: none;
}

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

/* ---------- ظرف استاندارد ---------- */
.container {
    max-width: 1100px;
    margin: 0 auto;
    padding: 0 20px;
}

پایه طراحی: پوشه 01-design-foundation

شرح مثال

این چند خط، پایه تمام هفت صفحه است. هر قسمتش دلیلی دارد:

چرا ۱۱۰۰ پیکسل

چشم انسان نمی‌تواند خط‌های بسیار بلند را آسان دنبال کند. محدود کردن عرض محتوا در همه سایت‌های حرفه‌ای انجام می‌شود و عدد رایجش بین ۱۰۰۰ تا ۱۲۰۰ پیکسل است.

۳. گام ۲: صفحه اصلی

صفحه اصلی مهم‌ترین صفحه است و چهار بخش دارد. اول اسکلت مشترکی که در هر هفت صفحه تکرار می‌شود:

<body>

<header class="site-header">
    <div class="container">
        <a href="index.html" class="logo">🎓 دبیرستان دانش</a>
        <nav>
            <a href="index.html" class="active">خانه</a>
            <a href="about.html">درباره ما</a>
            <a href="programs.html">رشته‌ها</a>
            <a href="teachers.html">دبیران</a>
            <a href="gallery.html">گالری</a>
            <a href="news.html">اخبار</a>
            <a href="contact.html">تماس با ما</a>
        </nav>
    </div>
</header>

<!-- محتوای مخصوص هر صفحه اینجا -->

<footer class="site-footer">
    <div class="container">
        <p>دبیرستان دانش - تهران، خیابان آزادی</p>
    </div>
</footer>

</body>
.site-header {
    background-color: var(--primary);
    color: #ffffff;
    position: sticky;
    top: 0;
    z-index: 100;
    box-shadow: var(--shadow-sm);
}

.site-header .container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    padding-top: 15px;
    padding-bottom: 15px;
}

.logo {
    font-size: 1.15rem;
    font-weight: bold;
}

.site-header nav {
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
}

.site-header nav a {
    padding: 5px 2px;
    border-bottom: 2px solid transparent;
    transition: color 0.3s, border-color 0.3s;
}

.site-header nav a:hover,
.site-header nav a.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

سربرگ مشترک: پوشه 02-home-page

شرح مثال

این سربرگ در هر هفت صفحه عیناً تکرار می‌شود و تنها جای کلاس active عوض می‌شود. آن کلاس به کاربر نشان می‌دهد الان در کدام صفحه است، که برای گم نشدن در سایت لازم است.

در این کد هفت مفهوم از هفت فصل مختلف کنار هم آمده‌اند:

هدر بزرگ صفحه اصلی

<section class="hero">
    <div class="container">
        <h1>به دبیرستان دانش خوش آمدید</h1>
        <p>آموزش با کیفیت در محیطی آرام و پویا</p>
        <a href="programs.html" class="btn">رشته‌های ما</a>
    </div>
</section>
.hero {
    background-image:
        linear-gradient(rgba(20, 40, 40, 0.72), rgba(20, 40, 40, 0.72)),
        url('images/hero-classroom.jpg');
    background-size: cover;
    background-position: center;
    color: #ffffff;
    text-align: center;
    padding: 110px 0;
}

.hero h1 {
    font-size: 2.2rem;
    margin-bottom: 15px;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
}

.btn {
    display: inline-block;
    background-color: var(--accent);
    color: #ffffff;
    padding: 13px 34px;
    border-radius: var(--radius);
    margin-top: 25px;
    transition: transform 0.3s, background-color 0.3s;
}

.btn:hover {
    transform: translateY(-3px);
    background-color: #e5533d;
}

هدر بزرگ صفحه اصلی

این همان تکنیک «پرده تیره روی عکس» فصل سیزدهم است. بدون آن پرده، متن سفید روی عکس روشن کلاس درس اصلاً خوانده نمی‌شد.

۴. گام ۳: صفحه درباره ما و اتصال صفحه‌ها

حالا اولین صفحه داخلی را می‌سازیم. صفحه‌های داخلی به جای هدر بزرگ، یک نوار عنوان کوتاه‌تر دارند.

<div class="page-banner"
     style="background-image: linear-gradient(rgba(20,40,40,0.7), rgba(20,40,40,0.7)),
            url('images/about-building.jpg');">
    <div class="container">
        <h1>درباره ما</h1>
    </div>
</div>

<section class="section">
    <div class="container">
        <h2 class="section-title">تاریخچه مدرسه</h2>
        <p>دبیرستان دانش از سال ۱۳۷۵ فعالیت می‌کند...</p>
    </div>
</section>
.page-banner {
    background-size: cover;
    background-position: center;
    color: #ffffff;
    padding: 70px 0;
    text-align: center;
}

.section {
    padding: 55px 0;
}

.section-title {
    position: relative;
    color: var(--primary);
    font-size: 1.6rem;
    padding-bottom: 14px;
    margin-bottom: 28px;
}

.section-title::after {
    content: "";
    position: absolute;
    right: 0;
    bottom: 0;
    width: 60px;
    height: 4px;
    background-color: var(--accent);
    border-radius: 2px;
}

نوار عنوان و عنوان بخش: پوشه 03-about-page

شرح مثال

section-title. با خط تزیینی after:: در تمام هفت صفحه استفاده می‌شود. این تکرار عمدی است و به سایت هویت بصری واحد می‌دهد.

درباره آن style درون‌خطی

در فصل سوم گفتیم CSS درون‌خطی روش خوبی نیست، اما اینجا برای عکس نوار عنوان از آن استفاده کرده‌ایم. دلیلش این است که هر صفحه عکس متفاوتی دارد و این روش برای دانش‌آموز بسیار روشن‌تر است. راه تمیزتر، ساختن هفت کلاس جداگانه مانند banner-about. و banner-programs. در فایل CSS است. هر دو راه درست‌اند؛ این یک انتخاب سلیقه‌ای است.

اتصال صفحه‌ها

از این گام به بعد، منوی سربرگ واقعاً کار می‌کند. چون همه فایل‌ها در یک پوشه هستند، لینک‌ها به شکل ساده و نسبی نوشته می‌شوند: href="about.html". همان درس فصل دوم درباره مسیرها.

۵. گام ۴: صفحه رشته‌ها

<section class="section">
    <div class="container">
        <h2 class="section-title">رشته‌های تحصیلی</h2>

        <div class="cards">
            <article class="card">
                <img src="images/math-class.jpg" alt="کلاس ریاضی">
                <div class="card-body">
                    <h3>ریاضی و فیزیک</h3>
                    <p>مناسب علاقه‌مندان به مهندسی و علوم پایه</p>
                </div>
            </article>
            <!-- دو کارت دیگر -->
        </div>
    </div>
</section>
.cards {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 25px;
}

.card {
    background-color: #ffffff;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    transition: transform 0.3s, box-shadow 0.3s;
}

.card:hover {
    transform: translateY(-6px);
    box-shadow: var(--shadow-md);
}

.card img {
    width: 100%;
    height: 200px;
    object-fit: cover;
}

.card-body {
    padding: 20px;
}

.card-body h3 {
    color: var(--primary);
    margin-bottom: 10px;
}

کارت‌های رشته‌ها: پوشه 04-programs-page

شرح مثال

سه نکته کلیدی در این کارت‌ها هست که هر سه را در فصل‌های قبل یاد گرفتیم:

  1. object-fit: cover روی تصویرها. سه عکس رشته‌ها اندازه‌های مختلفی دارند و بدون این خط، کارت‌ها نامرتب می‌شدند.
  2. overflow: hidden روی کارت. بدون آن، گوشه‌های مربعی تصویر از گوشه گرد کارت بیرون می‌زند.
  3. افکت hover: با transform و سایه بزرگ‌تر، که به کارت‌ها حس تعامل می‌دهد.

۶. گام ۵: صفحه دبیران

این صفحه ساختار مشابه رشته‌ها دارد، اما کارت‌های کوچک‌تر و بیشتری در هر ردیف جا می‌گیرد و عکس‌ها دایره‌ای هستند.

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

.teacher {
    background-color: #ffffff;
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 25px 18px;
    text-align: center;
    transition: transform 0.3s;
}

.teacher:hover {
    transform: translateY(-5px);
}

.teacher img {
    width: 110px;
    height: 110px;
    border-radius: 50%;
    object-fit: cover;
    margin: 0 auto 15px;
}

.teacher h3 {
    color: var(--primary);
    font-size: 1.05rem;
}

.teacher .role {
    color: var(--muted);
    font-size: 0.9rem;
}

کارت‌های دبیران: پوشه 05-teachers-page

شرح مثال

ترکیب سه خط، عکس پروفایل دایره‌ای می‌سازد: عرض و ارتفاع برابر، border-radius: 50% از فصل چهارم و object-fit: cover از فصل سیزدهم. بدون مورد آخر، عکس‌های مستطیلی داخل دایره فشرده و بدشکل می‌شدند.

margin: 0 auto 15px هم عکس را در کارت وسط‌چین می‌کند. اینجا سه مقدار داده‌ایم که یعنی بالا صفر، چپ و راست خودکار و پایین پانزده پیکسل.

۷. گام ۶: صفحه گالری

.gallery {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 15px;
}

.gallery-item {
    position: relative;
    overflow: hidden;
    border-radius: var(--radius);
}

.gallery-item img {
    width: 100%;
    height: 230px;
    object-fit: cover;
    transition: transform 0.4s;
}

.gallery-item:hover img {
    transform: scale(1.08);
}

.gallery-item .caption {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(20, 40, 40, 0.8);
    color: #ffffff;
    padding: 10px 14px;
    font-size: 0.9rem;
}

.gallery-item.wide {
    grid-column: span 2;
}

گالری: پوشه 06-gallery-page

شرح مثال

این بخش زیباترین افکت کل سایت را دارد و از سه قطعه ساخته شده است:

۸. گام ۷: صفحه اخبار

.news-list {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 25px;
}

.news-item {
    display: flex;
    gap: 18px;
    background-color: #ffffff;
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    overflow: hidden;
}

.news-item img {
    width: 150px;
    height: 100%;
    object-fit: cover;
    flex-shrink: 0;
}

.news-text {
    padding: 18px 0 18px 18px;
}

.news-text h3 {
    color: var(--primary);
    font-size: 1.05rem;
    margin-bottom: 6px;
}

.date {
    color: var(--muted);
    font-size: 0.85rem;
    margin-bottom: 8px;
}

فهرست اخبار: پوشه 07-news-page

شرح مثال

اینجا برای اولین بار گرید و فلکس را تودرتو استفاده می‌کنیم، دقیقاً همان چیزی که در فصل یازدهم گفتیم:

flex-shrink: 0 روی تصویر لازم است تا وقتی عنوان خبر طولانی شد، تصویر باریک و فشرده نشود. این همان درس فصل هشتم است.

۹. گام ۸: صفحه تماس

.contact-layout {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 35px;
}

.contact-info p {
    margin-bottom: 14px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
}

.contact-info p:last-child {
    border-bottom: none;
}

.contact-form label {
    display: block;
    margin-bottom: 6px;
    color: var(--primary);
    font-weight: bold;
}

.contact-form input,
.contact-form textarea,
.contact-form select {
    width: 100%;
    font-family: Tahoma, sans-serif;
    font-size: 1rem;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    margin-bottom: 18px;
    transition: border-color 0.3s;
}

.contact-form input:focus,
.contact-form textarea:focus {
    outline: none;
    border-color: var(--primary);
}

.contact-form button {
    width: 100%;
    background-color: var(--primary);
    color: #ffffff;
    border: none;
    padding: 14px;
    border-radius: var(--radius);
    font-family: Tahoma, sans-serif;
    font-size: 1rem;
    cursor: pointer;
    transition: background-color 0.3s;
}

.contact-form button:hover {
    background-color: var(--accent);
}

صفحه تماس: پوشه 08-contact-page

شرح مثال

اینجا تمام درس‌های فصل دهم را به کار می‌بریم: قلم روی اجزای فرم که حتماً لازم است، display: block روی برچسب‌ها، حالت focus: برای نشان دادن فیلد فعال، و cursor: pointer روی دکمه.

در بخش اطلاعات تماس هم از last-child: فصل سیزدهم استفاده کرده‌ایم تا خط جداکننده زیر آخرین مورد برداشته شود.

لینک‌های کاربردی

در بخش اطلاعات تماس، شماره تلفن را با tel: و ایمیل را با mailto: لینک کنید. کاربر موبایل با یک لمس تماس می‌گیرد.

۱۰. گام ۹: پرداخت نهایی

سایت کامل شده اما هنوز روی موبایل خوب نیست. در این گام همه چیز را واکنش‌گرا می‌کنیم و جزئیات ظاهری را صیقل می‌دهیم.

/* ================= تبلت ================= */
@media (max-width: 900px) {
    .cards,
    .news-list,
    .contact-layout {
        grid-template-columns: repeat(2, 1fr);
    }

    .teacher-grid {
        grid-template-columns: repeat(3, 1fr);
    }

    .hero {
        padding: 80px 0;
    }

    .hero h1 {
        font-size: 1.8rem;
    }
}

/* ================= موبایل ================= */
@media (max-width: 600px) {
    .site-header .container {
        flex-direction: column;
        gap: 12px;
    }

    .site-header nav {
        justify-content: center;
        gap: 12px;
        font-size: 0.9rem;
    }

    .cards,
    .news-list,
    .contact-layout,
    .gallery {
        grid-template-columns: 1fr;
    }

    .teacher-grid {
        grid-template-columns: repeat(2, 1fr);
    }

    .gallery-item.wide {
        grid-column: span 1;
    }

    .news-item {
        flex-direction: column;
    }

    .news-item img {
        width: 100%;
        height: 180px;
    }

    .news-text {
        padding: 0 18px 18px;
    }

    .section {
        padding: 35px 0;
    }
}

واکنش‌گرا کردن: پوشه 09-visual-polish

شرح مثال

دقت کنید که چگونه با انتخابگر گروهی فصل پنجم، چند چیدمان را با یک قانون عوض کرده‌ایم. این کد بسیار کوتاه‌تر از نوشتن قانون جداگانه برای هر کدام است.

چند نکته مهم در بخش موبایل:

۱۱. گام ۱۰: بررسی و تحویل

پوشه 10-final-project نسخه کامل و نهایی است. پیش از تحویل هر پروژه‌ای، این فهرست را بررسی کنید:

بررسیچگونه
همه لینک‌ها کار می‌کنند روی تک‌تک لینک‌های منو در هر هفت صفحه کلیک کنید
هیچ تصویری خراب نیست دنبال آیکون تصویر شکسته بگردید و مسیرها را بررسی کنید
هر صفحه عنوان و توضیح دارد title و meta description هر صفحه متفاوت باشد
سه اندازه صفحه دسکتاپ، سپس ۹۰۰ پیکسل، سپس ۶۰۰ پیکسل
هر تصویر alt دارد برای دسترس‌پذیری و زمانی که تصویر بارگذاری نمی‌شود
کلاس active درست است در هر صفحه روی لینک همان صفحه باشد
نوار اسکرول افقی وجود ندارد پنجره را کاملاً باریک کنید و مطمئن شوید صفحه نمی‌شکند
تنها کاری که نتوانستیم بکنیم

روی موبایل، منوی ما هفت لینک را در دو خط نشان می‌دهد و فضای زیادی می‌گیرد. راه‌حل درست یک دکمه سه‌خطی است که با کلیک منو را باز کند، اما CSS نمی‌تواند کلیک را به خاطر بسپارد. این تنها محدودیت واقعی ما در کل دوره است و در فصل بعد با سه خط جاوااسکریپت حلش می‌کنیم.

فایل‌های پروژه

پوشه 14-final-project شامل ده گام: 01-design-foundation تا 10-final-project. هر پوشه به تنهایی قابل اجراست.

خلاصه فصل

در این پروژه از هر سیزده فصل قبل چیزی به کار رفت:

فصلچه چیزی به کار رفت
۱ و ۲ساختار سند، عنوان، فهرست، لینک، تصویر، جدول، مسیر فایل
۳فایل CSS خارجی مشترک برای هفت صفحه، کلاس و آی‌دی
۴padding و margin و border-radius همه جا
۵انتخابگر گروهی و فرزندی، hover، تصویر پس‌زمینه
۶تگ‌های معنایی، line-height، برداشتن خط زیر لینک
۷ و ۸فلکس‌باکس در سربرگ و کارت خبر، gap، transition
۹sticky برای منو، absolute برای نوار توضیح گالری، overflow
۱۰فرم تماس کامل با استایل
۱۱گرید برای کارت‌ها، گالری، دبیران و اخبار
۱۲media query در دو نقطه شکست، تصویر واکنش‌گرا
۱۳متغیرها، سایه، پرده تیره روی عکس، transform، object-fit، شبه‌عنصرها

تمرین‌های فصل چهارده

  1. کل پروژه را برای موضوعی دیگر بازسازی کنید: باشگاه ورزشی، کتابفروشی یا رستوران.
  2. تنها بلوک root: را عوض کنید و تم کاملاً متفاوتی برای سایت بسازید.
  3. یک صفحه هشتم به سایت اضافه کنید و لینکش را به منوی هر هفت صفحه اضافه کنید.
  4. عکس‌های پروژه را با عکس‌های خودتان عوض کنید و مطمئن شوید object-fit همه را مرتب نگه می‌دارد.
  5. فهرست بررسی گام دهم را روی پروژه خودتان اجرا کنید و هر ایرادی پیدا کردید بنویسید و رفع کنید.
  6. نوار عنوان صفحه‌های داخلی را از style درون‌خطی به هفت کلاس در فایل CSS تبدیل کنید.
فصل قبل: تکنیک‌های تکمیلی فصل بعد: نگاهی به آینده