iT邦幫忙

2021 iThome 鐵人賽

DAY 21
0
Modern Web

1995到2021,php到react網站開發歷程系列 第 21

DAY21-導覽設計之Navbar

codememe.jpeg

前言:

接下來要來完成我們網站的導覽部分了,這裡阿森主要分為兩個大項目,分別是Navbar和Sidebar。Navbar就是一般看網頁時會浮在最上面的導覽選單,而Sidebar則是使用手機或是小視窗打開時,會縮小成一個按鈕,要打開才能做選擇的導覽選單。

今天會先講Navbar的設計,那我們就開始吧!

目標:

有看前幾篇的figma設計篇的話,應該都看過我設計的草稿了,這裡我想做的是當訪客點開網頁時,出現的第一個畫面是這個:

截圖 2021-09-04 下午3.14.45.png

當他把滑鼠滾輪往下捲時,我的Navbar會從上面跑下來,同時底部也會有一個Slogan往上跑,變成這樣:

截圖 2021-09-04 下午3.15.54.png

Logo也會漸漸往左上角移動,同時縮小一點。

再來是如果訪客是用手機或是小視窗打開時:

截圖 2021-09-04 下午3.22.17.png

會讓他自動縮小,至於點開Sidebar的部分就留到明天介紹。

無情開寫:

這裡阿森是用前面提到過的架構來建立我react的資料夾,所以一共有這些內容:

截圖 2021-09-04 下午3.24.41.png

那我們最主要的Home也是放在pages這個資料夾中的index.js裡,先把我們的HeroSection加上來:

index.js in pages:

import React from 'react'
import HeroSection from '../components/HeroSection'
import { useState } from 'react'

const Home = () => {
		const [isOpen, setIsOpen] = useState(false)
const toggle = () => {
		setIsOpen(!isOpen)
}

    return (
        <>

        <HeroSection toggle = { toggle }/>
				//傳入一個toggle讓HeroSection裡面的MobileIcon可以偵測之後Sidebar的開關。

        </>
    )
}

export default Home

接著我們在components裡面新增一個HeroSection資料夾,裡面有一個index.js、style.css還有一個HeroElements.js,因為這裡我們會用到前面提到的style component:

截圖 2021-09-04 下午3.36.42.png

為了達成scroll的效果,我們要用到css和javascript的搭配,所以index.js和style.css都完成後會長這樣:

index.js

import { MobileIcon, Logo} from './HeroElements'
import logo from '../../images/logo.png'
import back from '../../images/back.jpg'
import name from '../../images/name.png'
import './style.css'
import {FaBars} from 'react-icons/fa'

const HeroSection = ({toggle}) => {
    window.addEventListener("scroll", ()=>{
        const header = document.querySelector('header');
        header.classList.toggle('sticky', window.scrollY > 0);
    });
    
    return (
        <>
        <img className="logo" src = {logo} />
        <header id="header">
        <img src= {back} style={{opacity: 1}} alt="background" className = "banner"/>
    
        <Logo className="name" src = {name}/>
        
        <nav>
            <ul>
                <li><img className="navLogo" src={logo}></img></li>
                <li><a href ="/" style={{background:"gray", borderRadius:"10px"}}>News</a></li>
                <li><a href ="/">Intro</a></li>
                <li><a href ="/">Roadmap</a></li>
                <li><a href ="/">Buy</a></li>
                <li><a href ="/">FAQs</a></li>
                <li><a href ="/">Team</a></li>
                
                
                <MobileIcon onClick = {toggle} >
                 <FaBars />
                </MobileIcon>
            </ul>
        </nav>
        <div className="bottom"><p>What if their legends never end.</p></div>
        </header>
        </>
    )
}

export default HeroSection

style.css

body{
    min-height: 1000px;
    background: black;
}

header {
    position: relative;
    top: 0;
    left: 0;
    width: 100%;
    height: 100vh;
    background-origin: #000;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    transition: 1s;
}

header .banner{
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    top: 0;
    object-fit: cover;
    transition: 1s;
    
}

header.sticky nav{
    flex: none;
    background: black;
    width: 100%;
    transition: 1s;
    top: 0;
}

header nav {
    flex: none;
    transition: 1s;
    width: 100%;
    top: -80px;
}

header .name{
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    
    height: 200px;
    width: auto;
    z-index: 10;
    transition: 1s;
}

header.sticky .name{
    position: absolute;
    font-size: 2em;
    left: 50px;
    top: 30%;
    transform: translate(0, -50%);
    width: auto;
    height: 150px;
    transition: 1s;
}

@media screen and (max-width: 768px){
    header.sticky .name{
        position: absolute;
        
        transform: translate(0, -50%);
        height: 75px;
        width: auto;
        transition: 1s;
    }

    header .name{
        height: 75px;
        width: auto;
        
    }

    header .banner{
        max-width: auto;
        height: 100vh;
    }

    .bottom{
        width: fit-content;
    }

    nav ul li a{
        color: #fff;
        display: none !important;
    }

    .navLogo{
        margin-left: -70px;
    }
    .bottom p{
        margin-left: 50%;
        font-size: 0.5em;
    }

    header.sticky .navLogo{
        margin-left: -200%;
    }
}

nav {
    position: fixed;
    display: flex;
    z-index: 10;
    padding-right: 5%;
    top: 0;
}

nav ul{
    position: relative;
    display: flex;
    flex: none;
    flex-direction: row;
    transition: 0.25s;
    opacity: 0;
    justify-content: space-evenly;
    width: 100%;
}

header.sticky nav ul{
    opacity: 1;
    transition-delay: 0.75s;
    align-items: center;
}

nav ul li{
    list-style: none;
    
}

nav ul li a{
    color: #000;
    display: flex;
    padding: 10px 10px;
    font-size: 1.3em;
    text-decoration: none;
    color: white;
    top: 0;
    font-weight: 700;
    
}

nav ul li a:hover{
    color: #c64c4c;
}
nav ul li img{
    transition: 0.5s;
}
nav ul li img:hover{
    transform: scale(1.5);
    transition: 0.5s;
    cursor: pointer;
}

.navLogo{
    height: 35px;
    width: auto;
    
}

.bottom{
    width: 100%;
    height: 60px;
    position: absolute;
    display: flex;
    bottom: -60px;
    z-index: 5;
    background: #000;
    color: #fff;
    font-size: 1.8em;
    font-weight: 600;
    justify-content: center;
    align-items: center;
    transition: 1s ;
}

.bottom p{
    margin-left: 50%;
    transition: 1s;
    transition-delay: 0.75s ;
}

header.sticky .bottom{
    display: flex;
    bottom: 0;
    transition: 1s ;
}

.logo{
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    height: 200px;
    z-index: 1;
    opacity: 0.7;
}

header.sticky.logo{
    position: fixed;
    opacity: 1;
}

主要是設定header在偵測到scroll這個動作後,會觸發.sticky這個class,所以在css檔案中,可以用header.sticky這個選擇器來選擇捲動後的各個tag,之後再加上transition: 1s; 這項指令就可以達到緩緩移動的效果了。

那這裡要注意@media,他可以控制在手機螢幕還有網頁寬度小於768px時內容的表現方法,而為了達到我們的目的,這裡要把Nav ul li a的display設成none才行,然後我們來完成HeroElements.js:

截圖 2021-09-04 下午3.55.09.png

這裡我們設定MobileIcon在小於768px時才會顯現,而這個Icon我們會從react-icon這個插件中使用FaBars來完成,也就是在index.js中import的那個。關於react插件安裝的部分也可以看前面的react介紹篇哦!

所以在完成這些之後,最重要的就是把圖片存到images這個資料夾中,像是這樣:

截圖 2021-09-04 下午4.00.45.png

最後阿森附上我的package給大家參考:

{
  "name": "dino",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.4",
    "@testing-library/react": "^11.1.0",
    "@testing-library/user-event": "^12.1.10",
    "gsap": "^3.7.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-gsap": "^3.2.1",
    "react-icons": "^4.2.0",
    "react-router-dom": "^5.2.1",
    "react-scripts": "4.0.3",
    "react-scroll": "^1.8.4",
    "react-scrollmagic": "^2.3.0",
    "styled-components": "^5.3.1",
    "web-vitals": "^1.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

就可以達成我們要的效果啦!

demo2.gif

小結:

那Navbar的部分就先到這邊,明天再來延伸Sidebar要怎麼和他結合在一起吧!


上一篇
DAY20-網站構思之進階figma
下一篇
DAY22-導覽設計之Sidebar
系列文
1995到2021,php到react網站開發歷程30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言