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

موقعیت‌دهی و سرریز

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

در این فصل با این مباحث آشنا می‌شوید
  1. جریان عادی صفحه
  2. position: relative
  3. position: absolute
  4. position: fixed
  5. position: sticky
  6. z-index و لایه‌بندی
  7. overflow
  8. نمونه نهایی فصل

۱. جریان عادی صفحه

مرورگر عنصرها را به ترتیبی که در HTML نوشته‌اید می‌چیند: بلوکی‌ها زیر هم و درون‌خطی‌ها کنار هم. به این ترتیب طبیعی، جریان عادی می‌گویند.

ویژگی position به ما اجازه می‌دهد این جریان را بشکنیم. مقدار پیش‌فرضش static است که یعنی «همان جریان عادی». چهار مقدار دیگر هم دارد که این فصل درباره آنهاست.

هر چهار حالت با چهار ویژگی همراه، جای دقیق عنصر را تعیین می‌کنند: top، bottom، right و left. این چهار ویژگی روی عنصر static هیچ اثری ندارند و تنها وقتی position را عوض کنید کار می‌کنند.

۲. position: relative

.box {
    position: relative;
    top: 20px;
    right: 30px;
}

position relative: نمونه 01-position-relative

شرح مثال

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

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

کاربرد اصلی relative

راستش را بخواهید، relative را به ندرت برای جابه‌جا کردن عنصر به کار می‌بریم. کاربرد اصلی‌اش این است که به یک عنصر position: relative بدهیم بدون هیچ مقدار top و right، تنها برای اینکه بشود عنصرهای absolute را داخلش قرار داد. در بخش بعد می‌بینید چرا.

۳. position: absolute

.card {
    position: relative;          /* والد مرجع */
    width: 300px;
    height: 200px;
}

.badge {
    position: absolute;
    top: 10px;
    left: 10px;
    background-color: #ff6347;
    color: white;
    padding: 5px 12px;
    border-radius: 20px;
}

position absolute: نمونه 02-position-absolute

شرح مثال

absolute عنصر را کاملاً از جریان عادی بیرون می‌کشد. جای اصلی‌اش دیگر خالی نمی‌ماند و بقیه عنصرها جایش را پر می‌کنند، انگار که اصلاً وجود ندارد.

سؤال مهم این است: نسبت به چه چیزی جابه‌جا می‌شود؟ جواب: نسبت به نزدیک‌ترین والدی که position غیر از static دارد. اگر هیچ والدی چنین چیزی نداشته باشد، نسبت به کل صفحه محاسبه می‌شود.

به همین دلیل در مثال بالا به کارت position: relative دادیم. این کار کارت را «مرجع» می‌کند تا نشان کوچک دقیقاً در گوشه کارت بنشیند، نه در گوشه صفحه.

پرتکرارترین اشتباه

اگر عنصر absolute شما به جای گوشه کارت، به گوشه کل صفحه پرید، دلیلش صد در صد این است که به والدش position: relative نداده‌اید. این جفت، همیشه با هم می‌آیند: والد relative، فرزند absolute.

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

۴. position: fixed

.top-bar {
    position: fixed;
    top: 0;
    right: 0;
    left: 0;
    background-color: #2f4f4f;
    padding: 15px;
}

.back-to-top {
    position: fixed;
    bottom: 25px;
    left: 25px;
}

body {
    padding-top: 60px;           /* جبران ارتفاع نوار ثابت */
}

position fixed: نمونه 03-position-fixed

شرح مثال

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

در مثال بالا با دادن right: 0 و left: 0 به نوار بالا، آن را به تمام عرض صفحه کشیده‌ایم. این ترفند رایجی برای منوهای ثابت است.

نکته‌ای که همه فراموش می‌کنند

چون عنصر fixed از جریان بیرون است، جایی برای خودش اشغال نمی‌کند و روی محتوای ابتدای صفحه می‌افتد و آن را می‌پوشاند. راه‌حل، دادن padding-top به body به اندازه ارتفاع نوار است، دقیقاً همان خط آخر مثال.

۵. position: sticky

.section-title {
    position: sticky;
    top: 0;
    background-color: white;
    padding: 12px;
}

position sticky: نمونه 04-position-sticky

شرح مثال

sticky ترکیبی از دو حالت قبل است و رفتار جالبی دارد:

  1. تا وقتی عنصر در محدوده دید است، مانند یک عنصر عادی رفتار می‌کند و با صفحه حرکت می‌کند.
  2. به محض اینکه بخواهد از بالای صفحه خارج شود، در همان نقطه می‌چسبد و مانند fixed ثابت می‌ماند.
  3. وقتی والدش هم از صفحه خارج شود، بار دیگر با آن می‌رود.

دو شرط برای کار کردن sticky لازم است: باید حتماً یکی از top یا bottom را مشخص کنید، و والد عنصر نباید overflow: hidden داشته باشد. اگر sticky شما کار نمی‌کند، این دو را بررسی کنید.

مقایسه چهار حالت
مقدار نسبت به چه جای اصلی خالی می‌ماند با اسکرول حرکت می‌کند
staticجریان عادیخودش آنجاستبله
relativeجای خودشبلهبله
absoluteنزدیک‌ترین والد غیر staticخیربله
fixedپنجره مرورگرخیرخیر
stickyترکیبیبلهتا نقطه چسبیدن

۶. z-index و لایه‌بندی

وقتی عنصرها از جریان بیرون می‌آیند، ممکن است روی هم بیفتند. z-index تعیین می‌کند کدام رو باشد و کدام زیر.

.background-layer {
    position: absolute;
    z-index: 1;
}

.content-layer {
    position: absolute;
    z-index: 10;               /* روی لایه قبلی */
}

.modal {
    position: fixed;
    z-index: 1000;             /* روی همه چیز */
}

z-index: نمونه 05-z-index

شرح مثال

اعداد را منظم نگه دارید

عادت بدی که بسیار رایج است، نوشتن اعداد بی‌حساب مانند ۹۹۹۹۹ است. بعد از مدتی هیچ‌کس نمی‌داند چه چیزی روی چه چیزی است. یک نظم ساده انتخاب کنید: مثلاً ۱ تا ۱۰ برای محتوای عادی، ۱۰۰ برای منوی ثابت و ۱۰۰۰ برای پنجره‌های بازشو.

۷. overflow

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

.box {
    width: 300px;
    height: 150px;
}

.visible {
    overflow: visible;         /* پیش‌فرض: بیرون می‌ریزد */
}

.hidden {
    overflow: hidden;          /* اضافه‌ها بریده می‌شوند */
}

.scroll {
    overflow: scroll;          /* همیشه نوار اسکرول */
}

.auto {
    overflow: auto;            /* فقط در صورت نیاز نوار اسکرول */
}

.only-vertical {
    overflow-x: hidden;
    overflow-y: auto;
}

overflow: نمونه 06-overflow

شرح مثال

مقدارنتیجه
visibleپیش‌فرض. محتوا از جعبه بیرون می‌زند.
hiddenهر چه بیرون بزند بریده و پنهان می‌شود.
scrollنوار اسکرول همیشه هست، حتی وقتی لازم نیست.
autoنوار اسکرول تنها وقتی محتوا بسیار باشد. بهترین انتخاب.

دو نسخه جهت‌دار هم دارد: overflow-x برای افقی و overflow-y برای عمودی. ترکیب رایج آنها، همان دو خط آخر مثال است: اسکرول عمودی مجاز، افقی ممنوع.

دو کاربرد بسیار پرتکرار

اول، overflow: hidden روی جعبه‌ای که border-radius دارد و داخلش تصویر است. بدون آن، گوشه‌های تصویر از گوشه گرد جعبه بیرون می‌زنند. دوم، overflow-x: auto روی جدول‌های عریض، تا روی موبایل به جای خراب کردن کل صفحه، خودشان اسکرول بخورند.

۸. نمونه نهایی فصل

<body>

    <header class="navbar">
        <div class="logo">فروشگاه</div>
        <nav><a href="#">خانه</a><a href="#">محصولات</a></nav>
    </header>

    <main>
        <h2 class="sticky-title">محصولات ویژه</h2>

        <div class="products">
            <div class="product">
                <span class="badge">۳۰٪ تخفیف</span>
                <div class="image"></div>
                <h3>محصول اول</h3>
            </div>

            <div class="product">
                <span class="badge">جدید</span>
                <div class="image"></div>
                <h3>محصول دوم</h3>
            </div>
        </div>

        <div class="note-box">
            <p>متن طولانی که داخل یک جعبه با ارتفاع محدود قرار دارد...</p>
        </div>
    </main>

    <a href="#" class="to-top">بالا</a>

</body>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: Tahoma, sans-serif;
}

body {
    background-color: #f5f5f5;
    line-height: 1.9;
    padding-top: 65px;             /* جبران نوار ثابت */
}

/* نوار بالا: همیشه ثابت */
.navbar {
    position: fixed;
    top: 0;
    right: 0;
    left: 0;
    z-index: 100;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: #2f4f4f;
    color: white;
    padding: 18px 30px;
}

.navbar a {
    color: white;
    text-decoration: none;
    margin-right: 18px;
}

/* عنوان چسبان */
.sticky-title {
    position: sticky;
    top: 65px;
    z-index: 50;
    background-color: #f5f5f5;
    color: #2f4f4f;
    padding: 15px 30px;
}

.products {
    display: flex;
    flex-wrap: wrap;
    gap: 20px;
    padding: 20px 30px;
}

/* کارت محصول: مرجع نشان تخفیف */
.product {
    position: relative;
    width: 250px;
    background-color: white;
    border-radius: 10px;
    overflow: hidden;              /* تا تصویر از گوشه گرد بیرون نزند */
    padding-bottom: 15px;
}

.product .image {
    height: 160px;
    background-color: #dddddd;
}

.product h3 {
    padding: 12px 15px 0;
    color: #2f4f4f;
}

/* نشان تخفیف در گوشه کارت */
.badge {
    position: absolute;
    top: 10px;
    left: 10px;
    z-index: 5;
    background-color: #ff6347;
    color: white;
    padding: 4px 12px;
    border-radius: 20px;
    font-size: 13px;
}

/* جعبه با ارتفاع محدود و اسکرول داخلی */
.note-box {
    margin: 20px 30px;
    height: 120px;
    overflow-y: auto;
    background-color: white;
    padding: 15px;
    border-radius: 10px;
}

/* دکمه شناور بازگشت به بالا */
.to-top {
    position: fixed;
    bottom: 25px;
    left: 25px;
    z-index: 200;
    background-color: #ff6347;
    color: white;
    text-decoration: none;
    padding: 12px 18px;
    border-radius: 50px;
}

نمونه نهایی فصل: نمونه 07-final-example

شرح مثال

در این صفحه هر چهار حالت position و هر دو مفهوم دیگر فصل نقش دارند:

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

پوشه 09-position-and-overflow شامل نمونه‌های 01-position-relative تا 07-final-example.

خلاصه فصل

ویژگیکارش
position: relativeجابه‌جایی نسبت به جای خود؛ مرجع فرزندان absolute
position: absoluteخروج از جریان، نسبت به نزدیک‌ترین والد غیر static
position: fixedثابت روی پنجره، بی‌تأثیر از اسکرول
position: stickyعادی تا نقطه‌ای، بعد چسبیده
top bottom right leftتعیین جای دقیق. روی static اثر ندارند.
z-indexترتیب لایه‌ها. تنها با position غیر static.
overflow: hiddenبریدن محتوای اضافه
overflow: autoاسکرول تنها در صورت نیاز

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

  1. یک منوی ثابت بالای صفحه بسازید و با padding-top جای آن را جبران کنید.
  2. یک کارت محصول با نشان تخفیف در گوشه‌اش بسازید.
  3. عمداً position: relative والد را حذف کنید و ببینید نشان کجا می‌رود.
  4. یک دکمه بازگشت به بالا در گوشه پایین صفحه بگذارید که با اسکرول حرکت نکند.
  5. یک عنوان چسبان بسازید و صفحه را اسکرول کنید تا رفتارش را ببینید.
  6. جعبه‌ای با ارتفاع ثابت بسازید و متن طولانی داخلش بگذارید. یک بار با hidden و یک بار با auto امتحان کنید.
فصل قبل: فلکس‌باکس پیشرفته فصل بعد: فرم‌ها