طراحی واکنشگرا
امروز بیشتر بازدیدکنندگان هر سایتی با گوشی میآیند. در این فصل یاد میگیریم یک صفحه بسازیم که روی هر اندازهای درست و زیبا دیده شود.
۱. واکنشگرا یعنی چه
یک سایت واکنشگرا سایتی است که چیدمانش را با اندازه صفحه بازدیدکننده تطبیق میدهد. روی مانیتور بزرگ سه ستون نشان میدهد، روی تبلت دو ستون و روی گوشی یک ستون.
قدم اول این کار را از فصل اول انجام دادهایم، بدون اینکه بدانیم چرا.
همان خط viewport در قسمت head:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
خطی که بدون آن هیچکدام از تکنیکهای این فصل کار نمیکنند
توضیح
گوشیها مشکلی تاریخی دارند: وقتی ساخته شدند، هیچ سایتی برای صفحه کوچک طراحی نشده بود. پس تصمیم گرفتند وانمود کنند صفحهشان حدود ۹۸۰ پیکسل عرض دارد و بعد کل تصویر را کوچک کنند تا جا شود. نتیجهاش سایتی است که کاملاً درست اما به شکل ریز و ناخوانا دیده میشود.
width=device-width به گوشی میگوید
«وانمود نکن، عرض واقعی خودت را استفاده کن».
initial-scale=1.0 هم یعنی «هیچ بزرگنمایی اولیهای اعمال نکن».
اگر این خط را ننویسید، میتوانید دهها media query بنویسید و هیچکدام روی گوشی اجرا نمیشوند. چون گوشی فکر میکند عرضش ۹۸۰ پیکسل است و شرطهای شما برای عرض کمتر از ۷۶۸ هرگز درست نمیشوند.
۲. واحدهای نسبی
تا این بخش تقریباً همه اندازهها را با پیکسل مشخص کردهایم. پیکسل واحد ثابت است و در طراحی واکنشگرا محدودمان میکند. چند واحد نسبی هم داریم.
.fixed {
width: 300px; /* ثابت */
}
.percent {
width: 80%; /* نسبت به عرض والد */
}
.viewport-width {
width: 50vw; /* نصف عرض پنجره */
}
.viewport-height {
height: 100vh; /* تمام ارتفاع پنجره */
}
html {
font-size: 16px;
}
.rem-size {
font-size: 1.5rem; /* ۱.۵ برابر قلم ریشه = ۲۴ پیکسل */
padding: 2rem; /* ۳۲ پیکسل */
}
.em-size {
font-size: 1.2em; /* ۱.۲ برابر قلم والد */
}
واحدها: نمونههای 01-units و 01-partition
شرح مثال
| واحد | نسبت به چه | کاربرد |
|---|---|---|
px |
هیچ چیز، ثابت است | حاشیه، گردی گوشه، سایه |
% |
عنصر والد | عرض جعبهها |
vw |
عرض پنجره مرورگر | بخشهای تمامعرض |
vh |
ارتفاع پنجره مرورگر | هدر بزرگ تمامصفحه |
rem |
قلم ریشه صفحه | اندازه قلم و فاصلهها |
em |
قلم عنصر والد | فاصله داخلی دکمهها |
rem مهمترینشان است. قلم ریشه به طور پیشفرض
شانزده پیکسل است، پس 1rem برابر شانزده پیکسل و
2rem برابر سی و دو پیکسل. مزیتش این است که
اگر روزی قلم ریشه را عوض کنید، کل سایت
به شکل هماهنگ بزرگ یا کوچک میشود.
rem همیشه به ریشه نگاه میکند، پس قابل پیشبینی است.
em به والد نگاه میکند و در عنصرهای تودرتو
ضرب میشود و از کنترل خارج میشود. برای شروع، همیشه
rem را انتخاب کنید.
۳. media query
این بخش هسته اصلی طراحی واکنشگراست: راهی برای نوشتن قانونهایی که تنها در اندازههای مشخصی از صفحه اجرا میشوند.
/* استایل پایه: برای همه اندازهها */
.container {
width: 90%;
margin: 0 auto;
font-size: 1rem;
}
/* فقط وقتی عرض صفحه ۷۶۸ پیکسل یا کمتر است */
@media (max-width: 768px) {
.container {
width: 100%;
font-size: 0.95rem;
}
}
/* فقط وقتی عرض صفحه ۴۸۰ پیکسل یا کمتر است */
@media (max-width: 480px) {
.container {
padding: 10px;
}
}
media query: نمونه 02-media-query-basics
شرح مثال
media@با شرطی داخل پرانتز شروع میشود. هر چه داخل آکولاد بزرگش باشد، تنها وقتی شرط درست باشد اجرا میشود.-
max-width: 768pxیعنی «۷۶۸ پیکسل یا کمتر». -
min-width: 768pxیعنی «۷۶۸ پیکسل یا بیشتر». - media query ها همیشه پایین فایل نوشته میشوند، بعد از استایلهای عادی. چون در تداخل، قانون پایینتر برنده است.
نقطههایی که در آنها چیدمان عوض میشود را نقطه شکست مینامیم. اعداد رایج:
| عرض | معمولاً یعنی |
|---|---|
| ۴۸۰ پیکسل | گوشی |
| ۷۶۸ پیکسل | تبلت |
| ۹۹۲ پیکسل | لپتاپ کوچک |
| ۱۲۰۰ پیکسل | مانیتور بزرگ |
روش بهتر این است که عرض پنجره مرورگر را بهتدریج کاهش دهید و هر جا طرحتان زشت شد، همانجا یک نقطه شکست بگذارید. نقطه شکست را طرح شما تعیین میکند، نه فهرست مدلهای گوشی.
۴. پنهان کردن در موبایل
.sidebar {
display: block;
}
.mobile-only {
display: none; /* در حالت عادی پنهان */
}
@media (max-width: 768px) {
.sidebar {
display: none; /* در موبایل پنهان شود */
}
.mobile-only {
display: block; /* فقط در موبایل دیده شود */
}
}
پنهان کردن: نمونه 03-hide-in-mobile
شرح مثال
display: none عنصر را کاملاً از صفحه حذف میکند.
نه دیده میشود و نه جایی اشغال میکند، انگار اصلاً در HTML نیست.
با ترکیب این ویژگی و media query میشود دو نسخه از یک قسمت داشت: یکی برای صفحه بزرگ و یکی برای موبایل. مثلاً یک منوی کامل برای دسکتاپ و یک منوی فشرده برای گوشی.
کاربر موبایل، کاربر درجه دو نیست. محتوای مهم را از موبایل حذف نکنید؛ تنها چیدمانش را عوض کنید. display: none را برای تزیینات و ستونهای فرعی نگه دارید، نه برای محتوای اصلی.
۵. تغییر جهت فلکس
این پرکاربردترین تکنیک واکنشگرا کردن یک چیدمان فلکس است.
.layout {
display: flex;
flex-direction: row; /* کنار هم در دسکتاپ */
gap: 20px;
}
.sidebar {
flex-basis: 250px;
flex-shrink: 0;
}
.content {
flex-grow: 1;
}
@media (max-width: 768px) {
.layout {
flex-direction: column; /* زیر هم در موبایل */
}
.sidebar {
flex-basis: auto; /* دیگر عرض ثابت لازم نیست */
}
}
تغییر جهت: نمونه 03-responsive-flex-direction
شرح مثال
تنها با عوض کردن flex-direction از row به column، کل چیدمان از افقی به عمودی تبدیل میشود. نوار کناری که در دسکتاپ کنار محتوا بود، در موبایل بالای آن قرار میگیرد.
نکتهای که بسیارها فراموش میکنند: باید flex-basis را هم به auto برگردانید. وگرنه در حالت عمودی، آن مقدار به ارتفاع تبدیل میشود و نوار کناری بیدلیل دویست و پنجاه پیکسل بلند میشود.
اگر تنها چند کارت کنار هم دارید، حتی به media query هم نیاز ندارید. flex-wrap: wrap به تنهایی کار را انجام میدهد و کارتها خودشان در صفحه باریک زیر هم میروند. سادهترین راهحل را همیشه اول امتحان کنید.
۶. تغییر ستونهای گرید
.gallery {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
@media (max-width: 992px) {
.gallery {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 768px) {
.gallery {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 480px) {
.gallery {
grid-template-columns: 1fr;
}
}
ستونهای واکنشگرا: نمونه 04-responsive-grid-columns
شرح مثال
یکی از دلایلی که گرید را دوست داریم همین است: برای عوض کردن کل چیدمان یک گالری، تنها یک خط عوض میشود. چهار ستون در مانیتور بزرگ، سه ستون در لپتاپ، دو ستون در تبلت و یک ستون در گوشی.
همین کار را با grid-template-areas هم میشود کرد. کافی است نقشه را در media query بار دیگر و به شکل تکستونی بنویسید:
@media (max-width: 768px) {
.layout {
grid-template-columns: 1fr;
grid-template-areas:
"header"
"content"
"sidebar"
"footer";
}
}
عوض کردن کل نقشه صفحه با چند خط
دقت کنید که در این نقشه، content بالای
sidebar آمده است، در حالی که در دسکتاپ کناری اول بود.
یعنی حتی ترتیب بخشها را هم بدون دست زدن به HTML عوض کردیم.
۷. تصویر واکنشگرا
img {
max-width: 100%;
height: auto;
display: block;
}
تصویر واکنشگرا: نمونه 05-responsive-images
شرح مثال
این سه خط کوچک، مشکل بزرگی را حل میکنند. یک تصویر با عرض ۱۲۰۰ پیکسل روی گوشی ۳۷۵ پیکسلی، صفحه را میشکند و نوار اسکرول افقی میسازد.
-
max-width: 100%یعنی «هرگز از عرض والدت بزرگتر نشو». اگر جا بود اندازه اصلیات را داشته باش، وگرنه کوچک شو. اگر به جایشwidth: 100%بنویسید، تصویرهای کوچک هم به زور کشیده و بیکیفیت میشوند. -
height: autoباعث میشود ارتفاع متناسب با عرض تغییر کند و تصویر کشیده و بدشکل نشود. -
display: blockفاصله سفید کوچکی را که مرورگر زیر تصویرهای درونخطی میگذارد حذف میکند.
این سه خط را همان اول فایل CSS و کنار قانون ستاره بنویسید. یک بار مینویسید و دیگر هیچوقت مشکل تصویر بزرگتر از صفحه نخواهید داشت.
۸. نمونه نهایی فصل
<body>
<header class="site-header">
<div class="logo">کادوس</div>
<nav class="desktop-menu">
<a href="#">خانه</a>
<a href="#">دورهها</a>
<a href="#">درباره ما</a>
<a href="#">تماس</a>
</nav>
</header>
<div class="layout">
<aside class="sidebar">
<h3>دستهبندی</h3>
<p>طراحی وب</p>
<p>شبکه</p>
</aside>
<main class="content">
<h2>دورههای ما</h2>
<div class="cards">
<div class="card"><h3>HTML</h3></div>
<div class="card"><h3>CSS</h3></div>
<div class="card"><h3>فلکس</h3></div>
<div class="card"><h3>گرید</h3></div>
</div>
</main>
</div>
</body>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Tahoma, sans-serif;
}
img {
max-width: 100%;
height: auto;
display: block;
}
body {
background-color: #f5f5f5;
line-height: 1.9;
font-size: 1rem;
}
/* ---------- سربرگ ---------- */
.site-header {
display: flex;
justify-content: space-between;
align-items: center;
background-color: #2f4f4f;
color: white;
padding: 1rem 2rem;
}
.desktop-menu a {
color: white;
text-decoration: none;
margin-right: 1.2rem;
}
/* ---------- چیدمان اصلی ---------- */
.layout {
display: flex;
gap: 1.5rem;
padding: 1.5rem;
}
.sidebar {
flex-basis: 240px;
flex-shrink: 0;
background-color: white;
padding: 1.2rem;
border-radius: 10px;
}
.content {
flex-grow: 1;
}
.content h2 {
color: #2f4f4f;
margin-bottom: 1rem;
}
/* ---------- کارتها ---------- */
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 1rem;
}
.card {
background-color: white;
padding: 1.5rem;
border-radius: 10px;
border-top: 4px solid #ff6347;
}
.card h3 {
color: #2f4f4f;
}
/* ================= تبلت ================= */
@media (max-width: 768px) {
.layout {
flex-direction: column;
}
.sidebar {
flex-basis: auto;
}
.cards {
grid-template-columns: repeat(2, 1fr);
}
}
/* ================= موبایل ================= */
@media (max-width: 480px) {
body {
font-size: 0.95rem;
}
.site-header {
padding: 1rem;
}
.desktop-menu {
display: none;
}
.layout {
padding: 1rem;
gap: 1rem;
}
.cards {
grid-template-columns: 1fr;
}
}
نمونه نهایی فصل: نمونه 06-final-example
شرح مثال
این یک صفحه واقعاً واکنشگراست و در سه حالت مختلف رفتار میکند. روش نوشتنش هم روش درست است: اول استایل عادی و کامل را برای صفحه بزرگ مینویسیم، بعد در media query ها تنها چیزهایی را که باید عوض شوند بازنویسی میکنیم.
روی دسکتاپ:
- سربرگ با لوگو در یک سو و منوی کامل در سوی دیگر.
- نوار کناری ۲۴۰ پیکسلی در کنار محتوا.
- کارتها در سه ستون.
روی تبلت با عرض ۷۶۸ یا کمتر:
-
flex-direction: columnنوار کناری را بالای محتوا میبرد، وflex-basis: autoجلوی بلند شدن بیدلیلش را میگیرد. - کارتها از سه ستون به دو ستون میآیند.
روی گوشی با عرض ۴۸۰ یا کمتر:
- منوی دسکتاپ پنهان میشود، چون در آن عرض جا نمیشود.
- کارتها تکستونی میشوند.
-
قلم پایه و همه فاصلهها کمی کوچکتر میشوند. چون همه اندازهها را
با
remنوشتهایم، عوض کردن یک عدد رویbodyهمهشان را با هم تنظیم میکند.
وقتی منوی دسکتاپ را پنهان میکنیم، کاربر موبایل هیچ منویی ندارد. راهحل درست، یک دکمه سهخطی است که با کلیک منو را باز کند. اما CSS نمیتواند «کلیک» را به خاطر بسپارد. این تنها کاری است که در این دوره با CSS تنها نمیتوانیم انجام دهیم، و در فصل پانزدهم با سه خط جاوااسکریپت حلش میکنیم.
پوشه 12-responsive-design شامل نمونههای
01-units و 01-partition تا
06-final-example.
خلاصه فصل
| ویژگی یا مفهوم | کارش |
|---|---|
meta viewport | پیشنیاز همه چیز. بدون آن هیچ media query روی گوشی کار نمیکند. |
% | نسبت به عنصر والد |
vw و vh | نسبت به عرض و ارتفاع پنجره |
rem | نسبت به قلم ریشه. انتخاب اول برای قلم و فاصله. |
em | نسبت به قلم والد. در تودرتویی ضرب میشود. |
@media (max-width: ...) | قانونهایی برای صفحههای کوچکتر |
display: none | حذف کامل عنصر از صفحه |
flex-direction: column | عمودی کردن چیدمان در موبایل |
grid-template-columns در media query | کم کردن تعداد ستونها |
max-width: 100% روی تصویر | جلوگیری از بیرون زدن تصویر |
تمرینهای فصل دوازده
- صفحهای بسازید که در دسکتاپ سه ستون، در تبلت دو ستون و در موبایل یک ستون داشته باشد.
- خط
viewportرا حذف کنید، صفحه را روی گوشی باز کنید و تفاوت را ببینید. - همه اندازههای یک صفحه را از
pxبهremتبدیل کنید و بعد تنها قلمbodyرا عوض کنید. - یک نوار کناری بسازید که در موبایل به بالای محتوا منتقل شود.
- تصویری بزرگتر از عرض صفحه بگذارید و ببینید
max-width: 100%چگونه نجاتش میدهد. - پنجره مرورگر را آرامآرام باریک کنید و هر جا طرحتان زشت شد، یک نقطه شکست تازه اضافه کنید.