如何使用CSS对一个固定高度可变的标题和可滚动内容框进行定位?

67

我希望制作一个固定头部和可滚动内容区域的网页。当头部高度已知时,这很简单,但是当头部是流体时,我很难找到解决方案。

我想要的布局是:

--------------
head
--------------
content
--------------

“head”是其内容所需高度,“content”没有最小高度,但在达到视口底部的最大高度之前将成为可滚动的。

现在纯CSS是否可以实现这一点?我针对IE8+。

为了澄清我的意思,这里是如果我知道标题高度我会怎么做

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">

body {
    margin: 0;
}

#head {
    background: yellow;
    height: 20px; /* I can't rely on knowing this. */
}

#content {
    background: red;
    position: absolute;
    top: 20px; /* here also */
    bottom: 0;
    width: 100%;
    overflow: auto;
}

        </style>
    </head>
    <body>
        <div id="head">some variable height content</div>
        <div id="content">
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
        </div>
    </body>
</html>

1
你想要滚动条在内容旁边还是整个页面的高度上? - Eric
1
如果标题是“固定的”,那么它的高度以何种方式是流动的? - Eric
1
滚动条最好与内容并排。当我说固定时,我的意思是位置固定,即它不随主要内容滚动。 - David Roe
@David:添加了一个 jsFiddle 链接,这样大家就可以看到了。你在这里寻找什么样的兼容性? - Eric
谢谢。我正在针对IE8+进行开发。 - David Roe
显示剩余2条评论
8个回答

32

如果你所说的“fixed”是position:fixed,我认为这在纯CSS中是不可能的,因为position:fixed会将元素从文档流中移除。

但是,使用一两行JavaScript代码就可以实现你想要的效果。例如(未经测试,仅供示例,需要调整语法才能真正工作):

var height = document.getElementById("head").offsetHeight;
document.getElementById("content").style.marginTop = height + 'px';

这样做可以获取固定的 <div> 的渲染高度,并相应地设置内容 <div> 的外边距。您还需要在固定的 <div> 上明确设置背景颜色,否则滚动时内容将似乎渗透到固定的 <div> 中。


9
调整页面大小后不要忘记重新计算。 - Eric
我可以设计页眉,使其在宽度更改时不会重新流动,因此我不必担心调整大小。 - David Roe
如果您可以使用JavaScript,那么这是一个很好的答案,因为它消除了在freezepane上指定初始高度或在容器上添加边距的需要。我只是将其放入pageLoad()中,并添加了一个页面调整大小的事件监听器。 - Ravendarksky
要么添加页面尺寸变化的事件监听器,要么使用setInterval函数确保其正确地定位。 - ferr
1
我也曾遇到这个问题,我将与上述代码非常相似的代码放入一个函数中,并通过<body onresize=>调用它。这似乎起作用了。在我的情况下,底部的div已经被定义为position:relative,所以我设置了content.style.top而不是marginTop,这可能有利有弊,但是基本思路是相同的。 - Jay
这确实是一个很棒的答案,附上了很好的示例代码。如果能提及并提供样例,将这两行代码附加到一个事件侦听器上,在头部高度改变时触发,那就更好了。这可行吗? - Bernd Wechner

27

这里提供了一个解决方案,但它是作弊的。基本上,你需要有一个重复的页眉元素,将内容推到固定位置下面:

<div class="outer">
    <div class="header">Header content goes here</div>
    <div class="header-push">Header content goes here</div>
    <div class="content">
        ...
    </div>
</div>

1
这是一个不错的(虽然有点hacky)解决方案,但我简化了我的要求,以便更容易回答问题。实际上,我想要两个独立的列,所以不能使用全页滚动来实现。也许JavaScript是唯一的方法。我希望一些新的表格布局东西能起到作用,但我还没有能够使它工作。 - David Roe
2
我已经尝试了几个小时来想出一个纯CSS的解决方案,得出结论,确实不可能。这就是'96年发明的标准的奇妙之处。 - Dan Dascalescu
1
这很棒。如果您不想让 HTML 变得混乱,您总可以使用 JavaScript 进行复制。 - Oleh Prypin
2
@WoodrowBarlow 这并不会使网站无法使用。标题栏只会滚动,而不是固定在原处。 - Oleh Prypin
1
不要忘记可访问性:如果您不能仅在副本上设置 visibility: hidden,请至少使用 aria-hidden="true" 来防止屏幕阅读器认为实际上存在两个文本实例的可能性。 - Tomty
显示剩余3条评论

11

我结合了接受的答案和 Eric 的答案。使用空的 div 元素将内容推到“head”元素下方。当 window.onresize 事件触发时,使用 jQuery 设置此 div 的宽度:

我同时采用了接受答案和Eric的答案。使用一个空的div将"head"下面的内容往下挤。当window.onresize被触发时,使用jQuery设置这个div的宽度:

function resizeHeader() {
    $(".header-push").height($(".header").height());
}
$(document).ready(resizeHeader);
$(window).resize(resizeHeader);

点击这个 jsFiddle 链接获取更多信息。


2
奇怪的是,我最喜欢这种方法。它不需要重复的标题(但是需要一个空的div,这并不影响我),而且它不需要内容了解标题的任何信息。这也要短得多。 - Boom
2
在窗口大小调整期间添加一定的延迟是很有帮助的,以避免触发太多事件 - 我使用250毫秒,看起来足够好了:https://dev59.com/f3E85IYBdhLWcg3wShaf - But those new buttons though..
我花了太多时间才弄清楚纯CSS解决方案是不可能的。这绝对可以解决问题,但那些禁用JS的人怎么办呢(尽管我可以想象他们的浏览体验已经很糟糕了)? - edwardmp
CSS非常复杂。必须存在干净的、仅基于CSS的解决方案来回答这样的问题。真正聪明和有经验的CSS专家应该坐下来重新设计整个东西。应该可以做到所有简单的事情,比如创建一个固定高度的div,以及适合其内容的div,计算元素与另一个元素之间的真实像素距离等等。如果指定了具有明确含义的内容,例如“min-height: 30rem”,则显示的高度不应违反此规则,例如1rem,除非抛出错误。 - David Spector
1
我们已经有了flexbox,它很可能可以轻松解决这个问题。请参见https://css-tricks.com/snippets/css/a-guide-to-flexbox/。 - David Spector

6
最简单的方法是将 position: fixed; 替换为 position: sticky;
header {
  position: sticky;
  top:0;
  background-color: red;
  color: #fff;
}

main {
  background-color: green;
  color: #fff;
  min-height: 150vh;
}

演示:https://jsfiddle.net/4zndve6p/


最佳答案:一行且无JS ;-) - hugsbrugs

3
这段JavaScript会获取固定页眉的高度变量,并将内容的顶部边距设置为流动到其下方。只需调用页面加载即可。
<script type="text/javascript">
    function AdjustHeight() {
        var height = document.getElementById("fixedheader").offsetHeight;
        document.getElementById("content").style.marginTop = height + 'px';
    }    
</script>

2
这是Shauna在上面提出的解决方案的完整代码示例,供那些懒惰/困惑/无法使其正常工作的人使用。
<html>
<head>

<style>
#FreezePaneHeader {
    position: fixed; top:0; left: 0; width: 100%;background-color: gray;
}

#FreezePaneBody {
    margin-top: 30px;
} 
</style>

 <script type="text/javascript">        
        function resizeFreezePane()
        {
            var height = document.getElementById("FreezePaneHeader").offsetHeight;
            document.getElementById("FreezePaneBody").style.marginTop = height + 'px';
        }

        //Resizes content to allow static header with dynamic height on postbacks
        function pageLoad() {
            resizeFreezePane();
        }

        var addEvent = function (elem, type, eventHandle) {
            if (elem == null || typeof (elem) == 'undefined') return;
            if (elem.addEventListener) {
                elem.addEventListener(type, eventHandle, false);
            } else if (elem.attachEvent) {
                elem.attachEvent("on" + type, eventHandle);
            } else {
                elem["on" + type] = eventHandle;
            }
        };

        //also when page is resized.
        addEvent(window, "resize", resizeFreezePane);

    function GenerateLorem(ele){
        var x = document.getElementById(ele);
        x.innerHTML = x.innerHTML + "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur pretium euismod leoquis convallis. In ornare suscipit massa eu commodo. Pellentesque vel nibh volutpat, commodo libero et, 

porta tellus. Duis eu fringilla arcu. Etiam imperdiet lectus diam, dignissim viverra dui hendrerit id. Fusce condimentum bibendum tincidunt. Aenean fringilla felis elit, et dapibus ante tempus at. Phasellus quis dolor odio.</p>";
        resizeFreezePane();
        }
    </script>
</head>

<body>
<div id="FreezePaneHeader">Frozen Page Header</div>
<div id="FreezePaneBody">
<button id="ButtonAddText" onclick="GenerateLorem('FreezePaneHeader'); return false;">Add more header text</button>
<button id="ButtonAddText" onclick="GenerateLorem('FreezePaneBody'); return false;">Add more body text</button>
<p id="PageContents"></p>
</div>
</body>

</html>

0

我使用getComputedStyle解决了这个问题。 这种方法允许您获取所有CSS样式。并基于它们,更改另一个元素的样式。 以下是使用本机JS的所有代码:

<style>
#head {
    position: fixed;
    width: 100%;
    top: 0;
    left: 0;
    background: rgb(170, 170, 170);
    /* height: 50px; for example no fixed height*/
    z-index: 2;
}

#content {
    position: relative;
    width: 100%;
    background: rgb(180, 37, 37);
  }

<body>
<div id="head">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Enim, quisquam.</div>
<div id="content">
    Some content text<br />

</div>
<script>
    const header = document.querySelector('#head'),
        content = document.querySelector('#content');
    //Now get all possible CSS styles from #head using getComputedStyle
    const marginTopOffset = getComputedStyle(header);
//Resize event is for autosearch width of a browser window
window.addEventListener('resize', ()=> {
    function marginOffset() {
        content.style.marginTop = marginTopOffset.height;
        // you can add changes to another CSS style 
        // content.style.backgroundColor = marginTopOffset.backgroundColor;
    };
    marginOffset();
    // You can see how changes margin-top in console on the fly
    console.log(content);
});
</script>
</body>

0

这是我的简单且有效的解决方案,只需四行代码。

描述

  • getBoundingClientRect 计算元素的有效属性,包括边距。我使用它来获取有效的底部值。
  • 将此值分配给内容元素的 marginTop 属性。
  • 需要一个 onResize 的事件监听器来响应窗口大小的变化,这可能会影响标题高度。

查看演示

我的 fiddle(调整宽度以查看效果):https://jsfiddle.net/z1uac3Lw/

function adjustHeaderHeight() {
   let header = document.getElementById('head');
   let rect = header.getBoundingClientRect();
   document.getElementById('content').style.marginTop = rect.bottom + 'px';
}

window.addEventListener('resize', function() {
   adjustHeaderHeight();
});
body {
    margin: 0;
}

#head {
    background: yellow;
//    height: 20px; /* I can't rely on knowing this. */
}

#content {
    background: red;
    position: absolute;
    top: 0px;
    bottom: 0;
    width: 100%;
    overflow: auto;
}
<!DOCTYPE html>
<html>
    <head>
    </head>
    <body onLoad='adjustHeaderHeight();' >
        <div id="head">some variable height content ... with a very long long long long long long long long long long long long long long long long long long long long long line to show the effect</div>
        <div id="content">
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
            scrollable content<br/>
        </div>
    </body>
</html>

内嵌JavaScript / CSS的代码

<!DOCTYPE html>
<html>
    <head>
        <style type="text/css">
body {
    margin: 0;
}

#head {
   background: yellow;
//    height: 20px; /* I can't rely on knowing this. */
}

#content {
   background: red;
   position: absolute;
   top: 0px;
   bottom: 0;
   width: 100%;
   overflow: auto;
}

        </style>
        <script type="text/javascript" type="text/javascript">        
    
function adjustHeaderHeight() {
   let header = document.getElementById('head');
   let rect = header.getBoundingClientRect();
   document.getElementById('content').style.marginTop = rect.bottom + 'px';
}

window.addEventListener('resize', function() {
   adjustHeaderHeight();
});

      </script>        
        
   </head>
   <body onLoad='adjustHeaderHeight();' >
      <div id="head">some variable height content ... with a very long long long long long long long long long long long long long long long long long long long long long line to show the effect</div>
      <div id="content">
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
         scrollable content<br/>
      </div>
   </body>
</html>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接