آموزش CSS از صفر
CSS می گوید چیزی که HTML ساخته چه شکلی دیده شود: رنگ، فاصله، اندازه و جای هر عنصر روی صفحه. هر قانونش سه تکه دارد، یک انتخابگر که می گوید کدام عنصر، یک ویژگی که می گوید چه چیزی، و یک مقدار.
- درس ۳ از ۱۲
- مقدماتی
- رایگان، بدون ثبت نام
یک استایل از کجا به یک عنصر می رسد
-
۱
ویژگی style روی خود تگ
نزدیک ترین لایه به عنصر و سخت ترین چیزی که بعدا می شود عوضش کرد.
-
۲
قانون شما با کلاس یا شناسه
هر چه انتخابگر دقیق تر باشد وزنش بیشتر است. شناسه سنگین ترین است و برای همین کمتر استفاده اش کنید.
-
۳
قانون شما با نام تگ
سبک ترین قانون شما، ولی باز هم از پیش فرض مرورگر جلوتر است.
-
۴
پیش فرض مرورگر
تیتر بزرگ، لینک آبی، فهرست نقطه دار. اینجاست که همه چیز قبل از شما تعریف شده است.
-
۵
ارث از عنصر والد
ضعیف ترین لایه. رنگ روی body به لینک نمی رسد، چون مرورگر برای خود لینک قانون مستقیم دارد.
ترتیب لایه ها را important به هم می ریزد و برای همین آخرین راه است. ارث بیرونی ترین لایه است: هر قانون مستقیم، حتی قانون خود مرورگر، از آن جلو می زند.
آخرین بررسی: فکت ها و نام ابزارهای این درس در همین تاریخ با منابعشان بازبینی شده اند.
CSS چه چیزی را کنترل می کند و چطور به صفحه وصل می شود؟
یک کار می کند: می گوید هر چیزی که HTML ساخته، چه شکلی دیده شود. CSS کوتاه شده برگه های سبک آبشاری است و کوچک ترین واحدش یک قانون است:
p {
color: #333;
line-height: 1.9;
}سه راه برای وصل کردنش هست و در عمل یکی را استفاده می کنیم. می شود ویژگی style را روی خود تگ نوشت، می شود قانون ها را داخل تگ style در head گذاشت، و می شود همه را در یک فایل جدا نگه داشت و با یک خط صدا زد:
<link rel="stylesheet" href="style.css">راه سوم را انتخاب کنید و دو تای دیگر را برای موارد استثنا نگه دارید. دلیلش سلیقه نیست: فایل جدا یک بار دانلود می شود و مرورگر در صفحه های بعدی از کش خودش برش می دارد، و روزی که رنگ دکمه ها باید عوض شود یک جا را عوض می کنید نه پنجاه جا را.
یک چیز هم هست که تازه کار را گیج می کند. قبل از اینکه شما حتی یک خط CSS بنویسید، صفحه استایل دارد: تیتر بزرگ و توپر است، لینک آبی است و زیرش خط دارد، فهرست نقطه دارد. این ها را خود مرورگر با برگه سبک داخلی اش می گذارد و کاری که شما می کنید بازنویسی همان هاست.
انتخابگر: به مرورگر بگویید کدام عنصر
با نام تگ می نویسید و همه آن تگ ها را می گیرید. با نقطه و نام کلاس فقط عنصرهایی را می گیرید که آن کلاس را دارند، و با علامت مربع و نام شناسه یک عنصر یکتا را.
a { color: #0b5; } /* هر لینک */
.btn { border-radius: 12px; } /* هر چیزی با class="btn" */
#header { position: sticky; } /* عنصری با id="header" */
.card p { margin-block: 0; } /* هر p داخل .card */
a:hover { text-decoration: underline; }در عمل تقریبا همیشه کلاس بنویسید. شناسه در صفحه یکتاست و به درد لینک دادن و جاوااسکریپت می خورد، ولی برای استایل وزن زیادی می آورد و شما را بعدا مجبور می کند وزن بیشتری بیاورید تا رویش را بگیرید. همین مسیر است که آخرش به important می رسد.
یک انتخابگر هم هست که کمتر یاد داده می شود و برای کاربر کیبورد حیاتی است. hover فقط برای ماوس معنا دارد؛ کسی که با Tab در صفحه می گردد باید ببیند همین حالا روی کدام عنصر ایستاده است:
.btn:focus-visible {
outline: 2px solid #0b5;
outline-offset: 2px;
}اگر حلقه پیش فرض مرورگر را با outline: none برداشتید و چیزی جایش نگذاشتید، صفحه را برای کاربر کیبورد کور کرده اید. این یکی از معدود جاهایی است که یک خط CSS مستقیم به دسترس پذیری آسیب می زند.
چرا استایل من اعمال نمی شود؟
جواب کوتاه: قانون شما اعمال شده، فقط قانون دیگری از آن جلو زده. مرورگر برای هر ویژگی هر عنصر سه چیز را به ترتیب می پرسد. کدام قانون ها اصلا این عنصر را هدف گرفته اند، کدامشان دقیق تر است، و اگر دقتشان برابر بود کدام دیرتر در فایل آمده.
شکل بالای صفحه همین لایه هاست، از نزدیک ترین به عنصر تا دورترین. style روی خود تگ از همه نزدیک تر است و برای همین سخت ترین چیزی است که بعدا می شود عوضش کرد، و پیش فرض مرورگر از همه دورتر. جایی که بیشتر آدم ها اشتباه می کنند بیرونی ترین لایه است: ارث.
رنگ را روی body می گذارید و انتظار دارید لینک ها هم همان رنگ را بگیرند. نمی گیرند. مرورگر برای خود تگ a یک قانون مستقیم دارد، و هر قانون مستقیم، حتی قانون خود مرورگر، از مقداری که از والد به ارث رسیده جلو می زند. ارث ضعیف ترین لایه است، نه قوی ترین.
حالا راه حل، که ده ثانیه طول می کشد. به جای حدس زدن، روی عنصر راست کلیک کنید، بازرسی را بزنید و برگه Computed را باز کنید. آنجا مقدار نهایی هر ویژگی نوشته شده و اگر بازش کنید، قانون برنده را با نام فایل و شماره خط نشانتان می دهد و قانون های بازنده را خط خورده. حدس زدن جایگزین این ندارد.
و important، کلمه ای که این ترتیب را می شکند. یک بار که بنویسیدش، هر قانون بعدی برای غلبه بر آن باید خودش important بگذارد و از آنجا به بعد فایل شما با وزن جلو می رود نه با منطق. قاعده ما ساده است: اگر بدون important کار نمی کند، یعنی انتخابگر اشتباه است. تنها استثنای واقعی جایی است که باید استایل کدی را بگیرید که خودتان ننوشته اید و به آن دسترسی ندارید.
هر عنصر یک جعبه است
هر چیزی روی صفحه یک مستطیل است، حتی یک حرف. آن مستطیل چهار لایه دارد: خود محتوا، padding که فاصله داخلی تا کادر است، border که خط دور آن است، و margin که فاصله بیرونی تا بقیه عنصرهاست. تمام کار فاصله گذاری در CSS همین چهار تاست.
یک تصمیم پیش فرض هم هست که تقریبا همه عوضش می کنند و کمتر کسی دلیلش را می گوید. به طور پیش فرض عددی که در width می نویسید فقط اندازه محتواست، پس عنصری با عرض صد درصد که padding هم دارد، از جای خودش بیرون می زند. این یک خط برای همیشه حلش می کند:
*, *::before, *::after { box-sizing: border-box; }با border-box عدد width شامل padding و border هم می شود، یعنی همان چیزی که از اول انتظار داشتید. این خط را اول هر فایل CSS بگذارید و دیگر بهش فکر نکنید.
یک رفتار دیگر هم یک بار همه را غافلگیر می کند. فاصله عمودی دو عنصر پشت سر هم با هم جمع نمی شود؛ بزرگ ترشان برنده می شود. به این می گویند ادغام حاشیه و فقط برای margin عمودی اتفاق می افتد، نه برای padding و نه داخل فلکس و گرید. یکی از دلایلی که در چیدمان های امروزی به جای margin سراغ gap می رویم همین است.
چیدمان: کی فلکس باکس، کی گرید؟
فلکس باکس یک محور دارد و گرید دو تا، و همین تفاوت بیشتر تصمیم ها را می گیرد. با فلکس چند چیز را در یک ردیف یا یک ستون می چینید و اجازه می دهید اندازه هر کدام از محتوای خودش بیاید. با گرید اول ساختار را می کشید، ستون ها و ردیف ها را خودتان تعریف می کنید و بعد محتوا داخلشان می نشیند.
.toolbar {
display: flex;
align-items: center;
gap: 12px;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 16px;
}آن خط دوم ارزش دارد که از حفظ بلد باشید. می گوید هر ستون دست کم ۲۲۰ پیکسل باشد و بقیه فضا را بین خودشان تقسیم کنند، و مرورگر خودش حساب می کند در هر عرض چند ستون جا می شود. یعنی یک شبکه واکنشگرا بدون حتی یک media query.
این دو رقیب هم نیستند و انتخاب یکی به معنی کنار گذاشتن آن یکی نیست. در عمل معمولا اسکلت صفحه با گرید چیده می شود و داخل هر خانه اش یک ردیف فلکس می نشیند. قاعده سرانگشتی: اگر می توانید بگویید «این چند چیز کنار هم»، فلکس؛ اگر می گویید «این جدول از خانه ها»، گرید.
فلکس باکس و گرید؛ دو ابزار برای دو نوع مسئله
یکی محتوا را در یک محور می چیند، دیگری ساختار را در دو محور تعریف می کند.
فلکس باکس، یک محور
- یک ردیف یا یک ستون؛ اندازه هر عنصر از محتوای خودش می آید
- برای نوار ابزار، منو، ردیف دکمه ها و کنار هم نشستن آیکن و متن
- وقتی نمی دانید چند تا عنصر می آید و فقط می خواهید کنار هم بنشینند
- با wrap به خط بعد می رود، ولی ستون ها با هم تراز نمی مانند
گرید، دو محور
- ستون ها و ردیف ها را شما تعریف می کنید و محتوا داخلشان می نشیند
- برای اسکلت صفحه، شبکه کارت ها و هر جایی که تراز عمودی مهم است
- با repeat و minmax بدون media query در هر عرض تعداد ستون را خودش می چیند
- برای یک ردیف ساده زیادی است؛ آنجا فلکس کوتاه تر و خواناتر است
در یک صفحه واقعی هر دو با هم کار می کنند: اسکلت با گرید و داخل هر خانه یک ردیف فلکس. انتخاب یکی کنار گذاشتن آن یکی نیست.
چرا در سایت فارسی باید margin-inline-start بنویسید نه margin-left
چون margin-left در فارسی همان جایی نیست که در انگلیسی است. ویژگی های فیزیکی به چپ و راست صفحه فکر می کنند و ویژگی های منطقی به اول و آخر خط. margin-inline-start یعنی فاصله از جایی که خط شروع می شود؛ مرورگر در فارسی و عربی آن را راست حساب می کند و در انگلیسی چپ، و شما هیچ کاری نمی کنید.
ترجمه اش هم سخت نیست:
| فیزیکی | منطقی | در راست به چپ چه می شود |
|---|---|---|
| margin-left | margin-inline-start | فاصله از ابتدای خط، که در فارسی سمت راست است |
| padding-right | padding-inline-end | فاصله داخلی از انتهای خط، در فارسی سمت چپ |
| left: 0 | inset-inline-start: 0 | چسبیدن به لبه ای که خط از آن شروع می شود |
| border-left | border-inline-start | خط کنار عنصر، همیشه سمت شروع |
| text-align: left | text-align: start | تراز متن با ابتدای خط، در هر دو زبان درست |
| width و height | inline-size و block-size | اندازه در راستای خط و عمود بر آن |
تست کردنش ده ثانیه است و کسی یادش نمی دهد: در ابزار توسعه دهنده مرورگر روی تگ html، مقدار dir را از rtl به ltr عوض کنید و به همان صفحه نگاه کنید. هر چیزی که جابه جا نشد یا به لبه غلط چسبید، یک ویژگی فیزیکی است که جا مانده. این کار روی سایت خودمان بخشی از بازبینی هر قالب جدید است.
کجا این قاعده لازم نیست: سایتی که فقط یک زبان چپ به راست دارد و قرار نیست هیچ وقت زبان دیگری بگیرد. آنجا margin-left هرگز گاز نمی گیرد و اصرار روی ویژگی منطقی فقط یک عادت خوب است، نه یک ضرورت. ولی اگر سایتتان فارسی است، یا قرار است روزی انگلیسی هم بشود، این تفاوت همان چیزی است که تعیین می کند بعدا یک ساعت کار دارید یا یک هفته.
همان کارت، با ویژگی فیزیکی و با ویژگی منطقی
با ویژگی منطقی
- یک فایل CSS برای هر چهار زبان، بدون نسخه راست به چپ جداگانه
- اضافه شدن یک زبان جدید کار CSS ندارد
- آیکن کنار متن همیشه سمت درست می ماند
- تست کردنش عوض کردن یک ویژگی dir در ابزار توسعه دهنده است
با ویژگی فیزیکی
- برای زبان دوم یا فایل دوم لازم است یا قانون های وارونه
- هر بار که کسی یک margin-left جدید اضافه کند، همان جا دوباره می شکند
- خطاها بی سر و صدا هستند: چیزی خراب نمی شود، فقط بد می افتد
- روی سایت تک زبانه هیچ کدام از این ها اتفاق نمی افتد
این تفاوت فقط وقتی خودش را نشان می دهد که سایت بیش از یک جهت داشته باشد. روی سایت تک زبانه چپ به راست، ویژگی فیزیکی هیچ وقت خراب نمی کند.
متغیرهای CSS: یک بار تعریف کنید، همه جا استفاده کنید
متغیر CSS نامی است که مقداری را نگه می دارد. اسم فنی اش ویژگی سفارشی است، با دو خط تیره شروع می شود و با var خوانده می شود:
:root {
--brand: #0b5;
--gap: 16px;
}
.btn {
background: var(--brand);
padding: var(--gap);
}چیزی که کمتر گفته می شود این است که این متغیر مثل هر مقدار دیگری ارث می رسد. اگر همان نام را روی یک عنصر دوباره تعریف کنید، هر چیزی که داخل آن عنصر است مقدار جدید را می بیند و بقیه صفحه دست نخورده می ماند:
.card--warn { --brand: #d97706; }حالا هر دکمه داخل آن کارت نارنجی است، بدون اینکه یک خط از قانون .btn عوض شده باشد. تم تیره هم دقیقا با همین ایده ساخته می شود: یک بلوک که فقط چند نام را دوباره تعریف می کند، نه یک فایل CSS دوم.
و حدش: این متغیر، متغیر زبان برنامه نویسی نیست. حساب کردن با آن فقط داخل calc انجام می شود، و در شرط یک media query نمی توانید از آن استفاده کنید. اگر دنبال حلقه و شرط و تابع هستید، دارید سراغ ابزارهایی مثل Sass می روید که کارشان همین است و خروجی شان باز هم همین CSS ساده است.
مسیر سریع با هوش مصنوعی
مدل های زبانی در «این چیدمان را برایم بساز» خوب اند، چون آن کار ترجمه مکانیکی یک توصیف به فلکس و گرید است. جایی که کم می آورند دقیقا همان جایی است که تازه کار گیر می کند: فهمیدن اینکه چرا یک استایل اعمال نشده. برای آن باید صفحه شما را ببینند و نمی بینند. پس مسیر سریع دو نیمه دارد: چیدمان را بسپارید، آبشار را خودتان نگه دارید. برای نیمه اول یک مدل سریع و ارزان کافی است؛ انتخاب فعلی ما در <a class="text-link" href="/ai/">بخش هوش مصنوعی</a> هست.
- بلوکی را که مشکل دارد جدا کنید و HTML واقعی خودش را بردارید. توصیف کردن صفحه به جای گذاشتن مارک آپ، بیشترین دلیل جواب بی ربط است.
- نسخه پایین را اجرا کنید. اگر متغیرهای رنگ و فاصله دارید، همان جا فهرستشان کنید تا مدل نام جدید نسازد.
- خروجی را بگذارید و هر دو جهت را تست کنید: در ابزار توسعه دهنده روی تگ html مقدار dir را عوض کنید و به همان صفحه نگاه کنید.
- اگر استایلی اعمال نشد، برنگردید سراغ چت. برگه Computed را باز کنید؛ آنجا نوشته کدام قانون برنده شده و از کدام فایل و کدام خط آمده.
نسخه آماده کپی
نقش: کسی که CSS مدرن می نویسد، بدون فریمورک.
چیزی که می خواهم:
بخش صفحه: {نام بخش}
مارک آپ فعلی: {HTML را اینجا بگذارید}
رفتار دلخواه: {مثلا سه کارت کنار هم، روی موبایل زیر هم}
جهت: راست به چپ (فارسی)، ولی همان کد باید در چپ به راست هم درست باشد
قواعد خروجی:
- فقط CSS بده. مارک آپ را عوض نکن؛ اگر لازم است کلاسی اضافه شود، اول بگو کجا و چرا.
- همه فاصله ها و جهت ها با ویژگی های منطقی: margin-inline، padding-inline، inset-inline-start، text-align: start. هیچ left و right فیزیکی ننویس.
- رنگ ها و فاصله ها را از این متغیرها بردار: {فهرست متغیرهای موجود}. متغیر جدید نساز مگر دلیلش را بنویسی.
- چیدمان یک محوره با flex و دو محوره با grid. یک خط بنویس کدام را چرا انتخاب کردی.
- important ممنوع. اگر بدون آن نمی شود، یعنی انتخابگر اشتباه است؛ همان را بگو.
- عرض ثابت پیکسلی نده مگر برای چیزی که واقعا ثابت است، مثل یک آیکن.
- هر چیزی که با ماوس حالت hover دارد، باید حالت focus-visible هم داشته باشد.
بعد از کد، در سه خط بگو در حالت چپ به راست چه چیزی جابه جا می شود و کجا شک داشتی.
قبل از اعتماد به خروجی: دو چیز را خودتان باید چک کنید. اول جهت: هیچ ابزار خودکاری به شما نمی گوید صفحه در آینه بد افتاده، فقط چشم خودتان می گوید. دوم آبشار: اگر از مدل بپرسید چرا استایلم اعمال نشده، جوابی می گیرید که شبیه جواب است ولی حدس است، چون صفحه شما را ندیده. آن سوال جای دیگری جواب دارد، در برگه Computed مرورگر خودتان.
هوش مصنوعی در این کار
در CSS هوش مصنوعی جای مشخصی دارد و بیرون از آن جا زود بی فایده می شود. سه کاری که واقعا جلو می اندازد: تبدیل توصیف یک چیدمان به فلکس و گرید، توضیح دادن یک تکه CSS ناآشنا خط به خط، و تبدیل یک فایل پر از left و right به نسخه منطقی همان. دو کاری که نمی سپاریم: تصمیم درباره اینکه صفحه چه شکلی باشد، و پیدا کردن دلیل اینکه چرا یک قانون اعمال نشده.
ابزارهایی که واقعا کمک می کنند
- Claude برای توضیح خط به خط یک فایل CSS و بازنویسی ویژگی های فیزیکی به منطقی خوب جواب می دهد. ایران در فهرست کشورهای پشتیبانی شده انتروپیک نیست؛ این را از صفحه خود انتروپیک خوانده ایم.
- Gemini برای ساختن یک چیدمان از روی توصیف و سوال های پایه ای کافی است و فارسی را خوب می فهمد. صفحه خود گوگل می گوید اپ وب جمنای در بیش از دویست و سی کشور و منطقه کار می کند و ایران در آن فهرست نیست.
- Claude Code وقتی به جای یک تکه، کل فایل را باید عوض کنید به کار می آید، چون در ویرایشگر و ترمینال خودتان کار می کند و فایل را می بیند. خودش رایگان نصب می شود ولی به اشتراک انتروپیک نیاز دارد و ایران در فهرست کشورهای پشتیبانی شده نیست.
کجا نتیجه معکوس می دهد
دو خطر مشخص اینجا هست و هر دو ساکت اند. اول جهت: مدل نمی داند صفحه شما راست به چپ است مگر بگویید، پس اگر در پرامپت نخواهید، هیچ چیز جلوی margin-left را نمی گیرد و خروجی در انگلیسی درست و در فارسی وارونه می افتد. برای همین در نسخه بالا ویژگی های منطقی صریح خواسته شده اند؛ فهرست کاملشان در مستندات MDN هست. دوم آبشار: مدل صفحه شما را نمی بیند، پس هر جوابی درباره اینکه چرا استایلی اعمال نشده حدس است، و رایج ترین حدس هایی که کار می کنند وزن انتخابگر را بالا می برند یا important اضافه می کنند. هر دو یک بار جواب می دهند و تغییر بعدی را سخت تر می کنند. موضع ما: چیدمان با مدل، آبشار با مرورگر. برای اینکه ببینید هر ابزار از ایران چطور قابل پرداخت است، راهنمای خرید را ببینید.
منبع ها: MDN: CSS logical properties and values MDN: Handling conflicts, the cascade and specificity Anthropic: supported countries Google: where Gemini Apps are available
حد این توصیه
CSS ظاهر یک صفحه را می سازد، نه یک سایت. محتوا و ساختار کار HTML است، رفتار کار جاوااسکریپت، و باز شدن صفحه روی اینترنت کار هاست و دامنه. و یک نکته که کمتر گفته می شود: اگر قرار است سایتتان را روی وردپرس با یک قالب آماده بالا بیاورید، کل CSS ای که لازم دارید شاید بیست خط باشد و عمیق شدن در گرید برای شما مسیر سریع نیست. این درس برای کسی نوشته شده که می خواهد خودش ظاهر را کنترل کند یا بفهمد قالبش چه می کند. قاعده ویژگی های منطقی هم به همان اندازه شرطی است: روی سایتی که برای همیشه یک زبان چپ به راست دارد، رعایت کردنش عادت خوبی است ولی هیچ چیزی را نجات نمی دهد.
از تجربه خود ما
همین سایت مثال خودمان است و قابل بررسی. فایل اصلی استایل rgb.ir حدود صد و سی کیلوبایت است و هر چهار زبان سایت را با هم سرویس می دهد: فارسی و عربی راست به چپ، انگلیسی و ترکی چپ به راست، بدون هیچ فایل rtl جداگانه در قالب. روزی که این درس بررسی شد، در آن فایل هفتاد جا ویژگی منطقی نوشته شده بود و صفر مورد margin-left یا padding-right یا حتی left و right خالی وجود داشت؛ text-align: left و float هم هیچ کدام. و یک صداقت لازم: در فایل شکل ها چهار خط margin-left باقی مانده و عمدا هم باقی مانده، چون هر چهارتا یک ترفند وسط چین کردن اند که مقدارشان قرینه است و در آن ها چپ اصلا معنای جهت نمی دهد. قاعده این است که ویژگی منطقی جایی لازم است که چیدمان اول و آخر داشته باشد، نه هر جا که کلمه left دیده می شود.
سوال هایی که واقعا پرسیده می شوند
اول HTML یاد بگیرم یا می شود مستقیم سراغ CSS رفت؟
اول HTML، ولی نه تا وقتی که کاملش کنید. انتخابگر CSS به عنصر و کلاس اشاره می کند، پس تا ندانید تگ های اصلی چه هستند، نصف قانون هایی که می نویسید به هیچ چیز نمی خورند. یک بعدازظهر HTML کافی است تا CSS معنا پیدا کند.
از همان اول سراغ بوت استرپ یا تیلویند بروم؟
در هفته اول نه. فریمورک همان آبشاری را که هنوز یاد نگرفته اید پشت یک لایه کلاس پنهان می کند و روزی که چیزی سر جایش نمی نشیند، هیچ ابزاری برای فهمیدنش ندارید. بعد از اینکه انتخابگر و آبشار و گرید را فهمیدید، انتخاب فریمورک یک تصمیم پروژه ای منطقی است، نه یک میان بر.
چرا سایتم روی موبایل به هم می ریزد؟
در بیشتر موارد یکی از این دو: تگ viewport در head نیست، یا جایی عرض ثابت پیکسلی نوشته اید که از صفحه موبایل بزرگ تر است. اولی یک خط است و در درس HTML همین مسیر توضیح داده شده، دومی معمولا یک width است که باید max-width می بود. طراحی واکنشگرا درس بعدی همین مسیر است.