Через день після написання статті про потік я раптом виявив, що абсолютно безсовісним чином забув написати там про те, як він працює з точки зору саме розкладки. Забув, тобто, саму сутність.
Виправляю цей недогляд!
Даємо місце
Дуже часто при розкладці сторінки виникає завдання вийняти щось із загального потоку сторінки і повісити поряд з основним вмістом і оформити у вигляді плаваючої панельки.
У цьому випадку можна той блок, який буде панеллю, повісити абсолютно, а основний вміст залишити в потоці. Однак цього недостатньо, тому що панелька залізе зверху тексту.
Ось тут і починають працювати кордони і відступи. Їх основне завдання: зрушити край блоку в потоці, щоб дати місце для чогось іншого. Задаються вони властивостями margin-left, margin-right, padding-left, padding-right.
Часто в різних форумах натрапляю на «одвічні питання», одне з яких: що використовувати – margin або padding. Причому, «експертні» відповіді бувають часто типу «треба використовувати завжди тільки margin (padding), тому що padding (margin) глючить». Це, звичайно, неправильно. Глючити та чи інша розкладка може по мільйону причин, і вибір відступів або меж тут рідко реально винен.
Суть вибору ж гранично проста: padding знаходиться усередині меж, і на ньому намальований фон боксу, а margin – за межами, і він прозорий. Тому вибирати треба виходячи з того, як ви хочете, щоб виглядало пусте місце, яке залишилося: всередині блоку або зовні. Якщо ж у вас немає ні фону, ні кордонів, то різниці ніякої й немає. Хоч монетку підкидайте.
Схлопування кордонів
З цього приводу є дуже хороша і що стала вже класичною стаття гуру CSS Еріка Мейєра. Ця глава, здебільшого – вільний виклад її по-українськи.
Схлопування кордонів («margin collapsing») – це на перший погляд дивний ефект, який спостерігається з верхньою та нижньою межами блоків. Виявляється він двояко.
Накладення кордонів сусідів
Перший прояв – це коли кордони між двома сусідніми блоками «провалюються» один в одного. Для прикладу візьмемо два блоки – заголовок і абзац, що йдуть в потоці один за іншим:
<h1>Заголовок</h1> <p>Абзац тексту</p>
Дамо заголовку верхню і нижню межу в 20 пікселів, а абзацу – у 10.
h1 {
margin:20px 0;
}
p {
margin:10px 0;
}
До речі, ось ці «10px 0 code>» - це зручний скорочений запис. Перша цифра задає верх і низ, друга - право і ліво. Вона підходить не тільки для margin'ів, але й для всіх інших властивостей, які можуть задаватися для сторін боксу.
Так ось, нижня межа заголовка і верхня межа абзацу накладуться одна на одну і між ними буде не 30 пікселів, а 20 (по найбільшому кордону).
Вивалювання за батьківські кордони
Ця штука менш очевидна. Уявіть собі кілька абзаців, що йдуть один за іншим, які укладені в один загальний блок-контейнер:
<div> <p>абзац</p> <p>абзац</p> <p>абзац</p> </div>
Дамо і контейнеру, і абзацам верхні та нижні межі:
p {
margin:10px 0;
}
div {
margin:5px 0;
}
Тут схлопування проявляється в тому, що верхній margin першого абзацу не лежить всередині div'а, а вивалюється з нього наверх.
margin самого контейнера і margin першого блоку накладаються, і в підсумку місце перед контейнером дорівнює найбільшому з них.
Теж саме відбувається і внизу з нижніми margin'ами контейнера та останнього вкладеного блоку.
Чому так
Схлопування кордонів - не глюк і не помилка браузерів. Це спеціально придумана поведінка. Воно, хоч і здається на перший погляд дивним, абсолютно нормально для того, для чого потік служить в першу чергу: форматування тексту.
Зокрема, накладення кордонів сусідніх елементів дуже корисно, коли ви визначаєте кордони для заголовків, абзаців, списків - основних блокових елементів тексту. Без схлопування в групі абзаців відстань між ними була б більшою, ніж перед першим і після останнього.
Це можна було б обійти завданням тільки нижньої або тільки верхньої межі, але тоді довелося б окремо боротися з тим, що перший або останній абзац прилипають до кордонів свого контейнера. Зі схлопуванням ви завжди можете задавати елементу ті межі, які потрібні саме йому, не думаючи про те, що його оточує.
Вивалювання кордону за межі батька теж має свій сенс. У першу чергу - для списків. Уявімо собі текст, в якому є список. Елемент списку (<li>) містить абзац (<p>). І в абзацу, і в елемента списку є свої межі.
Так ось, якщо б верхня межа абзацу не випадала з елемента списку нагору, то текст абзацу з'їжджав би вниз, і не був би навпроти крапочки списку. А це некрасиво.
Проблеми при розкладці
З простим потоком тексту схлопування працює добре, а от при розкладці іноді воно відгукується зовсім не так, як хотілося б. Візьмемо простий приклад. Нам потрібен на початку сторінки верхній блок, в якому будуть заголовок і підзаголовок:
<body>
<div id="header">
<h1>Суперконтора</h1>
<p><small>Суперконторим с 1381 года</small></p>
</div>
</body>
Далі за порадою гіпотетичного мегадізайнера нашої суперконтори ми хочемо, щоб весь верхній блок прилягав до країв сторінки, мав темно-червоний фон, заголовок "Суперконтора" мав би яскраво-червоний фон, а текст усередині всього верхнього блоку був білим. І крім того, хочеться, щоб навколо тексту були певні відступи. Тоді гіперверстальщік нашої суперконтори пише такий стиль:
body {
margin:0;
}
#header {
background-color:darkred; color:white;
}
#header h1 {
margin:20px 0 10px 0;
background-color:red;
}
#header p {
margin:5px 0;
}
І виходить у нас наступне:
Білий простір над верхнім блоком - це верхній margin заголовка, який вивалилися з нього! Явно не те, чого нам хотілося. Нам хотілося, щоб цей margin сидів усередині верхнього блоку, і щоб замість дешевого білого фону там був трендовий темно-червоний! Хоча з точки зору чистого тексту, все нормально - 20 пікселів вільного місця зверху заголовка присутні. Але тепер, оскільки у нас є фон, нам далеко не все одно, сидить цей margin всередині верхнього блоку або вивалюється назовні.
Існує кілька способів, які скасовують вивалювання кордонів елементів за межі контейнера.
- Вивалювання скасовується, якщо блоку-контейнера призначити
paddingабоborder(з того боку, де вивалюється). У нашому прикладі це буде виглядати так:#header { background-color:darkred; color:white; padding:1px 0; }Мінус полягає в тому, що висота всього верхнього блоку збільшується на 2 пікселя. Це може і не бути чимось страшним, але якщо на висоту цього блоку орієнтуються інші елементи дизайну, то це не дуже добре. І ні, нульовий
paddingне запрацює. Це все одно, що його немає. - У випадку, коли пікселі все ж зайві, є інший спосіб. Можна верхню межу, що вивалюється, у заголовка прибрати, а замість неї поставити верхній
paddingсамому контейнеру. Візуально ефект буде якраз потрібний. І те ж саме можна зробити і знизу блоку.#header { padding-top:20px; padding-bottom:5px; } #header h1 { margin:0 0 10px 0; } #header p { margin:5px 0 0 0; }Скорочений запис з чотирьох чисел розставить значення, починаючи з верхнього за годинниковою стрілкою (верх, право, низ, ліво). Тобто, запис
0 0 10px 0означає "всі межі - 0, нижня - 10 пікселів".Правда, в цьому випадку CSS вже виходить злегка більш дрімучим, що ускладнює розуміння написаного через тиждень-другий.
- Ще один спосіб відключити вивалювання будується на тому, що воно, як я говорив, придумано для форматування текстових блоків у потоці. А для блоків, які були виключені з потоку, вивалювання скасовується. Ну а щоб вилучити блок з потоку, його можна, наприклад, спозиціонувати абсолютно. Забігаючи наперед скажу, що є ще один спосіб - властивість
float, але про нього буде ціла наступна стаття.Однак, треба сказати, що позиціювання - це все ж не спосіб "виправлення" ситуації. Тому що якщо у сторінки взяти та й вилучити з потоку якийсь блок, то, швидше за все, все навколо зламається. Тому цей спосіб можна переформулювати: якщо ви все одно збиралися блок позиціонувати абсолютно, то про проблему вивалювання кордонів можна не піклуватися.
Підсумок
Отже, вивалювання кордонів за межі контейнера може викликати некрасиві ефекти. Для боротьби з ним є три способи зі своїми плюсами і мінусами.
| Спосіб | Плюси | Мінуси |
|---|---|---|
Скасовуючі однопіксельні padding або border |
Дуже простий спосіб | Зайві пікселі в дизайні найчастіше неприпустимі |
| Повна заміна крайніх margin'ом вкладених блоків padding'ами контейнера | Повна візуальна ідентичність бажаного | Завдання відступів "розмазується" за різними правилами в стилях, що їх неприємно ускладнює |
Абсолютне позиціонування або float |
Повна візуальна ідентичність і простота | Блок виймається з потоку і змінює розкладку |
***
Це переклад статті. Оригінал тут







