Почему процентная маржа вызывает новую строку?

<div style = "float : left; background-color: #dd3fb8;">
    <a style = "margin-left : 10%;">a</a> 
    <a>b</a> 
    <a>c</a> 
</div>

В приведенном выше примере буква "c" будет на новой строке, но если бы я установил единицу "margin-left" to px, "c" был бы на той же строке, что и "a" и "b". Почему это происходит?

Ответы

Ответ 1

К сожалению, спецификация CSS2.1, похоже, не имеет четкого ответа на этот вопрос. Фактически, я бы сказал, что это хорошо в сфере поведения undefined.

Вот соответствующие пункты, которые я могу найти:

  • Поплавки без указанной ширины будут сжиматься, чтобы соответствовать их содержимому. В случае поплавков с только встроенным контентом float нужно сделать достаточно широким, чтобы соответствовать его содержимому на одной строке (несмотря на явные разрывы строк) и не более.

  • Процентные отчисления рассчитываются в зависимости от ширины содержащего блока.

    Обратите внимание, что в нем говорится:

    Если ширина этого блока зависит от этого элемента, то результирующий макет undefined в CSS 2.1.

    ... но, насколько я вижу, поведение согласовано во всех браузерах.

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

Вот что я могу вывести на основе вышеперечисленных пунктов:

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

    Затем рассчитывается маржа на основе используемой ширины поплавка, а буква "c" обертывается на новую строку в результате продвижения вперед по краю на "a". Ширина поплавка не изменяется.

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

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

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

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

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

Ответ 2

Поскольку ваш div плавает, а его width - auto (неявно), применяется http://www.w3.org/TR/CSS21/visudet.html#float-width:

Если "width" вычисляется как "auto", используемое значение представляет собой ширину "shrink to-fit".

"shrink-to-fit" width в основном означает, что элемент должен быть таким же широким, как и его содержимое.

Теперь без margin-left это не проблема: все три из ваших a элементов являются встроенными элементами, которые содержат определенный символ каждый - достаточно легко определить их индивидуальную ширину и добавить их.

Но теперь вы хотите margin-left в процентах, и здесь все усложняется - если мы посмотрим на определение для margin-left, он говорит:

Проценты: см. ширину содержащего блока

Теперь это оставляет нас в немного рассола, так как ширина содержащего блока (который устанавливается элементом floated div) вычисляется на основе его содержимого - но теперь этот margin-left будет меняться общая ширина этого содержимого, но сама по себе зависит от width содержащего блока, который он сам влияет...

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

http://www.w3.org/TR/CSS21/box.html#margin-properties говорит,

Процент вычисляется по ширине сгенерированного блока, содержащего блок. [...]
Если ширина этого блока зависит от этого элемента, то итоговый макет undefined в CSS 2.1.


Изменить: В основном то же, что и в BoltClock, сказанное в его ответе, просто взяло меня немного дольше...

Ответ 3

Ссылка имеет левый край 10%, 10% от насколько? Родительский элемент плавает слева, что означает, что он не имеет собственной ширины, вместо этого он расширяет столько, сколько его содержимое. Если вы попытаетесь подражать тому, как браузер вычислит полученный в результате поле, и вы окажетесь в исправлении:

  • Пусть ширина содержимого (и, следовательно, контейнера) равна 30px
  • Добавить 10% от 30px = 3px левого поля к ссылке
  • Полученная ширина контейнера равна 30 + 3 = 33px

Это создает цикл, в котором маржа увеличивается по мере увеличения внешней ширины и увеличивается внешняя ширина с увеличением поля (10% от 33 пикселей = 3.3 пикселей означает, что ширина контейнера изменяется с 33 пикселей до 33,3 пикселей и т.д.). Для таких вычислений полученное поведение undefined (как указано CBroe).

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