クリックしたliタグをtranslateYする

Javascript

主な流れ

・クリックしたliタグをtranslateY(-10px)する

・effectクラスで装飾する

・「.offsetLeft」を使ってactiveクラスの左上座標を取得し、CSS変数にsetPropertyする

デメリット

・circle::beforeの影がeffect::before, effect::after に重なるため、要素の半透明にできない

・circleを角丸に変えたとき、circle::before が角丸の影にできない

・FontAwesomeが重くてサイト表示に時間がかかる ⇒ 使うものだけSVG画像をDLしたほうが良さそう

・ナビゲーションとして使う場合、ボタンを押したときに別のページに飛んでしまい、JSの動きを見ることすらできない => ナビゲーションよりタブとして使うべきアニメーションだと思う

HTML

font awesome のCDNは廃止されたため、CDNJSという海外のサイト(https://cdnjs.com/libraries/font-awesome)を使ってLinkタグを貼り付けること
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.7.2/css/all.min.css" integrity="sha512-Evv84Mr4kqVGRNSgIGL/F/aIDqQb7xQ2vcrdIwxfjThSH8CSR7PBEakCr51Ck+w+/U6swU2Im1vVX0SVk9ABhg==" crossorigin="anonymous" referrerpolicy="no-referrer" />

<nav>
    <ul>
        <li class="active"><i class="fa-solid fa-house"></i></li>
        <li><i class="fa-solid fa-location-dot"></i></li>
        <li><i class="fa-solid fa-building"></i></li>
        <li><i class="fa-solid fa-envelope"></i></li>
        <li><i class="fa-solid fa-phone"></i></li>
    </ul>
    <div class="effect">
        <div class="circle"></div>
    </div>
</nav>

CSS

	:root {
		--w-h-item: 60px;
		--position-active: 170px;	
	}
	body {
		background-color: #f2f2f2;
	}
	nav {
		position: fixed;
		inset: auto 0 0;
		border-bottom: 20px solid #fff;
		color: #fff;
		width: min(500px, 100%);
		--w-h-item: 60px;
		--position-active: 170px;
	}
	nav ul {
		padding: 0;
		margin: 0;
		display: grid;
		grid-template-columns: repeat(5, 60px);
		grid-template-rows: 60px;
		justify-content: space-between;
	}
	nav ul li {
		display: flex;
		justify-content: center;
		align-items: center;
		font-size: 15px;
		transition: 0.5s;
	}
	nav ul li.active {
		transform: translateY(-10px);
	}
	nav ul li.active i {
		color: #fff;
	}

/***** 装飾部分 *****/
	nav .effect {
	    position: absolute;
		left: 0;
		bottom: 0;
		width: 100%;
		height: calc( var(--w-h-item) + 10px );
		overflow: hidden;
		z-index: -1;
	}
	nav .effect::before {
	    position: absolute;
		left: 0;
		bottom: 0;
		
		content: "";
		width: calc( var(--position-active) - 10px );
		height: var(--w-h-item);
		
		background-color: #fff;
		border-top-right-radius: 30px;
		transition: 0.5s;
	}
	nav .effect::after {
	    position: absolute;
		right: 0;
		bottom: 0;
		
		content: "";
		width: calc( 100% - var(--position-active) - var(--w-h-item) - 10px );
		height: var(--w-h-item);
		
		background-color: #fff;
		border-top-left-radius: 30px;
		transition: 0.5s;
	}
	nav .effect .circle {
		position: absolute;
		left: var(--position-active);
		
		width: var(--w-h-item);
		height: var(--w-h-item);
		
		background-color: #039ffa;
		border-radius: 50%;
		box-shadow: 0 20px 20px #555;
		transition: 0.5s;
	}
	nav .effect .circle::before {
		position: absolute;
		left: -10px;
		right: -10px;
		bottom: -10px;
		
		content: "";
		height: 100%;
		
		background-color: transparent;
		border-radius: 50%;
		box-shadow: 0 50px 0 30px #fff;
		transform: 0.5s;
	}

※1 … insetを使うことでtop,left,right,bottomを一括で指定できます

Javascript

	let nav = document.querySelector("nav");
	let items = document.querySelectorAll("li"); ※2
	items.forEach( item => {
		item.onclick = () => {
			let oldActive = nav.querySelector("li.active");
			if (oldActive) {
				oldActive.classList.remove("active");
			}
			item.classList.add("active");
			nav.style.setProperty("--position-active", item.offsetLeft + "px");
		}
	});
	
    // 
	let itemActive = nav.querySelector("li.active");
	if (itemActive) {
		nav.style.setProperty("--position-active", itemActive.offsetLeft + "px");
	}

※1 … item.onclick = () => { … } は item.onclick = function() { … } と同じです。(アロー関数)

また、onClickではなく、onclickです。

※2 … Allの入れ忘れに注意

※3 … .offsetLeftによって左上座標が取得できます

参考サイト

https://www.youtube.com/watch?v=RIr9CxF28-0&list=WL&index=2

BACK