Почему проценты margin/padding в CSS всегда вычисляются по ширине?

Если вы посмотрите на спецификацию модели CSS-бокса, вы увидите следующее:

Процент [margin] рассчитывается по отношению к ширине созданного блока, содержащего блок. Обратите внимание, что это верно и для "margin-top" и "margin-bottom".. Если ширина используемого блока зависит от этого элемента, то результирующий макет undefined в CSS 2.1. (акцент мой)

Это действительно так. Но почему? Что же может заставить кого-нибудь спроектировать его таким образом? Легко думать о сценариях, где вы хотите, например. определенная вещь всегда должна быть на 25% ниже верхней части страницы, но трудно найти любую причину, по которой вы хотите, чтобы вертикальное заполнение было относительно горизонтального размера родителя.

Вот пример феномена, который я имею в виду:

<div style="border: 1px solid red; margin: 0; padding: 0; width: 200px; height: 800px;">
  This div is 200x800.
  <div style="border: 1px solid blue; margin: 10% 0 0 10%;">
    This div has top-margin of 10% and left-margin of 10% with respect to its parent.
  </div>
</div>

http://jsfiddle.net/8JDYD/

Ответ 1

Передача моего комментария в ответ, потому что он имеет логический смысл. Однако учтите, что это необоснованная гипотеза. Фактическое рассуждение о том, почему спецификация написана таким образом, по-прежнему технически неизвестна.

Высота элемента определяется высотой дети. Если элемент имеет padding-top: 10% (относительно родительского height), что будет влиять на высоту родителя. Поскольку высота ребенка зависит от высоты родителя, а высота родителя зависит от высоты ребенка, мы будем либо имеют неточную высоту, либо бесконечный цикл. Конечно, это только влияет на случай, когда смещенный родительский родитель, родитель, но все же. Это нечетный случай, который трудно решить.

Обновление: последние предложения пары могут быть не совсем точными. Высота элемента листа (ребенок без детей) влияет на высоту всех элементов над ним, поэтому это затрагивает множество различных ситуаций.

Ответ 2

Для поля "n%" (и заполнения) должно быть одинаковым для margin-top/margin-right/margin-bottom/margin-left, все четыре должны относиться к одной и той же базе. Если верхняя/нижняя область использовала другую базу, чем левая/правая, то маржа "n%" (и отступы) не будет означать одно и то же на всех четырех сторонах.

(Также обратите внимание, что верхнее/нижнее поле по отношению к ширине допускает странный CSS-хак, который позволяет вам указать поле с неизменным соотношением сторон... даже если окно изменено.)

Ответ 3

Я проголосую за ответ от @ChuckKollars после игры с этим JSFiddle (в Chrome 46.0.2490.86) и ссылаясь на этот пост (на китайском языке).


Основная причина против бесконечной гипотезы расчета заключается в том, что использование width сталкивается с той же бесконечной задачей вычисления.

Посмотрите на JSFiddle, на дисплее parent inline-block, который может определять маржи/отступы в теме. Значение child имеет значение поля 20%. Если мы следуем бесконечной гипотезе расчета:

  • Ширина child зависит от parent
  • Ширина parent зависит от child

Но в результате Chrome останавливает вычисление где-то, в результате:

введите описание изображения здесь

Если вы попытаетесь расширить панель "результат" по горизонтали на JSFiddle, вы обнаружите, что их ширина не изменится. Обратите внимание, что содержимое в child заключено в две строки (не, скажем, одна строка), почему? Наверное, Chrome просто жестко кодирует его где-то. Если вы отредактируете контент child, чтобы сделать его больше (JSFiddle), вы обнаружите, что до тех пор, пока есть дополнительное пространство по горизонтали, Chrome сохраняет содержимое двух строк.

Итак, мы можем видеть: есть способ предотвратить бесконечный расчет.


Я согласен с догадкой о том, что: этот проект состоит только в том, чтобы сохранить четыре значения margin/padding на основе той же меры.

этот пост (на китайском языке) также предлагает другую причину: это из-за ориентации чтения/набора. Мы читаем сверху вниз, с фиксированной шириной и высотой (фактически).

Ответ 4

Я понимаю, что ОП задает почему спецификация CSS определяет процентные доли верхнего и нижнего полей как% от ширины (а не, как предполагается, высоту), но я думал, что это также может быть полезно для публикации потенциального решения.

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

100vw/100vh равно 100% ширине /100% высоте (соответственно), если нет полосы прокрутки; если есть полоса прокрутки, номера в окне просмотра не учитывают это (в то время как номера%). К счастью, почти все браузеры используют размеры прокрутки 17px (см. Здесь), поэтому вы можете использовать функцию css calc для учета этого. Если вы не знаете, появится ли полоса прокрутки или нет, это решение не будет работать.

Например: если горизонтальная полоса прокрутки, верхний край 50% высоты, может быть определена как "margin-top: 50vh;". С горизонтальной полосой прокрутки это можно определить как "margin-top: calc (0.5 * (100vh - 17px)); (помните, что для операторов минус и плюс в calc требуются пробелы с обеих сторон!).