Skip to content

Commit 93bd78d

Browse files
committed
Header interaction
1 parent 4a416dd commit 93bd78d

File tree

2 files changed

+97
-20
lines changed

2 files changed

+97
-20
lines changed

src/App.svelte

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script>
2-
import { onMount } from 'svelte'
2+
import { onMount, tick } from 'svelte'
33
import { Router, Route } from 'svelte-routing'
44
55
// Components
@@ -21,36 +21,52 @@
2121
*/
2222
let hasScrolled = false
2323
let header
24+
let headerEl
25+
let main
26+
let mainY
2427
2528
const onScroll = ev => {
2629
const y = window.scrollY
2730
if (!hasScrolled && y > 50) {
2831
hasScrolled = true
2932
document.documentElement.style.setProperty('--color-active-bg', 'var(--color-light)')
30-
3133
} else if (hasScrolled && y < 50) {
3234
hasScrolled = false
3335
document.documentElement.style.setProperty('--color-active-bg', 'var(--color-salmon)')
3436
}
3537
36-
// if (hasScrolled && y > 300) {
37-
// header.classList.add('scrolled')
38-
// } else {
39-
// header.classList.remove('scrolled')
40-
// }
38+
if (hasScrolled && mainY && y > mainY) {
39+
header.moveForward()
40+
} else {
41+
header.moveBack()
42+
}
43+
}
44+
45+
const remToPx = (rem) => {
46+
return rem * parseFloat(getComputedStyle(document.documentElement).fontSize)
4147
}
4248
43-
onMount(() => {
49+
const setHeaderTransition = () => {
50+
const scrollOffset = window.scrollY
51+
const mainPos = main.getBoundingClientRect().top
52+
const headerHeight = remToPx(5.3)
53+
54+
mainY = scrollOffset + mainPos - headerHeight
55+
}
4456
45-
window.addEventListener('scroll', onScroll)
57+
onMount(async () => {
58+
window.addEventListener('scroll', onScroll, { passive: true })
59+
window.addEventListener('resize', setHeaderTransition, { passive: true })
60+
await tick()
61+
setHeaderTransition()
4662
})
4763
</script>
4864

4965
<div class="root" class:scrolled={hasScrolled}>
5066
<Router url={url}>
51-
<AppHeader bind:header={header} />
67+
<AppHeader bind:header={headerEl} bind:this={header}/>
5268

53-
<main>
69+
<main bind:this={main}>
5470
<Route path="about" component={About}/>
5571
<Route path="contribute" component={Contribute}/>
5672
<Route path="license" component={License}/>

src/components/AppHeader.svelte

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,34 @@
44
import Logo from './Logo.svelte'
55
import AppNav from './AppNav.svelte'
66
7-
export let header
7+
export let header = null
88
9+
let height
910
let shadow
11+
let fade
12+
13+
let open = false
14+
let top = false
15+
16+
export const moveForward = () => {
17+
if (!top) top = true
18+
}
19+
export const moveBack = () => {
20+
if (top) top = false
21+
}
1022
1123
const onResize = () => {
12-
shadow.style.height = header.offsetHeight + 'px'
24+
height = header.offsetHeight + 'px'
25+
shadow.style.height = height
26+
fade.style.height = height
27+
}
28+
const onMouseenter = () => {
29+
open = true
30+
if (top) header.style.height = height
31+
}
32+
const onMouseleave = () => {
33+
open = false
34+
if (top) header.style = null
1335
}
1436
1537
onMount(() => {
@@ -18,11 +40,19 @@
1840
})
1941
</script>
2042

21-
<span class="header-shadow" bind:this={shadow}/>
43+
<span
44+
bind:this={shadow}
45+
class="header-shadow"
46+
aria-hidden="true"
47+
/>
2248

2349
<header
2450
class="header"
2551
bind:this={header}
52+
class:top={top}
53+
class:open={top && open}
54+
on:mouseenter={onMouseenter}
55+
on:mouseleave={onMouseleave}
2656
>
2757
<div class="header-logo">
2858
<Link to="/" title="Go to homepage"><Logo/></Link>
@@ -38,6 +68,7 @@
3868
<div class="header-nav">
3969
<AppNav/>
4070
</div>
71+
<span class="header-fade" aria-hidden="true" bind:this={fade} />
4172
</header>
4273

4374
<style lang="scss">
@@ -52,11 +83,15 @@
5283
width: 100vw;
5384
height: auto;
5485
padding: 1rem;
86+
background-color: var(--color-active-bg);
5587
border-bottom: solid 1px transparent;
88+
transition: ease 0.15s background-color;
5689
5790
&-logo {
5891
order: 1;
5992
grid-column: span 4;
93+
position: relative;
94+
z-index: 2;
6095
6196
@include from(medium) {
6297
grid-column: span 3;
@@ -102,16 +137,42 @@
102137
grid-column: 13 / span 6;
103138
}
104139
}
140+
141+
&-fade {
142+
content: '';
143+
position: absolute;
144+
pointer-events: none;
145+
top: 0;
146+
left: 0;
147+
width: 100%;
148+
height: 5.3rem;
149+
background: linear-gradient(to bottom, #fff0, #ffff 5rem);
150+
opacity: 0;
151+
transition: ease 0.3s opacity;
152+
}
153+
154+
&.top {
155+
z-index: 3;
156+
height: 5.3rem;
157+
overflow: hidden;
158+
border-color: var(--color-dark);
159+
transition: ease 0.15s background-color,
160+
ease 0.3s height;
161+
162+
.header-fade {
163+
opacity: 1;
164+
}
165+
166+
&.open {
167+
.header-fade {
168+
opacity: 0;
169+
}
170+
}
171+
}
105172
}
106173
107174
.header-shadow {
108175
display: block;
109176
width: 100%;
110177
}
111-
112-
:global(.header.scrolled) {
113-
border-color: var(--color-dark);
114-
background-color: var(--color-active-bg);
115-
z-index: 10;
116-
}
117178
</style>

0 commit comments

Comments
 (0)