Combining two rods into one sticky header where the top bar changes height
I have two bars, an upper bar and a bread table. The top bar is higher when the two lanes are not combined. At some point, the bars are merged into one sticky header. The following snippet shows this concept.
$(() => {
const pivot = 500 - 145;
$(window).on('scroll', () => {
const scrollTop = $(window).scrollTop();
$('body').toggleClass('after-pivot', scrollTop > pivot);
});
});
.bar {
width: 100%;
display: block;
-webkit-transition: all .25s ease;
transition: all .25s ease;
}
.bar:before {
content: "";
display: inline-block;
vertical-align: middle;
height: 100%;
}
.bar.top {
height: 60px;
position: fixed;
top: 0;
left: 0;
margin-top: 85px;
background: rgba(1, 1, 1, 0.1);
}
.after-pivot .bar.top {
background: black;
margin-top: 0;
}
.bar.breadcrumbs {
background: red;
height: 40px;
}
.after-pivot .bar.breadcrumbs {
position: fixed;
top: 60px;
}
.bar>* {
vertical-align: middle;
}
.button {
height: 20px;
text-decoration: none;
color: white;
background: grey;
padding: 4px 10px;
}
.image {
height: 500px;
background: url("http://placehold.it/2000x500");
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
body {
height: 500vh;
padding: 0;
margin: 0;
}
p {
margin: 5px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="top bar">
<a href="#" class="button">I am a button</a>
</div>
<div class="image">
</div>
<div class="breadcrumbs bar">
<span>Home</span> - <span>My weird page</span>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque lacus augue, fermentum sed dui vel, imperdiet pretium risus. Nam quis diam eu tortor efficitur molestie. Nulla non nibh felis. Proin eget malesuada urna, sed bibendum ex. Mauris lacinia
ligula in ipsum ornare pulvinar. Pellentesque vitae volutpat nibh, in convallis velit. Aenean sed ex massa. Vestibulum ullamcorper purus et erat dignissim tristique. Pellentesque et viverra nisi.</p>
However, since the top panel has different heights when it is not combined with the bottom strip, the bottom panel "snaps" into place. If I were to change the pivot point to where the bottom pane is moving correctly, it will go over the top pane, which looks even worse.
$(() => {
const pivot = 500 - 60;
$(window).on('scroll', () => {
const scrollTop = $(window).scrollTop();
$('body').toggleClass('after-pivot', scrollTop > pivot);
});
});
.bar {
width: 100%;
display: block;
-webkit-transition: all .25s ease;
transition: all .25s ease;
}
.bar:before {
content: "";
display: inline-block;
vertical-align: middle;
height: 100%;
}
.bar.top {
height: 60px;
position: fixed;
top: 0;
left: 0;
margin-top: 85px;
background: rgba(1, 1, 1, 0.1);
}
.after-pivot .bar.top {
background: black;
margin-top: 0;
}
.bar.breadcrumbs {
background: red;
height: 40px;
}
.after-pivot .bar.breadcrumbs {
position: fixed;
top: 60px;
}
.bar>* {
vertical-align: middle;
}
.button {
height: 20px;
text-decoration: none;
color: white;
background: grey;
padding: 4px 10px;
}
.image {
height: 500px;
background: url("http://placehold.it/2000x500");
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
body {
height: 500vh;
padding: 0;
margin: 0;
}
p {
margin: 5px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="top bar">
<a href="#" class="button">I am a button</a>
</div>
<div class="image">
</div>
<div class="breadcrumbs bar">
<span>Home</span> - <span>My weird page</span>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque lacus augue, fermentum sed dui vel, imperdiet pretium risus. Nam quis diam eu tortor efficitur molestie. Nulla non nibh felis. Proin eget malesuada urna, sed bibendum ex. Mauris lacinia
ligula in ipsum ornare pulvinar. Pellentesque vitae volutpat nibh, in convallis velit. Aenean sed ex massa. Vestibulum ullamcorper purus et erat dignissim tristique. Pellentesque et viverra nisi.</p>
What I want to do is that when the bottom bar reaches the top bar, margin-top
the top bar gradually decreases until both bars are at the very top.
I can do this quite easily with javascript by specifying two anchor points and calculating margin-top
based on that. This would quickly get messy when looking at a responsive site because I need to move the styling to javascript.
function clamp(min, val, max) {
return Math.max(min, Math.min(val, max));
}
$(() => {
const pivotLower = 500 - 60;
const pivotHigher = 500 - 145;
$(window).on('scroll', () => {
const scrollTop = $(window).scrollTop();
$('.top.bar').css('margin-top', clamp(0, pivotLower - scrollTop, 85));
$('body').toggleClass('after-pivot', scrollTop > pivotLower);
});
});
.bar {
width: 100%;
display: block;
-webkit-transition: background .25s ease;
transition: background .25s ease;
}
.bar:before {
content: "";
display: inline-block;
vertical-align: middle;
height: 100%;
}
.bar.top {
height: 60px;
position: fixed;
top: 0;
left: 0;
margin-top: 85px;
background: rgba(1, 1, 1, 0.1);
}
.after-pivot .bar.top {
background: black;
margin-top: 0;
}
.bar.breadcrumbs {
background: red;
height: 40px;
}
.after-pivot .bar.breadcrumbs {
position: fixed;
top: 60px;
}
.bar>* {
vertical-align: middle;
}
.button {
height: 20px;
text-decoration: none;
color: white;
background: grey;
padding: 4px 10px;
}
.image {
height: 500px;
background: url("http://placehold.it/2000x500");
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
body {
height: 500vh;
padding: 0;
margin: 0;
}
p {
margin: 5px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="top bar">
<a href="#" class="button">I am a button</a>
</div>
<div class="image">
</div>
<div class="breadcrumbs bar">
<span>Home</span> - <span>My weird page</span>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque lacus augue, fermentum sed dui vel, imperdiet pretium risus. Nam quis diam eu tortor efficitur molestie. Nulla non nibh felis. Proin eget malesuada urna, sed bibendum ex. Mauris lacinia
ligula in ipsum ornare pulvinar. Pellentesque vitae volutpat nibh, in convallis velit. Aenean sed ex massa. Vestibulum ullamcorper purus et erat dignissim tristique. Pellentesque et viverra nisi.</p>
Instead, margin-top
I could use a real or pseudo element with height and change its height. We have min-height
and max-height
, which means that if we somehow force some element to move downwards and thus increase the height of this element, we can make this transition fluid. However, I cannot find any such interaction between the div that is position: fixed
and the element in normal flow.
Is it possible to use pure CSS and html structure as well as some javascript that sets one or two classes to gradually change the border between the top of the document and the top bar based on the scroll height?
Codepen to contact if you want.
source to share
How about positioning absolute
in CSS by adding a class .before-pivot
that makes it fixed
through JS in ready
, for now scrollTop < pivot
? Thereafter, for that short period, the time .top.bar
will have absolute positioning until it hits the top, at which point the class will be added .after-pivot
. You will still need a point secondPivot
to work, but in this case there is no need to gradually reduce the margin.
Basically, the classes .top.bar
go from .before-pivot
zero to .after-pivot
.
$(() => {
const pivot = 500 - 145;
const secondPivot = 500 - 60;
$(window).on('scroll', () => {
const scrollTop = $(window).scrollTop();
$('body').toggleClass('before-pivot', scrollTop < pivot);
$('body').toggleClass('after-pivot', scrollTop > secondPivot);
});
$(window).scroll();
});
.bar {
width: 100%;
display: block;
-webkit-transition: background .25s ease;
transition: background .25s ease;
}
.bar:before {
content: "";
display: inline-block;
vertical-align: middle;
height: 100%;
}
.bar.top {
height: 60px;
position: absolute;
top: 0;
left: 0;
margin-top: calc(440px);
background: rgba(1, 1, 1, 0.1);
}
.before-pivot .bar.top {
position: fixed;
margin-top: 85px;
}
.after-pivot .bar.top {
background: #000;
position: fixed;
margin-top: 0;
}
.bar.breadcrumbs {
background: red;
height: 40px;
}
.after-pivot .bar.breadcrumbs {
position: fixed;
top: 60px;
}
.bar > * {
vertical-align: middle;
}
.button {
height: 20px;
text-decoration: none;
color: white;
background: grey;
padding: 4px 10px;
}
.image {
height: 500px;
background: url("http://placehold.it/2000x500");
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
}
body {
height: 500vh;
padding: 0; margin: 0;
}
p {
margin: 5px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="top bar">
<a href="#" class="button">I am a button</a>
</div>
<div class="image">
</div>
<div class="breadcrumbs bar">
<span>Home</span> - <span>My weird page</span>
</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque lacus augue, fermentum sed dui vel, imperdiet pretium risus. Nam quis diam eu tortor efficitur molestie. Nulla non nibh felis. Proin eget malesuada urna, sed bibendum ex. Mauris lacinia ligula in ipsum ornare pulvinar. Pellentesque vitae volutpat nibh, in convallis velit. Aenean sed ex massa. Vestibulum ullamcorper purus et erat dignissim tristique. Pellentesque et viverra nisi.</p>
<p>Aliquam vel tempor urna. Ut consectetur, augue non consectetur auctor, quam est blandit dui, quis accumsan sem tortor id nunc. Cras mollis posuere lacus, ultricies placerat metus. Phasellus convallis erat ac nulla semper sollicitudin. Vestibulum lacinia arcu ut efficitur iaculis. Duis in erat vitae mi maximus hendrerit. Mauris ut felis id est pretium porta sit amet eget nunc. Proin posuere fringilla suscipit. Proin eu porttitor magna. Duis convallis rhoncus nisi, sit amet tincidunt turpis fermentum sit amet. Integer sit amet bibendum ligula. Vestibulum nunc felis, facilisis mollis ultrices sed, auctor ut nibh. Nullam suscipit nibh sed tellus commodo, in laoreet dui posuere. Aliquam pulvinar arcu sem, in bibendum augue dapibus at. Quisque mattis, lectus ut ornare dictum, odio urna pretium nibh, at consectetur ipsum magna nec turpis. Cras vel risus eros.</p>
<p>Nunc ante mi, placerat id odio vel, tristique faucibus tortor. Morbi et neque ac velit tincidunt condimentum. Nunc id neque condimentum, pulvinar enim tincidunt, cursus turpis. Sed tempus a ligula accumsan lobortis. Donec consequat dui mauris, vitae hendrerit enim hendrerit sed. Quisque nisl lorem, varius in eros eget, ullamcorper rhoncus sem. Mauris euismod diam eu imperdiet interdum.</p>
<p>Aenean a diam vestibulum, eleifend erat ac, porta magna. In mattis lorem ac libero suscipit luctus a quis tortor. Curabitur quam urna, porta vel faucibus bibendum, efficitur molestie orci. Vivamus ultricies urna dui, ullamcorper aliquam dui semper maximus. Praesent posuere enim massa, eu scelerisque enim tincidunt at. Pellentesque vitae rutrum metus. Nam ac blandit lorem. Sed posuere ornare dui, non imperdiet urna posuere a. Nullam consectetur mi sit amet ornare pulvinar. Nunc laoreet blandit dolor, non elementum purus porta ac. Vestibulum quis auctor quam. Maecenas mi est, ultrices in elit sit amet, congue sodales nunc. Suspendisse eget tristique nulla. Vestibulum vulputate lacus eu nibh porta, ut condimentum diam tristique.</p>
<p>Suspendisse convallis sem dolor, vel congue urna molestie quis. Praesent eros felis, aliquet quis mattis vel, tincidunt vel purus. Pellentesque sollicitudin lorem eu sapien porttitor posuere eget a lacus. In sagittis tincidunt sodales. Cras iaculis velit id elit facilisis lobortis. Maecenas id aliquet elit. Aliquam pretium quam at urna tempus dictum. Cras ornare tellus dolor, ac finibus turpis consectetur ac. Curabitur eget vulputate urna, sed finibus nisi. Quisque molestie, tortor sed sagittis pharetra, dui est suscipit odio, vel venenatis quam sapien vel felis.</p>
source to share