Skip to content

Instantly share code, notes, and snippets.

@tak-dcxi
Created October 6, 2024 11:31
Show Gist options
  • Select an option

  • Save tak-dcxi/c5cdd4ec5585bc2c67984bb4e9263458 to your computer and use it in GitHub Desktop.

Select an option

Save tak-dcxi/c5cdd4ec5585bc2c67984bb4e9263458 to your computer and use it in GitHub Desktop.
ベージトップへ戻るボタン
---
---
<return-button class="scoping-root">
<a href="#top" class="button">
<span class="visually-hidden">本文上部へ戻る</span>
</a>
</return-button>
<script>
class ReturnToTopButton extends HTMLElement {
private static readonly SENTINEL_BREAKPOINT = '30dvb'
private static readonly ACTIVE_ATTR = 'display'
private sentinel: HTMLElement | null = null
private observer: IntersectionObserver | null = null
constructor() {
super()
}
connectedCallback(): void {
this.sentinel = this.createSentinel(ReturnToTopButton.SENTINEL_BREAKPOINT)
this.initializeObserver()
}
disconnectedCallback(): void {
if (this.observer) this.observer.disconnect()
if (this.sentinel) this.sentinel.remove()
}
private createSentinel(breakpoint: string): HTMLElement {
const element = document.createElement('div')
Object.assign(element.style, {
position: 'absolute',
insetBlockStart: breakpoint,
inlineSize: '0',
blockSize: '0',
visibility: 'hidden',
})
document.body.appendChild(element)
return element
}
private initializeObserver(): void {
if (!this.sentinel) return
this.observer = new IntersectionObserver(
(entries) => {
const [entry] = entries
this.setAttribute(ReturnToTopButton.ACTIVE_ATTR, String(!entry.isIntersecting))
},
{
threshold: 0,
rootMargin: '0px',
},
)
this.observer.observe(this.sentinel)
}
}
customElements.define('return-button', ReturnToTopButton)
</script>
<style>
.scoping-root {
container: return-button / inline-size;
display: block flow;
@media (scripting: enabled) {
visibility: hidden;
}
&:defined {
transition: visibility var(--duration-default);
animation: var(--_keyframes) var(--duration-default) both;
}
&[display='true'] {
--_keyframes: fade-in;
visibility: unset;
}
&[display='false'] {
--_keyframes: fade-out;
}
}
.button {
--_foreground: var(--is-hover-false, var(--foreground-button)) var(--is-hover-true, var(--foreground-button-active));
--_background: var(--is-hover-false, var(--background-button)) var(--is-hover-true, var(--background-button-active));
display: block grid;
grid-template: var(--base-icon-size) / var(--base-icon-size);
place-content: center;
aspect-ratio: 1;
border: 1px solid transparent;
border-radius: var(--rounded-sm);
box-shadow: var(--shadow-button);
background-color: var(--_background);
color: var(--_foreground);
transition:
background-color var(--duration-default),
color var(--duration-default);
-webkit-touch-callout: none;
&::after {
content: '';
mask-image: var(--icon-chevron-up);
background-color: var(--background-current);
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment