Странное поведение фона при перекрытии элементов

Вот ситуация (код протестирован с использованием Chrome, Firefox и IE11)

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  text-align: right;
  background: green;
  animation: animate 2s infinite alternate linear;
}

@keyframes animate {
  from {
    margin-top: 10px;
  }
  to {
    margin-top: -40px;
  }
}
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>

Ответ 1

ПРЕДУПРЕЖДЕНИЕ: чтение следующей информации может повлиять на ваше психическое здоровье.

Порядок окраски для потомков элемента, создающего контекст стекирования (см. Свойство z-index):

  1. Если элемент является корневым элементом:
    1. цвет фона элемента по всему холсту.
    2. фоновое изображение элемента, по всему холсту, закрепленное в начале координат, которое будет использоваться, если оно было окрашено для корневого элемента.
  2. Если элемент
    • блок, элемент списка или другой эквивалент блока:
      1. цвет фона элемента, если он не является корневым элементом.
      2. фоновое изображение элемента, если оно не является корневым элементом.
      3. столбца элемента.
      4. граница элемента.
    • В противном случае, если элемент является таблицей уровня блока:
      1. таблицы (цвет, затем изображение), если это не корневой элемент.
      2. фон столбцов группы (цвет, затем изображение).
      3. фон столбца (цвет затем изображение).
      4. группы строк (цвет, затем изображение).
      5. (цвет затем изображение).
      6. (цвет затем изображение).
      7. правило столбцов для нескольких столбцов.
      8. все границы таблицы (в порядке дерева для разделенных границ).
  3. Сочетание контекстов, образованных позиционируемыми потомками с отрицательными z-индексами (исключая 0) в порядке z-индекса (с наибольшим отрицательным первым), затем порядок дерева.
  4. Для всех своих потоковых, непозиционированных потомков блочного уровня в древовидном порядке:
    • Если элемент является блоком, элементом списка или другим эквивалентом блока:
      1. цвет фона элемента.
      2. фоновое изображение элемента.
      3. столбца элемента.
      4. граница элемента.
    • В противном случае элемент представляет собой таблицу:
      1. стола (цвет затем изображение).
      2. фон столбцов группы (цвет, затем изображение).
      3. фон столбца (цвет затем изображение).
      4. группы строк (цвет, затем изображение).
      5. (цвет затем изображение).
      6. (цвет затем изображение).
      7. правило столбца ячейки (многоколоночное).
      8. все границы таблицы (в порядке дерева для разделенных границ).
  5. Все нележащие плавающие потомки в древовидном порядке. Для каждого из них обрабатывайте элемент так, как если бы он создавал новый контекст стекирования, но любые позиционированные потомки и потомки, которые фактически создают новый контекст стекирования, считаются частью родительского стекового контекста, а не нового.
  6. Если элемент является встроенным элементом, который генерирует контекст стекирования, то:
    1. Для каждого поля строки, в котором находится элемент:
      1. Перейдите к пункту 7.2.1 для поля (ов) элемента в этом поле строки (в древовидном порядке).
  7. В противном случае: сначала для элемента, затем для всех его потоковых, непозиционированных потомков уровня блока в порядке дерева:

    1. Если элемент является замещенным на уровне блока элементом, то: замененное содержимое - атомарно.
    2. В противном случае для каждого окна строки этого элемента:

      1. Для каждого окна, являющегося дочерним элементом этого элемента, в этом поле строки в порядке дерева:

        1. цвет фона элемента.
        2. фоновое изображение элемента.
        3. столбца элемента.
        4. граница элемента.
        5. Для встроенных элементов:
          1. Для всех элементов, находящихся в потоке, не-позиционированных дочерних рядовых дочерних элементов, которые находятся в этом поле строки, и всех прогонов текста внутри элемента, который находится в этом поле строки, в древовидном порядке:
            1. Если это пробег текста, то:
              1. любое подчеркивание, влияющее на текст элемента, в древовидном порядке элементов, применяющих подчеркивание (так что самые глубокие элементы, подчеркивающие, если таковые имеются, раскрашены сверху, а корневые элементы, подчеркивающие, если таковые имеются, нарисованы ниже).
              2. любое перекрытие, влияющее на текст элемента, в древовидном порядке элементов, применяющих перекрытие (так, что самые глубокие элементы, перекрывающие, если таковые имеются, раскрашены сверху, а корневые элементы, перекрывающие, если таковые имеются, нарисованы ниже).
              3. текст
              4. любая строка, влияющая на текст элемента, в древовидном порядке элементов, применяющих линейный проход (такой, что самые глубокие элементы, проходящие через линию, если они есть, раскрашены сверху, а корневые элементы линейны, если они есть, оттянутое большинство).
            2. В противном случае перейдите к 7.2.1 для этого элемента
        6. Для встроенных блоков и встроенных элементов таблицы:
          1. Для каждого из них обрабатывайте элемент так, как если бы он создавал новый контекст стекирования, но любые позиционированные потомки и потомки, которые фактически создают новый контекст стекирования, считаются частью родительского стекового контекста, а не нового.
        7. Для замененных элементов inline-уровня:
          1. замененное содержимое, атомарно.
        8. Необязательно, контур элемента (см. Ниже).

        Обратите внимание: некоторые из полей могут быть сгенерированы путем разделения строк или двунаправленного алгоритма Unicode.

    3. Необязательно, если элемент является блочным уровнем, контур элемента (см. Ниже).

  8. Все позиционированные, непрозрачные или трансформированные потомки в древовидном порядке относятся к следующим категориям:

    1. Все размещенные потомки с "z-index: auto" или "z-index: 0" в порядке дерева. Для тех, у кого есть "z-index: auto", обрабатывайте элемент так, как если бы он создавал новый контекст стекирования, но любые позиционированные потомки и потомки, которые фактически создают новый контекст стекирования, должны рассматриваться как часть родительского стекового контекста, а не новый, Для тех, у кого "z-index: 0", обрабатывается контекст стекирования, сгенерированный атомарно.

    2. Все потомки непрозрачности с непрозрачностью менее 1, в древовидном порядке, создают стековый контекст, сгенерированный атомарно.

    3. Все трансформированные потомки с преобразованием, отличным от ни одного, в древовидном порядке создают контекст стекирования, сгенерированный атомарно.
  9. Сочетание контекстов, сформированных позиционируемыми потомками с z-индексами, большими или равными 1 по порядку z-индекса (наименьшим первым), затем порядком дерева.

Теперь серьезно, обратитесь к документации по заказу краски w3c

В пункте 4.1 фон детей окрашен

В пункте 4.4 окрашивается граница детей.

Когда пункт 4 закончен, весь фон и граница вашего фрагмента были нарисованы

Теперь, в пункте 7.2.1.5.1.1.3, текст детей окрашен.

Это поведение, которое вы видите.

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

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  text-align: right;
  background: green;
  animation: animate 2s infinite alternate linear;
  opacity: 0.9999;
}

@keyframes animate {
  from {
    margin-top: 10px;
  }
  to {
    margin-top: -40px;
  }
}
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>

Ответ 2

Это из-за иерархии... Я попытаюсь объяснить это немного подробнее...

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  margin-top:-10px;
  text-align: right;
  background: green;
}
<div class="box">
  some content
</div>
<div class="bottom">
  other content
</div>

Ответ 3

Ответ на вопрос нигде рядом с кем-то не копается. Потому что все мы исправили наш ум, полагая, что это то, что во многом использует опыт пользователя, что-то интуитивное. Кто-нибудь думал, что это может быть для любой обработки процессора benifit?

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

Browser rendered layers

Итак, как создаются слои?

  • Рендеринг двигателя окрашивает все фоны и границы на базовом слое.
  • Создает новый слой для элемента с указанным позиционированием. Слой укладывается поверх базового слоя, чтобы графический процессор мог растеризовать его. Когда элемент перемещается, движок рендеринга только говорит графическому процессору, чтобы переместить слой, GPU делает все остальное. CPU сохраняется из-за накладных расходов.
  • Создает новый слой для элемента с непрозрачностью. При изменении прозрачности графический процессор выполняет растеризацию.
  • Аналогичным образом создается новый слой для входов, кнопок, холстов, видео, все, что может вызвать многократную краску процессора, переносится на GPU в качестве нового слоя. Мы сохраняем много процессорной обработки, не так ли? :)
  • Отрицает создание любого нового слоя для элемента с отрицательным полем :( Это очевидно, что браузер не может выпустить новый слой для каждого элемента с маржером, их много. Даже если он имеет отрицательный запас, он может или не может перекрывать другой элемент. Единственный способ убедиться в том, что вы посмотрите на дерево рендеринга. То, что мы пытаемся сохранить обработку, глядя в дерево рендеринга для каждого элемента, испортит его.
  • Выдает новый слой для текстового элемента. GPU может растрировать текст гораздо эффективнее на фоне, так зачем рисовать его с помощью ЦП на базовом уровне? Это был оригинальный вопрос. Думаю, теперь все могут ответить.

Почему текст окрашен на отдельный слой над базовым слоем?

  • CPU не нужно рисовать текст поверх фона, процессор счастлив.
  • Когда цвет текста или тени меняют ЦП, только окрашивает текстовый слой, GPU растеризует его на фоне.
  • Когда фоновые изменения в ЦП только окрашивают фоновый слой, GPU растеризует текст поверх него.
  • Когда текст прокручивается по фиксированному фону, рисование не требуется, CPU говорит только о том, что GPU перемещает текстовый слой, а GPU делает все остальное.
  • И многое другое...

Теперь рассмотрим магию, с которой мы сталкиваемся.

painting and rasterizing

  • Случай 1: Когда относительное положение добавляется во второй div, он получает новый слой, этот новый слой укладывается поверх базового слоя и даже поверх текстового слоя первого div.
  • Случай 2: То же самое происходит, когда применяется непрозрачность.
  • Случай 3: Любой стиль преобразования создаст новый слой.
  • Случай 4: Это интересно. Поля не создают ни одного слоя для второго div, он нарисован на базовом div после того, как первый div будет окрашен, поэтому он нарисован над первым div на том же слое. Текст первого div находится на собственном слое, который укладывается поверх базового слоя, поэтому GPU растеризует текст на фоне второго div.

[источник: developers.google.com ]

Ответ 4

Ответ @vals подсчитан, где это поведение объясняется в спецификации, но при условии, что только 80% ответа, поскольку я все еще ищу почему? , Поскольку это поведение как-то противоречиво, я пытался найти реальные варианты использования, когда это поведение должно быть таким, а не так, как я ожидал.

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

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


Поскольку у веб-разработчика есть полный контроль над его разработкой, я спрашивал себя, есть ли какие-либо внешние инструменты, которые могут повлиять на его CSS и рендеринг его веб-страницы, которую он не может контролировать?

Да, и один из них связан с доступностью. Я не говорю о рекомендациях, которые должен соблюдать веб-разработчик, но о некоторых виджетах на каком-то веб-сайте, которые позволяют увеличить размер шрифта, изменить контраст и т.д., Чтобы помочь вам лучше читать содержание. Этот вид виджетов можно интегрировать в любом месте с помощью надстроек.

Здесь упрощенный пример, когда пользователь может увеличить размер шрифта и где вышеприведенное поведение полезно, поскольку оно будет содержать текстовое содержимое выше, поэтому мы с легкостью можем его прочитать:

$('button').click(function() {
   $('body').css('font-size','22px');
})
body {
 font-size:14px;
 max-width:500px;
}
section {
  height: 80px;
  background: red;
  padding:5px;
  border-top: 40px solid blue;
  color:#fff;
}
div {
  height:80px;
  background:url(https://lorempixel.com/g/400/400/) center/cover;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Make font bigger</button>
<section>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam cursus posuere dolor vel faucibus. Proin augue orci, tempor cursus erat aliquet, pellentesque suscipit odio. Sed eleifend diam in justo vehicula feugiat. In pretium, elit eu dapibus efficitur,
</section>
<section>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam cursus posuere dolor vel faucibus. Proin augue orci, tempor cursus erat aliquet, pellentesque suscipit odio. Sed eleifend diam in justo vehicula feugiat. In pretium, elit eu dapibus efficitur,
</section>
<div>
</div>

Ответ 5

Один из способов задать вопрос: может ли он обрабатываться по-разному и по-прежнему управлять различными функциями, требуемыми CSS, особенно для свойства float?

Что спецификация говорит, что для контекста стекирования (в основном верхнего блока части дерева DOM, который позиционируется) вы рисуете элементы в этом порядке:

  1. фон верхнего элемента контекста укладки
  2. элементы с отрицательным индексом z

До сих пор это имеет смысл, тогда у вас есть

  1. все фоны и границы всех элементов уровня блока (в основном элементы, которые отображаются: блок, но не расположены) в дереве под верхним элементом.
  2. затем все плавающие элементы всего дерева под верхним элементом.
  3. Этот шаг выполняется в другом шаге 2, поэтому он не мешает этому конкретному случаю.
  4. Затем все входящие элементы (или неплавающие элементы) всего дерева под верхним элементом (это не только тексты, которые отображаются в 7, это все встроенные элементы. Если ваши встроенные элементы имеют фон, это замаскирует то, что позади).

"Проблема" в этом заключается в том, что элементы потока не отображаются в порядке дерева. Фон элемента ниже в дереве может быть отображен перед элементом потока в дереве. Что подразумевается в вопросе, так это то, что мы ожидаем чего-то большего:

  1. визуализировать все фоны и элементы границы и в потоке всех элементов уровня блока в древовидном порядке.

Это создало бы элементы более интуитивно понятным способом. Итак, зачем тогда отделять входящие элементы от остальных. Почему шаг 5 перед шагом 7? Ясно, что если вы это сделаете, у вас возникнет проблема с вашими плавающими элементами. Они должны быть размещены перед остальной частью потока, потому что это то, что они есть, элементы, которые выведены из потока. Итак, шаг 5 имеет смысл, вам нужно рассмотреть плавающие элементы перед неплавкими элементами.

Итак, что, если они были показаны на шаге 4, вот так:

  1. все фоны и границы, затем плавающие и затем неплавающие элементы всех элементов уровня блока в древовидном порядке.

У вас все еще есть проблема, из-за того, что ожидается от плавающих элементов. См. Этот фрагмент:

body {
  margin: 0;
  background: pink;
  color: #fff;
}

.box {
  margin-top: 20px;
  background: red;
}

.bottom {
  margin-top:-10px;
  text-align: left;
  background: green;
  
}
<div class="box">
  <span>some content some content some content some content some content some content some content some content some content some content</span>
<span style="float: left; background: navy">
  floated content box<br>
  floated content box<br>
  floated content box<br>
  floated content box
  </span>
  
 
  
  
</div>
<div class="bottom">
  <span style="background-color:turquoise;">other content</span>
  <span style="float: left; background-color:bisque;">
  floated content bottom<br>
  floated content bottom<br>
  floated content bottom
  </span>
  
 
  
</div>

Ответ 6

Важно отметить, что для этого случая каждый div имеет свою высоту из-за его содержимого. пусть скажут на мгновение, что результирующая высота равна 20px.

то, если вы скажете, что первый div будет иметь margin-top: 20px, второй div, который был объявлен после первого, начинается с того, где заканчивается первый div.

поэтому исходным положением второго будет крайний верх первого плюс высота первого. скажем, что дает 40px.

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

Ответ 7

Что происходит, так это то, что у вас есть два перекрывающих друг друга "ящика", которые нужно отображать на том же уровне z, слой 0. Однако в разделе "Введение в базовую коробку моделей CSS", объясняющей граничную область, говорится:

Когда в поле установлен фон (background-color или background-image), он распространяется на внешний край границы (т.е. распространяется под границей в z-порядке).

Я предполагаю, что граница и контент находятся на переднем плане.

Итак, спецификация рисования всех ящиков на одном слое в сочетании с спецификацией рисования фона под передним планом, я думаю, это приводит к рисованию всех фонов под всеми передними областями.

Внутри каждого "подслоя" перекрытие выполняется в соответствии с порядком HTML.

Чтобы понять, почему DIV в сообщении находятся на одном уровне, следует прочитать контекст стекирования.

Чтобы "понять", почему backgroung идет под передний план, следует прочитать " Введение в базовую коробку моделей CSS".