Позиция: фиксированная в пределах позиции: фиксированная: какой браузер правильный?

Позиционирование фиксированного элемента внутри другого фиксированного элемента ведет себя по-разному в Chrome/Safari и Firefox.

Этот ответ хорошо объясняет ожидаемое поведение для фиксированного div внутри относительного, и MDN довольно ясно:

Фиксированное позиционирование Не оставляйте пространство для элемента. Вместо этого расположите его в указанной позиции относительно экрана просмотра и не перемещайте его при прокрутке. При печати разместите его в этом фиксированном положении на каждой странице.

Я не понимаю, что делает Firefox с фиксированным div внутри фиксированного div. Я ожидаю, что дочерний элемент перемещается вместе с оберткой при наведении.

.wrapper, .header {
  position:fixed;
  width:320px;
}

.wrapper:hover{
  left:0px;
}
.wrapper{
  width:320px;
  height:100%;
  background:white;
  overflow:scroll;
  left:-200px;
  transition: all ease-out .3s;
}
ul {
  margin-top:120px;
}
 .header {
   background:rgba(255,255,255,0.9);
}

body{
  background:gray;
<div class="wrapper">
  <div class="header">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repudiandae vitae a, itaque commodi, odio et. Excepturi, obcaecati? Architecto repellendus omnis mollitia animi rem quasi at, odit aperiam voluptatibus voluptates earum!
  </div>
  <ul>
    <li>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
    </li>
    <li>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
    </li>
    <li>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
    </li>
    <li>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
    </li>
  </ul>
</div>

Ответ 1

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


11/18/16 Обновление - CSSWG вернулся ко мне и сказал, что он должен создать новый контекст стекирования:

Вы правы, это должно было быть также объединено с позиционирующей спецификацией - отражено сейчас. Спасибо.


По вопросу о том, какой браузер правильный:

Элементы позиции

fixed всегда должны быть размещены относительно окна просмотра, в частности, что элемент position: fixed, содержащий блок, установлен "в окне просмотра" в 10.1.3:

Если элемент имеет "position: fixed", содержащий блок устанавливается с помощью окна просмотра [...]

Этот содержащий блок формально называется "исходным содержащим блоком".

9.3.1 также подтверждает это, говоря, что для обычных невыгружаемых носителей (например, это),

[...] В случае типов карманных, проекционных, экранных, tty и tv-носителей, поле фиксируется относительно окна просмотра и не перемещается при прокрутке.

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

10.3.7 говорит

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

(статическое положение здесь означает положение элемента, если оно помещено в нормальный поток).

В нем также говорится:

[Если] "left" и "right" - "auto", а "width" не "auto", [...] установите "left" в статическую позицию, в противном случае установите "right" в статическую позицию, Затем решите для "left" (если "direction is" rtl ") или" right "(если" direction "is 'ltr').

Это объясняет, я полагаю, почему для элемента child position: fixed изначально установлено значение left: -200px;, где оно было бы в пределах его родительского элемента, если бы оно было position: static.

На данный момент похоже, что родительское новое значение left должно перемещать дочерний элемент, я предполагаю, потому что вы ожидаете, что новое свойство left будет унаследовано дочерним элементом (что не является как работает left), или вы ожидаете, что он будет повторно документировать документ, чего не происходит на :hover, как я помню; браузер только повторно рисует на :hover, который не меняет поток документа, но меняет внешний вид элементов (например, background-color, opacity, visibility: hidden; и т.д.).

Итак... элементы перекраски не должны перемещаться, если нет псевдоселекторов, которые изменяют свойства во время временных состояний (например, :hover) или переходы/анимации при воспроизведении.

В этой ситуации кажется, что Chrome и Safari делают что-то другое, кроме того, что предлагает спецификация; они либо вызывают полный повторный поток, либо устанавливают элементы position: fixed для наследования свойств left у предков. Это, по-видимому, выше платы, если хотите, в соответствии с проектом CSS Working Group, связанным с Oriol ниже. Тем не менее, это все еще нестандартное поведение, пока спецификация не будет обновлена.

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

Сделайте div .header наследующим ваше новое свойство left, так как это делает Chrome, и это поведение, которое вы ищете. Я также немного отрегулировал ширину .header, так что она не будет закрывать полосу прокрутки на .wrapper:

.wrapper, .header {
  position: fixed;
}

.wrapper:hover {
  left:0px;
}
.wrapper{
  width:320px;
  height:100%;
  background:white;
  overflow:scroll;
  left:-200px;
  transition: all ease-out .3s;
}
ul {
  margin-top:120px;
}
.header {
  background:rgba(255,255,255,0.9);
  left: inherit;
  width: 303px;
}

body{
  background:gray;
}
<div class="wrapper">
  <div class="header">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Repudiandae vitae a, itaque commodi, odio et. Excepturi, obcaecati? Architecto repellendus omnis mollitia animi rem quasi at, odit aperiam voluptatibus voluptates earum!
  </div>
  <ul>
    <li>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
    </li>
    <li>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
    </li>
    <li>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
    </li>
    <li>
      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium quam maiores, voluptas facere, iste quis iusto reiciendis delectus, quod blanditiis tempora. Earum voluptatum dicta quae, explicabo placeat at rerum assumenda!
    </li>
  </ul>
</div>

Ответ 2

Итак, я думаю, проблема возникла из-за ошибки в реализации left в Firefox.

При падении .wrapper, .header должно получить новое значение left из его родительского .wrapper i.e. 0px. При наведении .wrapper левое положение .header должно быть рассчитано с использованием значения left из его родительского .wrapper, поскольку явное значение left не присваивается .header.

Я думаю, что это связано с ошибкой в Firefox. Если вы активируете :hover псевдокласс класса .wrapper с помощью Firebug или инструмента разработчика по умолчанию, левая позиция .header поддерживается как в Chrome (но внезапно).

Протестировано на Firefox 49.0.2 и Chrome 54.0.2840.71