今回はcssとjavascriptを使って、次のようなナビゲーションを実装する方法を紹介します。
- ナビゲーションアイテム要素のcurrentクラスが付いている要素の下に最初はラインがある。
- ナビゲーションアイテム要素にホバーすると、ラインが移動する。
- ホバーアウトすると、currentクラスのナビゲーションアイテム要素にラインが戻る。
実装したのがこちら
See the Pen navigation line by takblog (@blanks-site) on CodePen.
コード(html,css,javascript)
html
<nav class="nav" id="nav">
<i class="nav-line" id="nav-line"></i>
<ul class="glnav" id="glnav">
<li class="glnav-item"><a class="glnav-link" href="/">HOME</a></li>
<li class="glnav-item current"><a class="glnav-link" href="/about/">ABOUT</a></li>
<li class="glnav-item"><a class="glnav-link" href="/products/">PRODUCTS</a></li>
<li class="glnav-item"><a class="glnav-link" href="/news/">NEWS</a></li>
<li class="glnav-item"><a class="glnav-link" href="/faq/">FAQ</a></li>
<li class="glnav-item"><a class="glnav-link" href="/contact/">CONTACT</a></li>
</ul>
</nav>
css
.nav {
position: relative;
}
.nav-line {
display: block;
width: 0;
height: 2px;
position: absolute;
bottom: 0;
background-color: #ff0000;
transition: .2s all ease;
}
cssは最低限のものしか載せていません。
javascript
// 変数・定数定義
const glnav = document.getElementById("glnav");
const navItems = document.getElementsByClassName("glnav-item");
const navLine = document.getElementById("nav-line");
let navLineInitLeft;
let navLineInitWidth;
// 関数定義
const initNavline = () => {
const navCurrent = glnav.getElementsByClassName("current")[0];
const navLeft = navCurrent.getBoundingClientRect().left
const navWidth = navCurrent.clientWidth;
navLine.style.left = `${navLeft}px`;
navLine.style.width = `${navWidth}px`;
navLineInitLeft = `${navLeft}px`;
navLineInitWidth = `${navWidth}px`;
}
const navMouseOver = (target) =>{
const left = target.getBoundingClientRect().left;
const width = target.clientWidth;
navLine.style.left = `${left}px`;
navLine.style.width = `${width}px`;
}
const navMouseOut = () =>{
navLine.style.left = navLineInitLeft;
navLine.style.width = navLineInitWidth;
}
// 関数実行
initNavline();
for( let i = 0;i < navItems.length; i++ ){
navItems[i].addEventListener("mouseover",(e)=>{
navMouseOver(e.currentTarget);
});
navItems[i].addEventListener("mouseout",()=>{
navMouseOut();
});
}
window.addEventListener('resize', ()=>{
initNavline();
});
IE11等に適用させるときは、トランスパイルツールでトランスパイルしてから使用してください。
私は以下のツールでトランスパイルしています。
javascriptの説明
1~6行目:変数定義
5行目、navLineInitLeftは画面の左端からcurrentクラスが付いたglnav-item要素の左端までの距離を入れます。
6行目、navLineInitWidthはcurrentクラスが付いたglnav-item要素のwidthを入れます。
9~17行目:initNavline関数
nav-line要素の初期位置(currentクラスが付いたglnav-item要素の下にくる位置)を設定する関数です。
10行目では、currentクラスが付いたglnav-item要素を取得しています。
glnav要素内にはcurrentクラスが付いた要素は1つしかない前提なので、
glnav.getElementsByClassName("current")[0]
で取得しています。
11、12行目ではcurrentクラスが付いたglnav-item要素の左端からの距離とwidthを取得しています。
今回の場合、nav要素はwidth:100%;なので
left = navCurrent.getBoundingClientRect().left;
になっています。
nav要素にmax-widthがあって、margin: 0 autoで真ん中寄せの場合は
const nav = document.getElementById("nav");
left = navCurrent.getBoundingClientRect().left - nav.getBoundingClientRect().left;
として、leftの位置を調整します。
15、16行目でnavLineInitLeft、navLineInitWidthに11、12行目の値を入れています。
19~24行目:navMouseOver関数
glnav-item要素にマウスオーバーした時に発火する関数です。
内容はほぼinitNavline関数と同じです。
こちらもnav要素にmax-widthがあって、margin: 0 autoで真ん中寄せの場合は
const nav = document.getElementById("nav");
left = target.getBoundingClientRect().left - nav.getBoundingClientRect().left;
として、leftの位置を調整します。
26~29行目:navMouseOut関数
glnav-item要素にマウスアウトした時に発火する関数です。
nav-line要素のleftとwidthにnavLineInitLeft、navLineInitWidthを入れています。
32行目以降:関数実行
関数を実行しています。
ウィンドウ幅が変わると、nav-line要素の位置と幅は変わるので、43行目ではresizeしたときに、initNavline関数が発火するようにしています。