I am trying to put a small gradient on the bottom of a scrolling div. I've based my solution on the accepted answer to this SO thread. The gradient shows up fine, but when I scroll the content in the div, the bottom of the gradient moves. I need it to remain in place so that the content scrolls independently of the gradient. I've tried several combinations of position: fixed
, position: relative
, and position: relatve
to no avail. What have I missed?
Relevant markup:
<div class="resultListContainer">
<ul class="result">
<li><span class="resultPermitNumber resultElement">B123456789</span></li>
<li><span class="resultPermitType resultElement">FINAL</span></li>
<li><span class="resultDisplayAddress resultElement">41975 LOUDOUN CENTER PL SE, LEESBURG, VA 20175</span></li>
</ul>
<!-- Lots more of the ul. -->
</div>
Relevant CSS:
.resultListContainer {
border: 1px solid #000;
height: 400px;
width: 40em;
overflow-y: scroll;
font-size: 1em;
position: relative;
}
.resultListContainer::before {
background-image: linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, rgba( 255, 255, 255, 1 ) 100% );
background-image: -moz-linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, rgba( 255, 255, 255, 1 ) 100% );
background-image: -ms-linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, rgba( 255, 255, 255, 1 ) 100% );
background-image: -o-linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, rgba( 255, 255, 255, 1 ) 100% );
background-image: -webkit-linear-gradient( top, rgba( 255, 255, 255, 0 ) 95%, rgba( 255, 255, 255, 1 ) 100% );
content: "\00a0";
height: 100%;
position: absolute;
width: 100%;
}
.result {
margin-bottom: 0;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 5px;
list-style-type: none;
}
The result:
You need to wrap your container in another div that is positioned as relative.
Also, overlay will block your scroll bar, so instead of width: 100%
I used: left:0; right: 16px;
- now scroll is clickable.
Try my fiddle:
https://fiddle.jshell.net/8c6k4k6d/1/
Because your element is positioned absolute
, it's position is absolute to the parent element so when you scroll it scrolls with your content. What you want is your ul
to scroll. I have quickly rewritten yours, but below I've got a simplified and cleaned up version:
.resultListContainer {
border: 1px solid #000;
height: 400px;
width: 40em;
font-size: 1em;
position: relative;
}
.resultListContainer::before {
background-image: linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, rgba( 255, 255, 255, 1 ) 100% );
background-image: -moz-linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, rgba( 255, 255, 255, 1 ) 100% );
background-image: -ms-linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, rgba( 255, 255, 255, 1 ) 100% );
background-image: -o-linear-gradient( top, rgba( 255, 255, 255, 0 ) 0%, rgba( 255, 255, 255, 1 ) 100% );
background-image: -webkit-linear-gradient( top, rgba( 255, 255, 255, 0 ) 95%, rgba( 255, 255, 255, 1 ) 100% );
content: "\00a0";
height: 100%;
position: absolute;
width: 100%;
z-index: 2;
pointer-events: none;
}
.result {
position: absolute;
left: 0;
top: 0;
margin: 0;
box-sizing: border-box;
z-index: 1;
width: 100%;
height: 100%;
margin-bottom: 0;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 5px;
list-style-type: none;
overflow-y: scroll;
}
.result li {
height: 100px;
background: red;
}
<div class="resultListContainer">
<ul class="result">
<li><span class="resultPermitNumber resultElement">B123456789</span></li>
<li><span class="resultPermitType resultElement">FINAL</span></li>
<li><span class="resultDisplayAddress resultElement">41975 LOUDOUN CENTER PL SE, LEESBURG, VA 20175</span></li>
<li><span class="resultPermitNumber resultElement">B123456789</span></li>
<li><span class="resultPermitType resultElement">FINAL</span></li>
<li><span class="resultDisplayAddress resultElement">41975 LOUDOUN CENTER PL SE, LEESBURG, VA 20175</span></li>
<li><span class="resultPermitNumber resultElement">B123456789</span></li>
<li><span class="resultPermitType resultElement">FINAL</span></li>
<li><span class="resultDisplayAddress resultElement">41975 LOUDOUN CENTER PL SE, LEESBURG, VA 20175</span></li>
</ul>
<!-- Lots more of the ul. -->
</div>
Basically there are two things that are important: your outer box cannot be scrollable, you inner box can. All the fixed elements need to be outside your inner box (which is your ul
in this case). Secondly, your :before
cannot be 100%
high, as it will absorb your mouse events, preventing scrolling. For all browsers except IE you can solve this by using pointer-events: none
, but otherwise the safest way is to make your gradient a fixed height and your :before
element the height of the gradient you want, resulting in a (in this case) 20px
area that would not take your mouse events at the bottom.
html, body { height: 100%; } body { padding: 0; margin: 0; }
div {
width: 400px;
height: 400px;
max-height: 100%;
position: relative;
}
div:before, div ul {
position: absolute;
left: 0;
bottom: 0;
width: 100%;
}
div:before {
background: linear-gradient(0deg, rgba(255,255,255,1), rgba(255,255,255,0));
background-size: 100% 100%;
height: 20px;
z-index: 2;
/* IE does not support pointer events, so making this small in height is important
as your scroll events will not be passed to the ul if it is covered by your :before */
pointer-events: none;
content: '';
display: block;
}
div ul {
margin: 0;
padding: 0;
height: 100%;
overflow-y: scroll;
z-index: 1;
}
div li {
width: 100%;
height: 100px;
background: #ececec;
}
div li:nth-child(2n){
background: #cecece;
}
<div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
</ul>
</div>
replace
.resultListContainer::before
with
.resultListContainer .result:last-of-type::before