【问题标题】:Position:fixed element within a position:relative parent. Which browser renders correctly?位置:位置中的固定元素:相对父级。哪个浏览器正确呈现?
【发布时间】:2015-02-19 22:26:55
【问题描述】:

我发现固定位置元素在相对定位的父元素中的行为方式存在差异。根据我在网上找到的文档,FireFox 和 Chrome 应该将元素修复到视口而不是父级。但是,我发现如果我没有在固定元素上指定左/右值,它的行为是静态和固定之间的一种混合,从某种意义上说,它垂直于视口固定,但就像它一样移动父元素中的静态元素。我找不到围绕这些条件的任何官方/受人尊敬的文件。它们基本上都声明如下:

固定定位 不要为元素留出空间。相反,将其放置在相对于屏幕视口的指定位置,并且在滚动时不要移动它。打印时,将其放置在每一页的固定位置。

Source

另一方面,Safari 似乎按照描述的方式渲染它,它完全固定在视口中,无论我是否将父元素设置为相对而没有定义任何上/右/下/左属性。如果有机会,请在 Safari 中尝试一下,方法是单击距离左侧 -100 像素的蓝绿色 div。黄色条将固定在视口上:

http://jsfiddle.net/bbL8Lh4r/2/

那么哪个浏览器可以正确呈现这个?我所有的浏览器都已更新到最新版本。起初我认为 Safari 是正确的,只是通过阅读文档,但 FireFox 和 Chrome 都共享相同的不同视图,它似乎是静态和固定的混合体。


HTML

<body>
    <aside>
        Blah
    </aside>

    <div class="container">
        <div class="nav">
            BLARGH
        </div>
    </div>
</body>

CSS

body,
aside,
.container,
.nav {
    margin:0;
    padding:0;
}

aside {
    background:red;
    width:30%;
    height:800px;
    float:left;
}

.container {
    position:relative;
    height:800px;
    width:70%;
    background:teal;
    float:right;
}

.container.stickied {
    left:-100px;
}

.container .nav {
    position:fixed;
    background:yellow;
    width:inherit;
}

【问题讨论】:

  • 有趣的是,如果您明确定义任何框位置属性,则该元素将不再继承其他元素。
  • @GregRozmarynowycz 正确。该行为在 W3C 规范中定义,关于框偏移和 fixed 元素的包含块。
  • CSS2.1 表示在计算固定定位元素的静态位置时,指定的包含块是初始包含块,而不是视口。 (由于某种原因,我在 css-position 中找不到相同的文本。)它说初始包含块采用视口的尺寸,并且似乎暗示即使内容溢出视口也不会改变,但它在这方面尚不清楚。所以也许这个问题的根源是:初始包含块是如何确定的?
  • @BoltClock 根据我回答中的研究,在这种情况下,我们可以说它完全不是由浏览器决定的 :-P

标签: html css css-position


【解决方案1】:

这似乎是一个有趣的案例。让我们深入了解规格以了解发生了什么。


TL;DR: W3 规范在这方面非常模糊/未定义,但似乎所有浏览器都偏离了规范,或者至少,他们制定了细节未定义的决定。然而,四种主流浏览器(Firefox、Chrome、IE 和 Opera)似乎都以同样的方式偏离规范。 Safari 绝对是个怪人。


这就是 CSS2.1 规范在 Chapter 9: Visual formatting model 中所说的:

  1. 9.1.2 Containing blocks - 在 CSS 2.1 中,许多框的位置和大小是相对于称为包含块的矩形框的边缘计算的。一般来说,生成的盒子充当后代盒子的包含块;我们说一个盒子为它的后代“建立”了包含块。短语“盒子的包含块”是指“盒子所在的包含块”,而不是它生成的那个。

这只是定义了一个包含块是什么。

  1. 9.3 Positioning Schemes - 绝对定位:在绝对定位模型中,将一个盒子从正常流程中完全移除,并分配一个相对于包含块的位置。

这表示绝对定位的元素是相对于包含块定位的。

  1. 9.6 Absolute Positioning - 在绝对定位模型中,框相对于其包含块显式偏移。 [...] 本规范中对绝对定位元素(或其框)的引用暗示该元素的position 属性的值是absolutefixed

这表示绝对定位的元素包括position:fixed; 元素以及position: absolute; 元素。

  1. 9.6.1 Fixed Positioning - 固定定位是绝对定位的一个子类别。唯一不同的是,对于一个固定位置的盒子,包含块是由视口建立的。

这表示position: fixed; 元素具有视口(嗯,不是字面意义上的视口,而是一个与视口具有相同尺寸和位置的框)作为它们的包含框。这一点稍后由 10.1 Definition of containing block 中的规范支持:

如果元素具有“位置:固定”,则包含块由视口建立 [...]

(如果您不熟悉什么是视口,它是“屏幕上的窗口或其他查看区域,用户通过它查阅文档”。视口的尺寸是初始包含块的基础。您的整个 HTML 内容(&lt;html&gt;&lt;body&gt; 等)都位于视口定义的初始包含块中。)

因此,应用了position: fixed;&lt;div class="nav"&gt; 元素应该有一个等于视口的包含块,或初始包含块


现在确定.nav 元素属性的第一步已经完成,我们可以确定浏览器的行为方式。

CSS2.1 规范是这样说的:

  1. 9.7 Relationships between 'display', 'position', and 'float' - 否则,如果 'position' 的值为 'absolute' 或 'fixed',则框是绝对定位的,'float' 的计算值为 'none',并设置显示根据下表。盒子的位置将由 'top'、'right'、'bottom' 和 'left' 属性以及盒子的包含块确定。

这基本上告诉我们,对于绝对定位的元素position: fixed;position: absolute;),任何float 属性都将被忽略,&lt;div&gt; 元素(以及其他)被设置到display: block;,并且元素根据其框偏移值toprightbottom,和/或left与初始包含块(视口)组合定位。

  1. 9.3.2 Box offsets: 'top', 'right', 'bottom', 'left' - 如果元素的“位置”属性的值不是“静态”,则称该元素已定位。定位元素生成定位框,根据四个属性布局:上、右、下、左。

这只是重申了&lt;div class="nav"&gt; 应根据其框偏移量定位的事实。

虽然它在几个地方说如果两个相反的偏移值是auto,那么它们被设置为零,CSS2.1 似乎没有指定如何用left 和@ 定位元素的情况987654354@ 值为零。但是,CSS Box Alignment Module Level 3 确实提到该值设置为“start”,其定义为:

对齐对齐对象,使其与对齐容器的起始边缘齐平。

这应该意味着元素位于包含块的左上角,对于position: fixed; 元素,它应该与视口相同。但是,我们可以看到,对于所有主流浏览器来说,情况并非如此没有主流浏览器似乎按照规范的指示将position: fixed; 的包含块设置为视口的包含块。相反,它们都表现得好像position: fixed;position: absolute; 之间的行为应该相同。

总而言之,当您在规范中拥有这么多证据时,答案很明确:position: fixed; 元素应该有一个包含块设置到视口。同样清楚的是,供应商都决定以自己的方式填写规范的模糊部分,与此声明相冲突或完全无视。最有可能发生的是一个浏览器实现了他们的解释(IE7 是第一个支持position: fixed;,我相信,紧随其后的是 Firefox 2.0),其余的紧随其后。

【讨论】:

  • 非常彻底,并提供了我所倾向于的证据,尽管对它不够肯定(也没有时间进一步研究)以让我的答案反映它。这应该是公认的答案。
  • 我认为这个分析可能不正确:“为了计算静态位置,固定定位元素的包含块是初始包含块而不是视口,应该假设所有可滚动的框滚动到它们的原点。”见drafts.csswg.org/css2/visudet.html#abs-non-replaced-width
  • @TomW 你认为那句话可能不正确?或者您认为根据该引用的某些部分分析是不正确的?如果是后者,您具体觉得哪一部分不正确;这里有很多信息,来自规范的不同部分。
  • @TomW 作为记录,最初的包含块是一个与视口具有相同位置和尺寸的块,正如我在回答中水平规则上方的最后几句话中所提到的。可以这么说,您可以互换使用术语“视口”和“初始包含块”,而不会产生任何影响。
  • @TylerH,实际上,再次阅读并再次阅读您的参考资料,我目前无法指责您的分析 - 抱歉打扰了!布局领域的规范非常复杂,有些模棱两可。我怀疑该规范旨在记录浏览器正在做什么:也就是说,对于没有明确定位的固定元素,以与绝对元素相同的方式定位它们。我看不到浏览器的变化,这意味着规范可能(最终)会发生变化。
【解决方案2】:

阅读 W3C 规范,我想说 Chrome/FF 中的行为实际上是正确的:

Fixed Positioning

框的位置是根据“绝对”模型计算的,但另外,框相对于某些参考是固定的。

相对于包含块的绝对模型位置:

Absolute Positioning

框的位置(可能还有大小)由 top、right、bottom 和 left 属性指定。这些属性指定相对于盒子的包含块的偏移量。

编辑:对于固定位置元素,containing block 被定义为视口:

如果元素有'positioned:fixed',在连续媒体的情况下,包含块由视口建立

但是,在所有定位属性都设置为auto 的情况下,我找不到任何关于auto 应该导致的确切结果的定义。因此,父级的位置定义了固定元素的初始位置,如果没有给出其他立场。此外,当滚动时,元素确实保持固定相对于视口,如指定的那样。如果父元素移动,固定元素应该随着它的初始位置移动;与您更改 left 属性时所期望的移动相同。

如果将块与其父级一起移动是不正确的,那么首先根据该父级来定位它是不正确的。唯一的选择是将其放置在auto 属性的视口左上角。如果是这种情况,则所有浏览器都错误地实现了规范,Safari 只是有一个错误且不一致的实现。

值得注意的是,无论父元素是否相对定位,都会发生表现行为。

【讨论】:

  • 这种解释只是忽略了3.1 以及其他地方的规范。 " 如果元素具有'定位:固定',则包含块在连续媒体的情况下由 viewport 建立,在分页媒体的情况下由页面区域建立。"包含块不是 position: fixed; 元素的父元素。
  • 我将 3.1 规范合并到我的答案中,请参阅我的编辑
  • "如果将块与其父级一起移动是不正确的,那么首先基于该父级定位它是不正确的。"这似乎是一个好点,但我仍然完全不相信这两种情况。不过,我不认为孩子因为position: fixed而处于父母的位置;我认为这是因为float: right;。我正在对规范进行另一次更彻底的研究,并已请 IE 团队的 Jonathan Sampson 进行查看,希望能提供供应商的观点。
  • "对于auto 的属性,唯一的选择是将其放置在视口的左上角" 事实上,这个例子显示了 Safari 是如何实现它的:jsfiddle.net/bbL8Lh4r/6Firefox,在另一方面,会将.nav 元素移动到left: -100px,但在.stickied 类被关闭后将其保留在那里。 Chrome 和 IE 一样始终将其保存在 .container 父级中。所以这里有一些明显的不一致。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-16
  • 2013-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-21
  • 2014-07-19
相关资源
最近更新 更多