Каскадные Таблицы Стилей

индекс
323,31

Поговорим о margin, он же маргин (часть 2-я)

Эта статья о горизонтальном margin, о том, откуда считаются проценты и что вообще это такое. О вертикальном margin было написанно в прошлой моей статье.Но! Перед тем, как начать…
Читая ваши отзывы к предыдущей статье я решил исправить некоторые недочеты:
  1. Так как некоторые писали, что слово «маргин» «режет» глаз, то именно для них в этой статье будет написано только «margin»
  2. В связи стем, что статья была популярна, я решил в одной статье описать и вертикальный и горизонтальный margin, тем самым повторить предыдущую, чтоб можно было добавить одну статью в «избранное» и не возвращаться к старой
Итак начнем.

Блочная модель
Как вообще работает css на компьютерах?


Допустим в браузер загружен какой-то документ. У любого браузера есть так называемая область просмотра. Это та область, в которой вы наблюдаете содержание, она зависит от разрешения вашего экрана.

Документ по своим размерам может быть любым и никогда не вздумайте подгонять размер документа под размер области просмотра!

Тот документ, который сейчас загружен и область просмотра — между собой связаны элементом html, который одновременно может взаимодействовать с область просмотра и документом, который сейчас загружен в браузер.

Так же область просмотра еще называется viewport, а то что загружено браузером — canvas. Эти две области с помощью html связываются через точку привязки origin point, она находится всегда в левом верхнем углу.

НО, это действует только для европейских языков.
В чём проблема?
У нас есть направление текста, слева на право, сверху вниз, поэтому для нас левый верхний угол важен.
Если вы специальными средствами( напр. атрибут dir={ltr | rtl}, где ltr — текст отображается как обычно — слева направо, rtl — текст инвертируется и отображается справа налево ), измените направление вашего приоритета, то увидите, как правый верхний угол станет более приоритетным.

То есть приоритетный угол зависит от направления текста.

Но поскольку мы европейцы, то для нас левый верхний угол имеет большую важность, то есть это и есть точка привязки.

Преобразование значений

Есть документ, который загрузился, — парсер его преобразовал в «дерево», подлючился css и начинает работать с этим «деревом». При этом, все величины начинаются преобразовываться в px.

Монитор работает с px. Для него em, ex, pt — всё ерунда!

Что монитор можен на этом этапе посчитать?
Всё, что определено размером шрифта( em, ex ), проценты, которые относятся к размерам, которые известны заранее, всё он это перевел в px без учёта области просмотра. Дальше «берет» область просмотра и начинает исходя из её размеров, пересчитывать проценты, которые применяются для размеров.

Например вы поставили div ширина, которого равна width:50%
От чего будут браться эти 50%?
От ширины контейнер, а откуда возьмётся контейнер?
Он определяется шириной области просмотра.

То есть, браузеру сначала нужно понять размер области просмотра, а потом посчитать все проценты. Вот на этом этапе браузер пересчитывает все проценты в px. И на последнем этапе он начинает применять все эти посчитанные проценты, но с учётом своих возможностей, например:

Имеем размер 22,5px, что делать браузеру?
У монитора нету дробных пикселей., поэтому браузер округляет px. В старых IE, в некоторых случаях есть ошибки округления, без учёта области, в которой эти элементы находятся. То есть он будет округлять всегда, без учёта того, что надо эти элементы уместить.

Модель CSS



Любой эелемент, абсолютно любой, можно представить в виде 4-х областей:
  1. margin — внешняя область
  2. border — область рамки
  3. padding — внутренний отступ
  4. область content( для которой задаётся два правила: ширина и высота )
Раньше в базовой модели IE ширина и высота указывалась внешней границе рамки и именно так себя ведёт IE в режиме quirks mode. В этом режиме все IE будут применять ширину и высоту к внешней границе рамки.

Размеры блочных областей



Если ничего не ставить в эти правила — они по-умолчанию становятся в значение auto.
Что это значит?
Если в элементе появляется какой-нибудь контент, то его высота определяется размером контента. а ширина определяется размером контейнера.

Вот теперь поговорим о margin

Margin может проставляться в em, ex, px — жёсткое задание и в % — всегда берется от чего-то.

Margin в % всегда считается от ширины контейнера этого элемента.

Итак, есть 2 блока(div), first и second, second вложен в first.

#first{
padding: 100px;
background:#999;
}
#second{
height:100px;
background:#009;
margin:30% 0 0;
}


И то, что мы можем наблюдать в браузере:


Итак мы видим что margin-top: 30%;
От чего же он считается?
А считается он от ширины контейнера.


Если мы будем уменьшать размеры ширины контейнера, то и margin-top блока #second будет изменяться соответственно:


Итак, margin по-вертикали считается от ширины контейнера

Кроме этого margin может быть отрицательный.

Есть 2 блока, один под другим, верхний — #first, нижний — #second

#first{
height: 200px;
margin: 0 0 100px;
background:#999;
}
#second{
height:200px;
background:#009;
margin:0 100px 0;
}




Пока результат очевиден.
Но, если мы зададим margin: 0 0 -100px;, то элемент по вертикали, позволяет на свою область «заехать» другому элементу или «вылезти» низу своему за пределы своего контейнера.
Вот, что у нас получилось:


Мы видим, что элемент #second «заехал» на элемент #first.
Почему так произошло?
Потому что элемент #second в коде ниже.
А вот теперь будет интересней! :)

Поговорим о Margin Collapsing ( «схлопывание» вертикальных margin ).

Возвращаем прежний код на место( оставляем margin: 0 0 100px; )
Чем определяется Margin Collapsing?
Пример:
второму элементу, тот который у нас #second меняем стили(задаём отступ сверху 50px)

#second{
height:200px;
background:#009;
margin: 50px 100px 0;
}


Многие думают, что сейчас у нас должен появитсья отступ от элемента #first до элемента #second — 150px ( не забываем, что у #first имеет margin: 0 0 100px; а #second только что изменили на margin: 50px 100px 0;.
Но это не так!
Правильный ответ: расстояние между двумя элементами будет 100px, так как 100px > 50px!


Едем дальше.
Изменим наш код:

#first{
height: 200px;
margin: 0 0 -100px;
background:#999;
}
#second{
height:200px;
background:#009;
margin: -50px 100px 0;
}


Поставим элементу #first margin: 0 0 -100px;, а второму эелементу #second margin: -50px 100px 0;
Теперь, как вы думаете, на сколько второй элемент «заедет» на первый?

На 100px !

Для одноименных margin выбирается наибольший по модулю размер.

А вот если мы изменим наш код так:

#first{
height: 200px;
margin: 0 0 -100px;
background:#999;
}
#second{
height:200px;
background:#009;
margin: 50px 100px 0;
}


и элементу #second зададим margin: 50px 100px 0;.
То что у нас произойдет?
А произойдет сложение! То есть, -100px + 50px = -50px. Вот на столько нижний элемент «заедет» на верхний.

Так работает Margin Collapsing для смежных элементов:
  1. Одноименный margin — берется больший по модулю.
  2. Разноименный margin — происходит сложение.

Дальше.

Margin Collapsing наблюдается не только по отношению к смежным элементам.

Есть 2 элемента, один находитсяв другом( #second находится в #first ) и ниже их стили:

#first{
background:#999;
}
#second{
height:200px;
background:#009;
margin: 0 100px 0;
}


И получаем следующую картину:


Так как у второго элемента( внутреннего #second стоит margin: 0 100px 0; ), то мы получили «отжатие» этого элемента слева и права.

А вот теперь указываем ему(внутреннему элементу #second margin: 200px 100px 0;).
Многие ожидают увидеть, что внутренний элемент #second «отодвинется» от границы своего контейнера #first на 200px.
Но это снова неверно!

Вот, что мы получаем на самом деле:


Почему так?
Потому что это одно из следствий Margin Collapsing.

Если у родительского элемента нет ограничивающих факторов( об этих факторах я напишу ниже ), то margin переходит от внутреннего элемента к внешнему, после чего выбирается по старой схеме этот margin ( если одноименные. то выбирается наибольший, для разноименный происходит сложение .)

Теперь, как же остановить этот Margin Collapsing?
  1. Внешнему элементу(#first) поставить border, например border:1px solid black;
  2. Можно добавить padding, например padding:10px;
  3. И последнее правило — overflow(любое значение, кроме visible)

Вот пример, что у нас получилось. я добавил в #first border:1px solid black;

А теперь откываем этот же файл в IE6 и IE7 :)
И видим :)

Но, у них есть такая модель, которая называется layout.
О ней я напишу ниже, а сейчас пока смотрите, что она делает.

Ставим элементу #first свойтсво width:100%(width может быть любым) и вуаля :)

Как это произошло?
А произошло это, за счет модели layout.

Теперь поговорим о горизонтальном margin.

Волшебная формула:

Вот из чего складываются все отдельные части.
Как же рассчитываются margin:auto;?

Представим, что margin не задан, width имеет значение auto, padding — не задали, border — не задал. Что в таком случае произойдет? А вот, что width:auto — рассчитается из ширины контейнера( вот как строится ширина наших div или p )


Напоминаю, что для нас левая сторона имеет больший приоритет, чем правая.
Например: смотрим 1-й пример в таблице: мы задали все три размера.Представим, что ширина контейнера равна 400px, а мы задали width:300px, а margin-left:200px, margin-right:200px;

Что в таком случае получится?
300px + 200px + 200px = 700px
А ширина контейнера, всего, как мы помним - 400px.
Как поступает браузер в такой ситуации?
Он «сбрасывает» margin-right в значение auto и рассчитывает его согласно формуле, то есть:
300px + 200px = 500px и эти 500px вычтит из 400px ( 400px — 500px = — 100px ).
А это значит, что margin-right у нас будет равен -100px.
Вот так.

Отсюда можно сделать вывод: по горизонтали margin участвует в расчете длины элемента, что никогда не делает margin по вертикали, потому что ширина определяется внешним фактором(шириной контейнера), а высота определяется содержанием элементов

Всем спасибо за внимание.
+60
6 июля 2011, 10:08
208

комментарии (60)

+1
beono #
Ох уж этот Margin Collapsing. Когда столкнулся с ним впервые никак не могу понять — Зааачееем?
0
Dark_Knight #
Согласен.
Я сам был в шоке :)
+4
lampslave #
softwaremaniacs.org/blog/2005/09/05/css-layout-flow-margins/
Читайте «Схлопывание границ» до полного просвещения.
0
Dark_Knight #
Мне бы пару лет назад такую статью :)
+2
lampslave #
«Маниакальный веблог, 05.09.2005 „
Так что и не пару можно.
0
beono #
Грациас! Я примерно так и думал.
0
whybenormal #
Спасибо, подробно и интересно излагаете.
0
Dark_Knight #
Рад помочь :)
+4
kurumpa #
Так как некоторые писали, что слово «маргин» «режет» глаз, то именно для них в этой статье будет написано только «margin»

Спасибо.
0
Krovosos #
Вы проигнорировали мое замечание относительно магнитофона относительно ширины блока и продолжаете указывать ее неправильно.

Правильно пишете в статье: "width — ширина поля содержания (content)" и все равно.

image

Ширина опять указана вместе с padding (правда теперь уже красной стрелкой, а не голубой).

Правильно будет, если ширина красной стрелки будет равна ширине блока second.

Зачем вводите в заблуждение?
–6
Dark_Knight #
Да, но это и так понятно, если я задам padding:0, то ширина блока все равно будет менятся, от паддинга она не завичит
+1
oddmanout #
по горизонтали margin участвует в расчете длины элемента, что никогда не делает margin по вертикали, потому что ширина определяется внешним фактором(шириной контейнера), а высота определяется содержанием элементов

Надо бы определиться с терминологией, а то и длина и ширина и высота… Какой-то 3D получается.
–1
Dark_Knight #
Но вы же поняли, что я имею в виду, тут нет никаких сложных формул :)
+3
torbasow #
Если уж Вы так чутки к пожеланиям читателей, то исправьте в статье опечатки. Их огромное количество. Между прочим, зачем Вы используете знак неравенства вместо «решётки»? Всё это не способствует читаемости статьи.
+1
pel #
> Между прочим, зачем Вы используете знак неравенства вместо «решётки»?
Кстати, это решетка. Легким наклоном курсива Verdana13px превращается… превращается… :)
0
tibalt #
короче, неудачно подобран шрифт)
0
medved13 #
Возможно выступлю в роли капитана очевидности, но всё это подробнейшим образом расписано в спецификации, у Мейера и в тысяче других книг по вёрстке. Так что любой верстальщик это знает.
+2
Dark_Knight #
У меня 4 книги по верстке, там подобного ничего нет
А вот в спецификации есть, не спорю
+5
Andrewus #
Для меня откровением стало то, что margin-top в процентах считается от ширины контейнера…
0
Snickersmix #
и я о том же
0
medved13 #
Это очень логично. Потому что если бы он считался от высоты контейнера, то случилась бы рекурсия, т.к. значение отступа входит в величину контейнера, от которого бы он считался.
–1
Snickersmix #
первый раз слышу чтобы отступ считал себя тоже. он считаем размер контейнера и не берет в расчет отступ. вы ломаете все мои стереотипы. если я задаю height, в расчет он не берется при высчитывании процетного margin-top:25% а в расчет берется размер внешнего контейнера, в котором находится этот блок
0
Snickersmix #
тоесть процент высчитывается от высоты внешнего блока, а не внутреннего
0
medved13 #
Во-первых, простите, ошибся. Margin это всё-таки поле, а не отступ. Отступ — padding.

Во-вторых:

Вы могли обратить внимание на некоторую странность в поведении абзацев, представленных на рис. 8.8. В соответсвии с изменениеми ширины родительских элементов меняются не только боковые поля, но и поля сверху и снизу. Такого поведения требует CSS. Вернёмся к объявлению свойства, и вы увидите, что процентные значения определяются относительно ширины родительского элемента. Это также относится и к верхнему и нижнему полям. Таким образом, исходя их следующих стилей и разметки выота верхнего поля абзаца составит 50px:

div p {margin-top: 10%;}
div style=«width:500px;»
p Это параграф текста и его верхнее поле в 10% ширину родителя /p
/div

Если значение width элемента div изменится, изменится также и верхнее поле. Кажется странным? Считаем, что высота большинства элементов в нормальном потоке такова, чтобы вместить их потомков, включая поля. Если верхнее и нижнее поля задать как процент от высоты родителя, это может привести к бесконечному циклу: высота родителя увеличивалась бы, чтобы вместить верхнее и нижнее поля, которые затем должны были бы увеличиться соответсвенно новой высоте и т.д. Вместо того чтобы просто игнорировать процентные значения для верхнего и нижнего полей, авторы спецификации решили соотнести их с шириной родительского элемента, которая не меняется в зависимости от щирины его потомков.
Эрик Мейер. Каскадные таблицы стилей. Подробное руководство. Стр. 253 в руссокм издании.
0
Snickersmix #
я не читал книг, но знаю на практике, если задать верхний и нижний отступ в процентах, он эти проценты высчитает от изначальной высоты контента. при этом не изменит размер самого контента, а просто сделает отсуп для всего что внутри. о какой рекурсии идет речь я не знаю. так как padding не изменяет размер контента и в расчетах опять же не учавствует
+2
medved13 #
почитайте книги. много нового для себя откроете.

я тоже долго думал, что пары статей и справочника по тэгам хватит для вёрстки. а потом прочёл пару книг и понял, что всё, что я делал до этого — детский лепет и движения слепого котёнка.
0
Snickersmix #
дело не в том что я читал. а в том что я делал и смотрел на поведение. я не по теории учусь, а потому как на самом деле это работает. если вы учились по подобной книге nano.sapegin.ru/entry/345 мне искрине жаль
0
Snickersmix #
забыл уточнить, паддинг не меняет размер высоты, если эта высота задана жестко. если же блок в сумме с padding не влезает в родительский, то родиельский начинает тянуться, пять же если он не задан жестко. если задан, то внутренний просто начинает вылазить на ружу. если же высота внутреннего задана например 100% а внешнего жестко, то рахмер будет меняться чтобы влесть вместе с padding'ами и margin'ами в этот самый родительский
–1
mirrr #
А теперь вдумайтесь, размер контейнера зависит от внутреннего блока с его margin. Если бы проценты считались от высоты контейнера, то происходила бы следующая ситуация:

Внутр: height: 10px; margin-top: 0%;
Наруж: height: 10px;

Внутр: height: 10px; margin-top: 10%;
Наруж: height: 10px + (10px*10%);
–1
mirrr #
Блин, комментарий сам отправился:
продолжение:

Внутр: height: 10px; margin-top: 10%(уже от 10px + (10px*10%))
Наруж: height: 10px + ((10px + (10px*10%))*10%)

и так далее, рост маржина провоцировал бы рост контейнера, тот в свою очередь увеличивал бы margin
0
Snickersmix #
может вы с padding-top перепутали? он берет размер высоту своего блока, но не себя опять же. и ширина на него уж точно никак не влияет. как то вообще странно чтобы высота зависила от ширины при процентном выставлении высоты
0
mirrr #
Но это так
0
VolCh #
Было бы по другому — было бы противоречие между margin: 10px и margin: 1 px — в первом случае поля одинаковые, во втором были бы разные (если контейнер не квадратный).
0
alemiks #
Достаточно один раз прочитать Мейера и откровений не будет ;) Будет просветление
+1
lampslave #
Спецификацию надо читать, тогда не будет откровений.
0
Snickersmix #
> Итак, margin по-вертикали считается от ширины контейнера
Меня просто плющит или все таки вертикаль это высота, а не ширина?
+1
Terion #
Все там верно написано.
Маржин считается исключительно от горизонтали родительского контейнера. Как горизонтальный, так и вертикальный. За исключением случая, когда блок позиционриован абсолютно.
+4
foo #
Ужасно сложно читать, поскольку в тексте очень много всевозможных ошибок.
Попробуйте перед публикацией проговаривать результат. Возможно, это хотя бы поможет правильно расставить запятые и избежать многословия.
+1
kulakowka #
Вот вот, читать было очень сложно. Не очень понятно почему. Ну и плюс иллюстрации оформлены ужасно. Надо добавить побольше воздуха в дизайн поста, и писать более простым и понятным языком с обязательным приведением конкретных примеров того, как можно использовать или как чаще всего используют ту или иную возможность. А так, получилось как всегда — «я умею так и вот так, только не знаю кому это нужно» :)
–1
danfe #
Кроме того, автор продолжает ставить пробелы с неправильной стороны скобок, несмотря на многочисленные просьбы так не делать.
–1
Dark_Knight #
чем вас пробелы не устраивают? или из-за них, вам читать тяжело? :)
0
danfe #
Меня не устраивает (ну, не так категорично, конечно, но все же) то, что вы крайне неряшливо с ними обращаетесь: то не ставите вовсе (например, между предложениями), то отбиваете скобки так, что приходится тратить секунды, чтобы распарсить ваш текст, то ставите запятую после точки. Зачем? Человек, читающий текст, ожидает видеть пробелы и знаки препинания там, где они нужны. Систематически и при этом хаотично нарушая это правило, вы действительно делаете ваш текст сложным для чтения и восприятия: вместо того, чтобы обрабатывать информацию, «циклы» мозга тратятся именно на чтение. Все равно что переключиться с DMA-режима в PIO.
+2
kulakowka #
Весьма и весьма познавательно. Немного запутано и сумбурно. Но если сильно вчитываться, то вполне доходчиво…
+4
Shedal #
margin, он же маргин

Он же марджин ;)
–1
Denai #
Подскажите пожалуйста что побудило вас использовать для этой графики jpg вместо png? В данном случае это выглядит хорошо, однако всё равно непонятно
0
Dark_Knight #
Мне и так пришлось уменьшать картинки, так как они не загружались в блог из-за большого размера, а если б я использовал.пнг, то они(картинки) были бы еще меньше
0
Denai #
Это плохо?
–1
Dark_Knight #
смотря для кого.
мне например без очков хрено видно бы было
0
Denai #
Эм, вы о размере ширина-высота? Тогда я действительно не понял. Почему бы они были меньше по ширине-высоте, если должен уменьшиться только размер (размер файлов, он же вес)?
–1
Dark_Knight #
Если я сделаю картинки в png такого же размера, как они сейчас в jpg то вес у них будет разный
0
Denai #
И у png он будет меньше, чем это плохо?
+2
Denai #
И спасибо за минусы в карму. Я видимо совсем глупый стал и не понимаю этот мир, но лучше бы всё-таки объяснили, чем минусовали.
+2
lampslave #
Хомячки минусуют, потому что это их инстинкт.
+2
Ryotsuke #
PNG были бы четче и меньше весили при тех же линейных размерах
например вот эта habrastorage.org/storage1/f2b6ec6f/4316ec92/a12707fa/8ba082ba.jpg
картинка в PNG8 128 colors весит 5Кб против 14Кб у JPEG
0
Ryotsuke #
Я уже не говорю про черно-белые, для которых подошел бы и PNG8 8 colors
0
Terion #
png8 еще никтон е отменял. И монохромные картинки в нем весили бы много меньше.
+1
klierik #
спасибо за статью.
в общем ничего нового так как где-то в подсознании и так понимал логику построения блока с вертикальным magrin, но тут разложено по полочкам.
позновательно.
0
Dark_Knight #
рад, что помог
–1
VolCh #
Зануда мод:
Это та область, в которой вы наблюдаете содержание, она зависит от разрешения вашего экрана.
Её размер зависит прежде всего от размера окна браузера, он может быть как меньше, так и больше разрешения экрана.
0
izharskiy #
поговорим о полях, они же маджин

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.