KINTO Tech Blog
Development

HTMLのアンカータグ(aタグ)でページの特定部分までスクロールしたら微調整が必要かもという話

Cover Image for HTMLのアンカータグ(aタグ)でページの特定部分までスクロールしたら微調整が必要かもという話

はじめに

こんにちは。KINTO Technologiesのグローバル開発部でフロントエンド開発をしているクリスです。

今日はフロントエンドの開発におけるちょっとした詰まったこととそれの解決策について紹介したいと思います!

詰まったこと

普段みなさんは以下のようにアンカータグ(aタグ)を使ってとあるページの特定部分までスクロールさせたい時ありますよね?
スクロール先の要素にidを付与し、aタグにhref="#{id}"をつければそれが実現できます。

<a href="#section-1">Section 1</a>
<a href="#section-2">Section 2</a>
<a href="#section-3">Section 3</a>
<section class="section" id="section-1">
  Section 1
</section>
<section class="section" id="section-2">
  Section 2
</section>
<section class="section" id="section-3">
  Section 3
</section>

no-header

記事や規約など長いページだと、ユーザーにとって役に立ちます。

しかし、現実では多くの場合、ヘッダーといったページの上に固定する要素があって、aリンクをクリックし、スクロールされた後に少し位置がずれてしまいます。

例えば以下のようなヘッダーがあるとします。

<style>
  header {
    position: fixed;
    top: 0;
    width: 100%;
    height: 80px;
    background-color: #989898;
    opacity: 0.8;
  }
</style>
<header style="">
  <a href="#section-1">......</a>
  <a href="#section-2">......</a>
  <a href="#section-3">......</a>
  ...
</header>

あえてこのヘッダーを少し透過にしましたが、aリンクをクリックして、移動になった後に、一部のコンテンツがヘッダーの後ろに隠れてしまったことがわかります。

with-header

HTMLとCSSだけを用いた解決策

aリンクをクリックした時に、Javascriptでヘッダーの高さを取得し、スクロール位置からヘッダーの高さを引いてスクロールさせれば問題解決できますが、今日はHTMLとCSSを用いた解決策を紹介したいと思います。具体的には本来到達したい<section>より少し上に別の<div>を用意し、その要素までスクロールさせる方法です。

先ほどの例に戻って、まず各セッションの中に一つのdivタグを作ります。そして該当divタグに一つのclass、例えばanchor-offsetを付与し、さらに元々<section>タグに付与したidも新しく作ったdivタグに移します。

<section>
  <div class="anchor-offset" id="section-1"></div>
  <h1>Section 1</h1>
  ...
</section>

そしてcssで<section>タグと.anchor-offsetのスタイル定義をします。

/* アンカーを設置する必要がある要素のみ付与したい場合はclassを利用 */
section {
  position: relative;
}

.anchor-offset {
  position: absolute;
  height: 80px;
  top: -80px;
  visibility: hidden;
}

上記のように設定すると、aリンクをクリックした時に、該当する<section>の本位置ではなく、それより少し(例の場合では80px)上の部分までスクロールされ、ヘッダーの高さ(80px)と相殺されます。

anchor-offset

Vueにおける書き方

Vueでは値をcssにバインドすることができます。この機能を利用し、高さを動的に設定しコンポーネントにすれば、さらにメインテナンスしやすくなると思います。

<template>
  <div :id="props.target" class="anchor-offset"></div>
</template>

<script setup>
const props = defineProps({
  target: String,
  offset: Number,
})
const height = computed(() => {
  return `${props.offset}px`
})
const top = computed(() => {
  return `-${props.offset}px`
})
</script>

<style scoped lang="scss">
.anchor-offset {
  position: absolute;
  height: v-bind('height');
  top: v-bind('top');
  visibility: hidden;
}
</style>

まとめ

以上、aタグでページの特定部分までスクロールする際にヘッダーなどの固定要素に合わせたスクロール位置の調整方法でした。
他にも色々なやり方がありますが、ご参考になれたらと思います!

Facebook

関連記事 | Related Posts

Chris.L
Chris.L
Cover Image for Improving User Experience with Subtle Scroll Adjustments on HTML Anchor Tags (<a> Tag)

Improving User Experience with Subtle Scroll Adjustments on HTML Anchor Tags (<a> Tag)

Cover Image for Vuetify と NuxtJS を使用した言語サポート

Vuetify と NuxtJS を使用した言語サポート

Cover Image for Vue.js におけるPinia:はじめての状態管理

Vue.js におけるPinia:はじめての状態管理

モジ
モジ
Cover Image for エキサイティングなTechBlogのデザイン変更

エキサイティングなTechBlogのデザイン変更

Chris.L
Chris.L
Cover Image for フロントエンドチームリーダーに就任して思ったこと

フロントエンドチームリーダーに就任して思ったこと

Yusuke Ikeda
Yusuke Ikeda
Cover Image for SvelteKit + Svelte を1年間くらい使ってみた知見など

SvelteKit + Svelte を1年間くらい使ってみた知見など

We are hiring!

【Webアナリスト】分析G/東京・名古屋・大阪

分析グループについてKINTOにおいて開発系部門発足時から設置されているチームであり、それほど経営としても注力しているポジションです。決まっていること、分かっていることの方が少ないぐらいですので、常に「なぜ」を考えながら、未知を楽しめるメンバーが集まっております。

【フロントエンドエンジニア(コンテンツ開発)】新車サブスク開発G/東京

新車サブスク開発グループについてTOYOTAのクルマのサブスクリプションサービスである『 KINTO ONE 』のWebサイトの開発、運用をしています。​業務内容トヨタグループの金融、モビリティサービスの内製開発組織である同社にて、自社サービスである、TOYOTAのクルマのサブスクリプションサービス『KINTO ONE』のWebサイトの開発、運用を行っていただきます。