پروژه نهایی: سایت دبیرستان دانش
سیزده فصل مفهوم یاد گرفتیم. حالا همه را کنار هم میگذاریم و یک سایت هفتصفحهای واقعی و واکنشگرا میسازیم، گام به گام.
۱. نقشه پروژه
پروژه ما سایت یک دبیرستان خیالی به نام دبیرستان دانش است. هفت صفحه دارد و هر صفحه یک فایل 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
شرح مثال
این چند خط، پایه تمام هفت صفحه است. هر قسمتش دلیلی دارد:
- متغیرها. دو رنگ اصلی، یک رنگ تأکیدی، سه خاکستری، یک اندازه گردی و سه سایه. این موارد کل زبان بصری سایت هستند. چون همه از فصل سیزدهم متغیر شدهاند، برای عوض کردن تم کل سایت تنها همین بلوک تغییر میکند.
- ریست. همان قانون ستاره فصل چهارم و پنجم.
-
a { color: inherit; text-decoration: none; }لینکها را از حالت آبی و زیرخطدار پیشفرض خارج میکند تا رنگشان را از والدشان بگیرند. با این کار در هر جای سایت، لینکها با محیطشان هماهنگ میشوند. - قانون تصویر. همان سه خط فصل دوازدهم که یک بار نوشته میشود و برای همیشه مشکل تصویرهای بزرگ را حل میکند.
- کلاس container. این مهمترین کلاس کمکی سایت است. محتوا را به حداکثر ۱۱۰۰ پیکسل محدود میکند، وسطچین میکند و از دو طرف بیست پیکسل فاصله میدهد. بدون آن، متن روی مانیتور بزرگ از لبه تا لبه کشیده میشود و خواندنش سخت میشود.
چشم انسان نمیتواند خطهای بسیار بلند را آسان دنبال کند. محدود کردن عرض محتوا در همه سایتهای حرفهای انجام میشود و عدد رایجش بین ۱۰۰۰ تا ۱۲۰۰ پیکسل است.
۳. گام ۲: صفحه اصلی
صفحه اصلی مهمترین صفحه است و چهار بخش دارد. اول اسکلت مشترکی که در هر هفت صفحه تکرار میشود:
<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 عوض میشود. آن کلاس به کاربر نشان میدهد الان در کدام صفحه است، که برای گم نشدن در سایت لازم است.
در این کد هفت مفهوم از هفت فصل مختلف کنار هم آمدهاند:
- فلکسباکس با
space-betweenبرای لوگو و منو. - gap از فصل هشتم برای فاصله لینکهای منو.
- sticky از فصل نهم تا منو با اسکرول همراه بماند.
- z-index تا منو زیر محتوا نرود.
- transition برای نرم شدن تغییر رنگ.
- متغیرها و سایه از فصل سیزدهم.
- ترفند حاشیه شفاف. در حالت عادی به لینکها
border-bottomبا رنگtransparentدادهایم. اگر این کار را نمیکردیم و حاشیه تنها درhover:اضافه میشد، ارتفاع لینک دو پیکسل بسیار میشد و کل منو در لحظه عبور موس تکان میخورد. این ترفند کوچک، نشانه یک کد حرفهای است.
هدر بزرگ صفحه اصلی
<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::
در تمام هفت صفحه استفاده میشود. این تکرار عمدی است و
به سایت هویت بصری واحد میدهد.
در فصل سوم گفتیم 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
شرح مثال
سه نکته کلیدی در این کارتها هست که هر سه را در فصلهای قبل یاد گرفتیم:
-
object-fit: coverروی تصویرها. سه عکس رشتهها اندازههای مختلفی دارند و بدون این خط، کارتها نامرتب میشدند. -
overflow: hiddenروی کارت. بدون آن، گوشههای مربعی تصویر از گوشه گرد کارت بیرون میزند. -
افکت
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
شرح مثال
این بخش زیباترین افکت کل سایت را دارد و از سه قطعه ساخته شده است:
- بزرگنمایی تصویر. در
hover:تصویر باscale(1.08)کمی بزرگ میشود. چون والدشoverflow: hiddenدارد، تصویر از کادر بیرون نمیزند و تنها داخل قاب بزرگ میشود. این دو با هم کار میکنند و بدون یکی، دیگری بیمعنی است. -
نوار توضیح. با
absoluteروی پایین تصویر نشسته. دادن هر سه مقدارrightوbottomوleftباعث میشود نوار تمام عرض تصویر را بگیرد. پسزمینه نیمهشفافrgbaهم متن را روی هر عکسی خوانا نگه میدارد. -
تصویرهای عریض. کلاس
wide.باgrid-column: span 2بعضی تصویرها را دو برابر میکند و گالری را از حالت یکنواخت درمیآورد.
۸. گام ۷: صفحه اخبار
.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
شرح مثال
دقت کنید که چگونه با انتخابگر گروهی فصل پنجم، چند چیدمان را با یک قانون عوض کردهایم. این کد بسیار کوتاهتر از نوشتن قانون جداگانه برای هر کدام است.
چند نکته مهم در بخش موبایل:
- سربرگ عمودی میشود تا لوگو بالا و منو زیرش قرار بگیرد.
gallery-item.wide.باید بهspan 1برگردد. اگر این کار را نکنید، در گرید تکستونی خطا میدهد و تصویر عریض چیدمان را میشکند. این نوع جزئیات را تنها با امتحان کردن واقعی پیدا میکنید.- کارتهای خبر از افقی به عمودی تغییر جهت میدهند و عرض ثابت تصویر هم باید به صد درصد برگردد.
۱۱. گام ۱۰: بررسی و تحویل
پوشه 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، شبهعنصرها |
تمرینهای فصل چهارده
- کل پروژه را برای موضوعی دیگر بازسازی کنید: باشگاه ورزشی، کتابفروشی یا رستوران.
- تنها بلوک
root:را عوض کنید و تم کاملاً متفاوتی برای سایت بسازید. - یک صفحه هشتم به سایت اضافه کنید و لینکش را به منوی هر هفت صفحه اضافه کنید.
- عکسهای پروژه را با عکسهای خودتان عوض کنید و مطمئن شوید
object-fitهمه را مرتب نگه میدارد. - فهرست بررسی گام دهم را روی پروژه خودتان اجرا کنید و هر ایرادی پیدا کردید بنویسید و رفع کنید.
- نوار عنوان صفحههای داخلی را از
styleدرونخطی به هفت کلاس در فایل CSS تبدیل کنید.