【React】Material-UI(MUI):Webサイトのヘッダーナビを作成してみた

MUI

はじめに

筆者は普段、ReactNativeアプリの運用しているのですが、Webページを作るのにプレーンなHTMLをゴリゴリ書くのがどうも苦手でした。ReactNativeみたいな感じでコーディングできないかと行きついたものが「Material-UI」だったので早速使ってみたよという記録です。

さっそく自社サイトに組み込んでみました。

今回紹介するのはここのヘッダーナビの部分

material-ui

公式サイトはこちら

筆者はv5で実装を進めてますが、既にv6が(2023/06~)出ているようです。

インストール

npm install @mui/material @emotion/react @emotion/styled

スタイル関連のライブラリの使用頻度も高いので最初にインストールしておくことをおすすめします。

npm install @mui/material @mui/styled-engine-sc styled-components

※筆者の環境はnpmを使用しているため基本的にはnpmでインストールします。

あとMUIではないのですが、routerを使用して画面遷移を行うのでreact-router-domもインストールしておきます。

npm install react-router-dom

実装

全容はこんな感じです。

import * as React from 'react';

import { Link as RouterLink } from "react-router-dom";
import Assets from '../../assets';
import {
  AppBar, Box, Toolbar, IconButton, Typography, Menu, Container, Avatar, Button, Tooltip, MenuItem, Link, Fade
} from '@mui/material';
import { styled } from '@mui/material/styles';
import { Colors } from '../../common/Colors';

const pages = [
  {title: 'Top', to: '/', text: 'Top' },
  {title: 'Introduction', to: '/contact/', text: 'Introduction' },
  {title: 'Job', to: '/contact/', text: 'Job' },
  {title: 'Blog', to: '/contact/', text: 'Blog' },
  {title: 'Contact', to: '/contact/', text: 'Contact' },
];

function HeaderNav(props) {

  return (
      <PageBox>
        <AppBar position="static" style={{ backgroundColor: "transparent", borderWidth: 0 }} elevation={0}>
          <Container maxWidth="xl">
          <Toolbar disableGutters>
            {/* デスクトップ表示 */}
            <Box sx={{ width: 180, height: 180, display: { xs: 'none', md: 'flex' } }}>
              <Tooltip title="株式会社Sa-SaMi">
                <IconButton sx={{ width: 180, height: 180, borderRadius: 8 }} component={Link} to="/">
                  <img src={Assets.company_logo} alt="株式会社Sa-SaMi" title="株式会社Sa-SaMi" />
                </IconButton>
              </Tooltip>
            </Box>
            <Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}>
              {pages.map((page) => (
                <LinkComponent page={page} key={page.title}/>
              ))}
            </Box>
          </Toolbar>

          <Box sx={styles.messageArea}>
            <Typography variant="h1" component="h2" sx={styles.messageTxt}>
              創造したものを発信していこう
            </Typography>;
          </Box>

          </Container>
      </AppBar>

    </PageBox>

  );
}

const PageBox = styled(Box)(({ theme }) => ([{
  height: '70vh',
  backgroundImage: `url(${Assets.back})`,
  backgroundSize: "cover",
  opacity: 1,
  animation: `headerFadeIn 1.5s`,
},{
  '@keyframes headerFadeIn': {
    '0%': { opacity: 0 },
    '100%': { opacity: 1 }
}
}]));

const LinkComponent = ({page}) => {
  console.log('LinkComponent', page)
  return (
    <Link
      component={RouterLink}
      to={page.to} //遷移先
      color={Colors.WHITE}
      underline="hover"
      style={styles.linkStyle}
    >
     {page.text}
    </Link>
  )
}

export default HeaderNav;

const styles = {
  messageArea: {
    flexGrow: 1,
    display: { xs: 'none', md: 'flex' },
    justifyContent: 'center',
    paddingTop: '10rem',
    opacity: 1
  },
  messageTxt: {
    fontFamily: 'DotGothic16',
    fontSize: 56,
    letterSpacing: '3rem',
    color: Colors.WHITE
  },
  linkStyle: {
    fontSize: 24,
    marginRight: '5rem',
    fontWeight: 'bold',
    letterSpacing: '0.3rem'
  },
};

見た目がなんとなくReactNativeっぽいです。

使い心地的にはBootstrapに似てます。簡単に綺麗なUIが実装できるよ。というものなので元からある程度スタイルが設定されているので、それを理解して使いこなすのに少々学習コストがかかるなといった印象を受けました。

重要なタグを解説していきます。

一部割愛しているものがあるので気になる方は公式サイトを見てください。今回は筆者が調べて実装する必要があったものだけを紹介します。

PageBox

カスタムHTML的なものです。Box(ReactNativeで言うとView、HTMLでいうとdiv的な存在)をカスタムしてます。

何をしているかというと、Styleを独自にカスタマイズしたBoxコンポーネントを作成してます。

const PageBox = styled(Box)(({ theme }) => ([{
  height: '70vh',
  backgroundImage: `url(${Assets.back})`,
  backgroundSize: "cover",
  opacity: 1,
  animation: `headerFadeIn 1.5s`,
},{
  '@keyframes headerFadeIn': {
    '0%': { opacity: 0 },
    '100%': { opacity: 1 }
}
}]));

全然Boxで実装しても良いのですが、アニメーションの設定をしたかったのでカスタムHTMLを使用しております。

  opacity: 1,
  animation: `headerFadeIn 1.5s`,
},{
  '@keyframes headerFadeIn': {
    '0%': { opacity: 0 },
    '100%': { opacity: 1 }
}

Fadeのやり方はいろいろあるようなので興味ある方は公式サイトを見てみてください。(筆者はまだMUI初心者なのでこのやり方しか出来ませんでした。)

AppBar

公式サイトでいうとこれの大枠です。

<AppBar position="static" style={{ backgroundColor: "transparent", borderWidth: 0 }} elevation={0}>

styleを設定しないとデフォルトで青色のバーができあがります。筆者のサイトは背景画像の上にサイトバーを載せたかったのでtransparentで透過させてます。

elevationはデフォルトで1のようです。elevationは下線部の影のスタイルです。筆者のサイトは不要だったので0に設定してあります。

この黄色の部分

Box

前途でも書きましたが、ReactNativeでいうとView、HTMLでいうとdivみたいな存在のようです。

ただ1点テキストをただ単に表示させるときも使うのでそこがReactNativeやHTMLと違うところです。

<Box>{'ほげほげ'}</Box>

加えてスタイルを指定するときはsxを使用します。

 <Box sx={styles.messageArea}>
  <Typography variant="h1" component="h2" sx={styles.messageTxt}>
    創造したものを発信していこう
  </Typography>;
 </Box>

↑を見るとただ1点テキストをただ単に表示させるときにTypographyを使用しているじゃないかと思った方いるとおもいます。

Typographyは<h1><h2>などのhタグと同じ用途で使用するようです。

pタグみたいな使い方をするにはBoxを使用するほうが良いみたいです。

LinkComponent

一番大切な部分です。

「Top」「Introduction」「Job」「Blog」「Contact」この部分を実装しています。

import { Link as RouterLink } from "react-router-dom";
import {
 Link
 } from '@mui/material';

const pages = [
  {title: 'Top', to: '/', text: 'Top' },
  {title: 'Introduction', to: '/contact/', text: 'Introduction' },
  {title: 'Job', to: '/contact/', text: 'Job' },
  {title: 'Blog', to: '/contact/', text: 'Blog' },
  {title: 'Contact', to: '/contact/', text: 'Contact' },
];


<Box sx={{ flexGrow: 1, display: { xs: 'none', md: 'flex' } }}>
  {pages.map((page) => (
    <LinkComponent page={page} key={page.title}/>
  ))}
</Box>


const LinkComponent = ({page}) => {
  return (
    <Link
      component={RouterLink}
      to={page.to} //遷移先
      color={Colors.WHITE}
      underline="hover"
      style={styles.linkStyle}
    >
     {page.text}
    </Link>
  )
}

まず、表示させたいページの配列データを作成します。key項目/遷移先/表示したい文字列という構成にしてあります。

const pages = [
  {title: 'Top', to: '/', text: 'Top' },
  {title: 'Introduction', to: '/contact/', text: 'Introduction' },
  {title: 'Job', to: '/contact/', text: 'Job' },
  {title: 'Blog', to: '/contact/', text: 'Blog' },
  {title: 'Contact', to: '/contact/', text: 'Contact' },
];

次に表示用コンポーネントを作成します。

const LinkComponent = ({page}) => {
  return (
    <Link
      component={RouterLink}
      to={page.to} //遷移先
      color={Colors.WHITE}
      underline="hover"
      style={styles.linkStyle}
    >
     {page.text}
    </Link>
  )
}

ここがポイントで、

  1. @mui/materialのLinkのComponentにreact-router-domのLinkを設定します。
  2. @mui/materialのLinkのtoに遷移先を設定します。

これでリンクを押下したらページ遷移するようになります。

ちなみにRouterはこんな感じで設定してあります。※まだ作成途中なのでTop以外はContactしかありません・・・・・

import React from 'react';
import { BrowserRouter, Routes, Route } from "react-router-dom";
import HomeScreen from './screen/HomeScreen';
import ContactScreen from "./screen/ContactScreen";
import NotFoundScreen from './screen/NotFound';
import HeaderNav from './components/common/HeaderNav';
import Footer from './components/common/Footer';

const App = () => {
  return (
    <div>
      <BrowserRouter>
        <HeaderNav />
        <Routes>
          <Route exact path={`/`} element={<HomeScreen />} />
          <Route path={`/contact/`} element={<ContactScreen />} />
          <Route path={`/*/`} element={<NotFoundScreen />} />
        </Routes>
        <Footer />
      </BrowserRouter>
    </div>
  );
};

export default App;

諸々端折って書いてしまいましたが、参考になれば幸いです。

コメント