The CSS declaration position: fixed
pins an HTML element to the browser's view-port. Such an element does not move when you scroll the page content away. But when you apply this CSS to an element that sits within a page-internal scroll-pane, the element would ignore its relative
parent and go to top-level, try it out below.
position
: absolute
fixed
position
property is set to absolute
.fixed
by radio-buttons above. We learn that position: fixed
is good just for the browser's view-port, not for view-ports of page-internal scroll-panes. So when we develop CSS concepts like "sticky header", we always have to change source-code when we want to apply them to elements being in other scroll-containers than the browser itself.
There are voices saying
You shouldn't use internal scroll-panes.
Users do not like to scroll, and it removes accessibility from your web-page.
Besides, it is not printable.One of the computer application archetypes is the master-details view. Both the master (left) and the details (right) need to be independently scrollable. Think of the JavaDoc page layout, where two left-side frames serve as iterative navigation for a right-side content display. Yes, HTML
frames
have been deprecated. But: why have they been there? Because they were useful! There will always be situations where you need an internal scroll-pane on a web-page.
There are even more reasons to replace position: fixed
than internal scroll-panes. It seems to be not well supported on mobile browsers.
So this article will be about a "fixed" menu button (see my previous Blog) that does not scroll with the page. And it will not use position: fixed
, and there will be no JavaScript. Its CSS source-code, with according HTML structure, will be reusable also for buttons that are nested into internal scroll-panes.
I would like to distinguish now between
DIV
.To get rid of position: fixed
, we need to replace the browser scroll-bar by an internal scroll-bar that should look exactly the same.
The idea is to configure the HTML
and BODY
tags to be 100% height (I wrote about this in a passed Blog), and then set the BODY
to position: relative
, so that subsequent elements can be positioned absolute
to it. This gives the same effect as position: fixed
.
Care must be taken that no position: static
content is a direct child of BODY
, except just one scroll-pane, which must be configured to height: 100%
and overflow: auto
(show scrollbar when necessary). The only static content allowed within BODY
are elements that have float: left
or float: right
, and thus do not shift the vertical start-coordinate down.
Here are the relevant CSS parts (without beautifications like restoring the browser default padding).
Restrict page to the browser's view-port size (avoiding any scrollbars):
html, body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
overflow: hidden; /* make any eager browser scrollbar disappear */
}
Define scroll-pane-containers and scroll-panes:
.scroll-pane-container {
position: relative;
}
.scroll-pane {
height: 100%;
width: 100%;
overflow: auto;
}
Here is the necessary HTML structure for this to work.
<body class="scroll-pane-container">
<div class="scroll-pane">
<!-- any static content goes here and only here-->
</div>
</body>
When having long content within that page, you will see a scroll-bar on the right that looks exactly like the browser's scroll-bar, and it also will act the same way. Thus we replaced the browser scroll-bar by an internal scroll-bar of a "ground" DIV
.
Here comes an example for the new way to define fixed
. We declare sticking to top-right corner by positioning absolutely, and placing the sticky element into the parent element where we want it to stick to.
.sticky-top-right {
position: absolute;
top: 0;
right: 1.3em; /* leave place for a scrollbar */
}
<body class="scroll-pane-container">
<input class="sticky-top-right" type="button" value="☰"/>
<div class="scroll-pane">
<div style="height: 60em;">
I am the top-level scrolled content.<br>
Please scroll down to check whether the button moves.
</div>
</div>
</body>
Mind that the button is declared where no static
content should be: between the scroll-pane-container
(BODY
) and the scroll-pane
. This does not matter because the button is not a static
content, its position is absolute
.
By the way, you could put the button also inside the scroll-pane
. It would make no difference as long as the scroll-pane
is not of position: relative
.
Here is a compound example that shows that the same CSS can drive a top-level sticky button AND a nested sticky button.
The CSS in head
contains just the necessary declarations. Irrelevant stylings have been done down in the HTML by inline style attributes.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Replace Fixed Position by Absolute</title>
<style type="text/css">
html, body {
height: 100%;
width: 100%;
padding: 0;
margin: 0;
overflow: hidden; /* make any eager browser scrollbar disappear */
}
.scroll-pane-container {
position: relative;
}
.scroll-pane {
height: 100%;
width: 100%;
overflow: auto;
}
.sticky-top-right {
position: absolute;
top: 0;
right: 1.3em; /* leave place for a scrollbar */
}
</style>
</head>
<body class="scroll-pane-container">
<input class="sticky-top-right" type="button" value="☰"/>
<div class="scroll-pane">
<div style="height: 60em;">
I am the top-level scrolled content.<br>
Please scroll down to check whether the button moves, and to see the nested scroll pane.
</div>
<div class="scroll-pane-container" style="height: 20em; margin-left: 10%; margin-right: 10%;">
<input class="sticky-top-right" type="button" value="☰"/>
<div class="scroll-pane">
<div style="height: 30em;">
I am the nested scrolled content.<br>
Please scroll down to check whether the button moves.
</div>
</div>
</div>
</div>
</body>
</html>
As you can see here, the definition of scroll-pane-container
as CSS class actually made sense. In this example the class is reused in the element-hierarchy of the nested scroll-pane
. Mind that all internal scroll-pane-container
instances will restrict their height in some way, so it does not make sense to put the height or width definition into the class.
You can see this concept applied to the pure-CSS slide-menu button of my previous Blog on my homepage.
ɔ⃝ Fritz Ritzberger, 2015-12-29