I'm looking for a CSS-only solution, to create a fixed header on a div, where the scrollbar for the content starts next to (and not below of) the header. To get an idea on how it should look, have a look at this fiddle:
http://jsfiddle.net/V4uL6/
Here, I tried to take the following approach:
HTML
<div class="outer">
<div class="top">Title</div>
<div class="body">
<div class="content">
.... Text Content here ...
</div>
</div>
</div>
CSS
.outer {
position: absolute;
top: 20px;
left: 20px;
width: 200px;
height: 300px;
}
.top {
z-index: 2;
position: absolute;
height: 30px;
width: 100%;
}
.body {
z-index: 3;
position: relative;
width: 100%;
height: 100%;
overflow: auto;
}
.content {
margin-top: 30px;
}
The problem with this approach is, that the content lies on top of the header (you'll see it as soon as you start scrolling). It however feels like, it is really close to a solution. But since I haven't found anything on the web, I fear that this is only doable with JavaScript. So is that true or is there a CSS-only solution for this problem?
Set z-index on body to 1, or any number lower than the z-index on top.
EDIT: You still have the issue of the scrollbar being hidden, but since you said you wanted the scrollbar next to, and not under the header, you can change that by adjusting the width on the content classes.
I found a solution! The trick is to apply z-index: -1 to the content element and remove the z-index from all other elements:
.outer {
position: absolute;
top: 20px;
left: 20px;
width: 200px;
height: 300px;
}
.top {
position: absolute;
height: 30px;
width: 100%;
}
.body {
position: relative;
width: 100%;
height: 100%;
overflow: auto;
}
.content {
position: relative;
z-index: -1;
margin-top: 30px;
}
Here is the updated fiddle: http://jsfiddle.net/V4uL6/3/
Related
I have a very odd use case I'm trying to implement. I want to make an HTML element that will shrink as you scroll down (top edge will behave like position: sticky, and bottom will behave like position: absolute). I'm planning on using this element as a background for a header where I'll have some SVGs to form a landscape that as you scroll down the elements that are further in the background will be obscured by the closer elements (achieved by setting their positions based on percentage values). I can't see any way in CSS to set different positioning methods for different edges of an element.
Any advice on how to achieve this dynamic resizing effect? I'd prefer to use pure HTML and CSS if possible, but if JS is necessary to solve my problem then that's perfectly fine.
Here's my code so far:
HTML:
<header>
<nav> ... </nav>
<div id="hero">
<div class="bg">
<div class="item_1"></div>
<div class="item_2"></div>
<div class="item_3"></div>
</div>
<div id="hero-content">
...
</div>
</div>
</header>
Here, <div class="bg"> is the element I want to apply this behavior to.
Current CSS:
header {
}
#hero {
position: relative;
height: 90vh;
}
#hero .bg {
position: absolute;
bottom: 0;
height: 100%;
width: 100%;
z-index: -999;
}
#hero .bg .item-1 {
width: 100%;
height: 80%;
position: absolute;
bottom: 0;
}
#hero .bg .item-2 {
width: 100%;
height: 350px;
position: absolute;
bottom: 0;
}
#hero .bg .item-3 {
width: 150px;
height: 200px;
position: absolute;
bottom: 220px;
right: 5%;
}
#hero-content {
display: flex;
flex-flow: column nowrap;
justify-content: flex-end;
align-items: flex-start;
position: absolute;
bottom: 0;
left: 0;
margin: 1rem;
width: 70%;
}
This is so strange that I can't even replicate the error in jsfiddle despite copy-pasting the code.
Basically I have it like this:
<div class="container">
<div class="absolute-background" />
<div class="where-is-this" />
</div>
With this CSS:
.container {
background: transparent;
position: relative;
overflow: hidden;
height: 100%;
width: 100%;
}
.absolute-background {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
background: blue;
z-index: 0;
}
.where-is-this {
height: 100px;
width: 100%;
z-index: 1000000;
background: red;
}
This should display a red box at the top of the screen, as it does in this fiddle: https://jsfiddle.net/Lmj6d625/
However, in my actual page (on the same browser) the blue covers EVERYTHING. I can even add new divs below with text and they are completely hidden.
Screenshot:
Where is my div?!
Anyone have any suggestions how to troubleshoot this?
The z-index property only works on elements with a position value other than static (e.g. position: absolute;, position: relative;, or position: fixed).
There is also position: sticky; that is supported in Firefox, is prefixed in Safari, worked for a time in older versions of Chrome under a custom flag, and is under consideration by Microsoft to add to their Edge browser.
Thanks to Evert for this answer
1.) DIV Tags can't be self closing
2.) You need a height for the body tag, otherwise it will have 0 height, and that will also apply to container and .absolute-background, making them invisible.
3.) You need position: absolute or position: relative for the z-index of the red DIV to become effective (fixed would also work, but then it wouldn't scroll with the rest of the page)
html,
body {
height: 100%;
margin: 0;
}
.container {
background: transparent;
position: relative;
overflow: hidden;
height: 100%;
width: 100%;
}
.absolute-background {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
background: blue;
z-index: 0;
}
.where-is-this {
position: absolute;
height: 100px;
width: 100%;
z-index: 1000000;
background: red;
}
<div class="container">
<div class="absolute-background"></div>
<div class="where-is-this"></div>
</div>
I have the following setup which results in a horizontal scrolling UI with different "pages". Each page is the full width of the device/browser. Everything seems okay, except that #other is not at the top of the screen. It looks more like this (if you are mid-scroll between the two pages):
Using Chrome's dev tools I have confirmed that the height of the element is correct. It's actually behind the footer and about 400 pixels "lower" than the left div.
HTML
<div id="menu-header"></div>
<div id="pageContainerContainer">
<div id="pageContainer">
<div id="home" class="page">Stuff here</div>
<div id="other" class="page">Other things</div>
</div>
</div>
<div id="menu-footer"></div>
CSS
#menu-header, #menu-footer {
position: absolute;
left:0;right:0;
height: 80px;
z-index:50;
}
#menu-header { top: 0; }
#menu-footer { bottom: 0; }
#pageContainerContainer {
position: absolute;
top: 80px;
bottom: 80px;
width: 100vw;
overflow-x: auto;
overflow-y: hidden;
}
#pageContainer {
height: 100%;
width: 200vw;
overflow-x: auto;
overflow-y: hidden;
}
.page {
display: inline-block;
box-sizing: border-box;
width: 100vw;
height: 100%;
}
Adding position: relative to the .page class fixed the issue.
The last two days I've been reading most questions here and a lot more about 'fill remaining width' and 'escaping overflow: hidden', but I can't get my problem solved. At the moment, I seriously doubt if it is possible at all.
I have a scrolling box with full body width. On top of that I have a absolute positioned header that I need to make the exact same width as the scrollbox. My intention is to make the header 0px or (if needed) 1px in height and let the content overflow.
Here is a fiddle.
The scrollbox has a scrollbar (always visible), the header obviously not. To compensate for that, I float a fake scrollbar to the right inside the header container, and left of that a <div> filling the remaining width (being exactly the innerwidth of the scrollbox).
HTML
//THE SCROLLBOX
<div id="scrollbox">
<div id="center2">
content<br>content<br>...
</div>
</div>
// THE HEADER
<div id="header_box">
<!--- FAKE SCROLLBAR -->
<div id="scroller">
<div></div>
</div>
// REMAINING WIDTH
<div id="container">
<div id="FIRST">
<div id="FIRST_banner"></div>
</div>
</div>
<div id="SECOND">
<div id="SECOND_banner"></div>
</div>
</div>
</div>
CSS
#header_box {
background: yellow;
position: absolute;
left: 0;
top: 0;
right: 0;
height: 25px;
width: 100%;
overflow: visible;
}
#scroller {
float: right;
overflow-x: hidden;
overflow-y: scroll;
height: 50px;
width: auto;
/* visibility: hidden; */
}
#scroller>div {
width: 0px;
height: 101%;
}
#container {
display: inline;
width: auto;
height: 50px;
overflow: visible;
}
#FIRST {
position: relative;
overflow: hidden;
height: 25px;
background: pink;
}
#FIRST_banner {
position: absolute;
top: 0;
left: 50%;
height: 220px;
width: 30px;
background: crimson;
}
#SECOND {
background: darkcyan;
position: relative;
height: 5px;
}
#SECOND_banner {
position: absolute;
top: 0;
left: 50%;
height: 220px;
width: 30px;
background: blue;
}
The problem lies in the div (#FIRST) with remaining width. From all the solutions I've read only the one with
position: relative;
overflow: hidden;
works for me. It gives the exact width, lining up the center of the header and the scrollbox nicely. But I can't break out of the overflow: hidden, so it cuts off the content.
So my second thought was: wrap #FIRST in a #container and let the child determine the width of the parent. After that, I can put another div (#SECOND) inside the container with the width of the parent. It works partially. The #container has the width intended, and the #SECOND div overflows nicely but takes on the width of #header_box, as no width is set on the parent itself.
So, my questions:
Can I somehow break out of the overflow: hidden of the FIRST div? (In that case the container and second div can be removed).
Is there a way to let the SECOND div obey the width of it's parent.
Some totally different solution.
Sadly there is a catch to this all:
css only
no javascript
no flexbox
Thanks voor any toughts.
In the end, it was the good old <table> that saved the day, much simpler than I tought. There still is a fake scrollbar, but the absolute header now aligns perfect with the contents of the scrollable div behind it, and it remains fluid.
See fiddle here
HTML:
<!--- HEADER -->
<div id="THIRD">
<div id="THIRD_A">
<div id="THIRD_B"></div>
<div id="THIRD_C"></div>
<div id="THIRD_D"></div>
</div>
</div>
<!--- FAKE SCROLLBAR -->
<div id="scroller">
<div></div>
</div>
</div>
CSS:
/* The container for the header */
#header_box{
position: absolute;
left: 0;
top: 0;
right: 0;
height: 0px;
width: 100%;
overflow: visible;
display: table;
}
/* Takes on the width of its child: the fake scrollbar */
#scroller {
display: table-cell;
float: right;
overflow-x: hidden;
overflow-y: scroll;
height: 0px;
width: auto;
}
/* This triggers a scrollbar to be shown */
#scroller>div {
width: 0px;
height: 101%;
}
/* The 'remaining width' container (= screenwidth - scrollbar, equals innerwidth of scrollbox) */
#THIRD{
display: table-cell;
width: 100%;
height: 0px;
}
/* Needed to give the children a 'width' reference */
#THIRD_A{
position: relative;
width: 100%;
height: 0px;
}
/* The actual header items */
#THIRD_B {
position: absolute;
top: 0;
left: 50%;
width: 25px;
height: 220px;
background: black;
}
#THIRD_C {
position: absolute;
top: 0;
left: 10%;
width: 125px;
height: 120px;
background: black;
}
#THIRD_D {
position: absolute;
top: 0;
right: 0%;
width: 25px;
height: 220px;
background: black;
}
NOTE:
On most handheld browser, this is 1px off. It seems webkit based browsers display a tablecell of 0px width as 1px width (see this question). The solution is to wrap the table in another div with css:
position absolute;
left: 0;
right: -1px
and setting #scroller>div to a width of 1px.
NOTE 2:
This is also a solution for a fixed div inside a scrollable div. See this fiddle
Anyone know how I can prevent an equal height to dynamic width div from overlapping the content below. The div needs to expand to contain content in narrow viewports.
#caeth suggested moving the div below to be inside the div above, which works: http://jsfiddle.net/534k9e2n/5/ but I'm looking for a solution that doesn't require this.
Here's the code:
<div class="holder">
<div class="shape"></div>
<div class="shape_outer">
<div class="shape_inner">Content...</div>
</div>
</div>
<div class="shape_below"></div>
...
.holder {
display: inline-block;
position: relative;
width: 50%;
}
.shape {
margin-top: 100%;
}
.shape_outer {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.shape_inner {
background: #ddd;
min-height: 100%;
width: 100%;
}
.shape_below {
background: #111;
width: 200px;
height: 200px;
}
and a JSFiddle: http://jsfiddle.net/534k9e2n/4/
Thanks B.
Try this:
.shape {
margin:20px;
}
What you are doing is create a hidden field around the div.I think you can delete the shape-outer.