12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Material UI (MUI) 入門

Last updated at Posted at 2024-06-30

フロントエンドのスタイリングについて、考えた時にUIライブラリとして候補に上がってくるMaterial UI (MUI)を触ってみて基礎的な内容と、感じたことをメモで残しました。

この記事の対象者

  • cssの基本的な文法は分かる
  • MUIを使ってみようと思っているが、使うイメージが全然わかない人
  • MUI の文法の基礎を知りたい人

環境

シンプルに npx create-react-app アプリ名で生成した状態です。

package.json
  "dependencies": {
    "@emotion/react": "^11.11.4",
    "@emotion/styled": "^11.11.5",
    "@mui/material": "^5.15.21",
    "react": "^18.3.1",
  }

Container

コンテンツを水平方向に中央揃えでき、最も基本的なレイアウト要素になる。
デフォルトで左右にpaddingがデフォルトで適用されている

<Container>Hello World</Container>

image.png

backgroud-color、height などを変更したい時は、他のMUIコンポーネントに共通している sx props を使用すると良い。

<Container sx={{bgcolor: 'cyan', height: '64px'}}>Hello World</Container>

Box

MUIのテンプレートを見ているとめっちゃ見る要素。
divタグに変換されるが、あえてBoxを使用する理由は sx props を使用できることにある

せっかくなので、sxも少し深ぼってみる

sx

スタイルをシュートハンド記法で書くことができる仕組みを提供してくれている。

    <Container
      sx={{
        bgcolor: 'cyan',
        boxShadow: 1,
        borderRadius: 2,
        p: 2,
        minWidth: 300,
      }}
    >Hello World</Container>

image.png

使用しているbgcolorなどはCSSのプロパティでは backgroud-colorになるが、これはMUIのショートハンド(省略記法)で、以下のような省略がある。
p: padding
m: margin
py: padding top & bottom

使用可能なプロパティのリストも公式に載っているので、こちらを参考にすると良い

その他、MUIを初めて使ってみて慣れない記法があったので、少しまとめようと思う

spacingプロパティ

margin, padding などの spacing プロパティでは px を使用するのではなく 1, 2 ... と数値型を指定する。

    <Typography sx={{m: 1, bgcolor: 'pink'}}>Hello</Typography>

image.png

1 = 8px と 8px単位で組み込まれていることに注意が必要。
「めんどくさくね?」と感じるかもしれないが、8pxルールが設けられていることでコンテンツの大きさや余白の秩序をより厳密に保ちやすくなるようにも感じる

hover

便利だと感じたのはhoverを指定できること
通常、style に指定しても hover を効かせることはできない

  // 以下のホバーは機能しない
  <Button style={{background: 'cyan', ':hover': {background: 'gray'}}}>送信</Button>

が、sx を使用することで hover を適用できる

    <Button sx={{bgcolor: 'cyan', ':hover': {bgcolor: 'gray'}}}>送信</Button>

そして、これは他の擬似要素(::befire, ::after など)でも適用できる。
例えば、 before, after 擬似要素にスタイルを当てることもできる。

    <Box
      sx={{
        position: 'relative',
        p: 2,
        my: 2,
        "&::before, &::after": {
          content: '""',
          position: 'absolute',
          width: '100%',
          height: '2px',
          bgcolor: 'black',
        },
        "&::before": {
          top: 0,
        },
        "&::after": {
          bottom: 0,
        },
      }}
    >
      <Typography variant="h6" textAlign="center">
        Box with Top and Bottom Lines
      </Typography>
    </Box>

以下のように、擬似要素にスタイルを当てて、線を表現することもできる
image.png

ブレイクポイント

ブレイクポイントに合わせたスタイルを適用することもできるのでレスポンシブデザインも簡単に設定できる

    // xs: 0px
    // sm: 600px
    // md: 900px
    // lg: 1200px
    // XL: 1536px

    <Box
      sx={{
        bgcolor: 'cyan',
        width: {
          xs: 100,
          xl: 1200,
        },
      }}
    >
      <Typography variant="h6" textAlign="center">
        Box with Top and Bottom Lines
      </Typography>
    </Box>

また、デフォルトの設定では xs, lg とかぱっと見、「どのような条件で値を変化させるのか」のルールが分かりにくい。もっと直感的な命名にしたいこともあるだろう。

width: { pc: 100, mobile: 1200}のように PC, Mobile版 とユースケースを明確にしたい。

そんな時はカスタムテーマを設定し、適用したい範囲を ThemeProviderでラップすると良い。

import * as React from 'react';
import Box from '@mui/material/Box';
import { createTheme, ThemeProvider } from '@mui/material/styles';

const theme = createTheme({
  breakpoints: {
    values: {
      mobile: 0,
      tablet: 640,
      laptop: 1024,
      desktop: 1280,
    },
  },
});

export default function CustomBreakpoints() {
  return (
    <ThemeProvider theme={theme}>
      <Box
        sx={{
          width: {
            mobile: 100,
            laptop: 300,
          },
        }}
      >
        This box has a responsive width
      </Box>
    </ThemeProvider>
  );
}

メモ:
カスタムテーマを各ファイルで呼び出すと冗長なので、themeファイルを作成し、App.js あたりでprovide してしまうのが綺麗なんじゃないかと思う

theme.jsx
// 略

export const theme = createTheme({
  breakpoints: {
    values: {
      mobile: 0,
      tablet: 640,
      laptop: 1024,
      desktop: 1280,
    },
  },
});
App.jsx
 // 略
 function App() {
  return (
    <ThemeProvider theme={theme}>
      <AppContextProvider>
        // routerとかの定義
      </AppContextProvider>
    </ThemeProvider>
  );
}
 

Typography

文字を入力する時に使用する
デフォルトで pタグ として出力されるが、variant props を使用することでh1タグなどに変換できる
variant の種類も公式に載っているので良い感じに使い分けたい。

ちなみに variant props は他のコンポーネント( Buttonコンポーネント とか)にも用意されているので、用途にあったvariantをチョイスしたい。

    <Container sx={{bgcolor: 'cyan', height: '88px'}}>
      <Typography variant='h3'>Hello World</Typography>
      <Typography variant='subtitle1'>good morning!</Typography>
    </Container>

image.png

備考

Container, Box, Typography とMUIの記法についてざっくり分かるとあとはテンプレートを見ると書いている内容がざっくり理解できる...はず。

基本的にはテンプレートをコピペして、必要な部分のみに削ったり、詳細なプロパティを調整するだけで立派なレイアウトを組み立てることができそうです。

まとめ

ここまでみていただきありがとうございます。 m(._.)m

MUIを使う上で頻出のコンポーネントについて軽く触れました。
記事には載せてはいませんが、テンプレートを使った上で感じたことは

  • 書き方にルールがあるため、スタイリングに規則性が生まれそう
  • 基本テンプレを調整するだけで実装できるのでリードタイムを格段に短縮できそう

などとメリットも感じますが

  • デフォルトで存在する padding などを調整したい時は上書きで行う必要がある
  • 単位、書き方が特殊なのでキャッチアップにコストがかかる
  • アプデがあった時の追随が結構しんどいかも
  • MUIのデザインに引っ張られるので、オーバーライドが多いと実装が大変

といったデメリットもあり、全部MUIで書くと後々恨まれそうな気がします。

しかし、カレンダーchart など普通に実装するとあまりにめんどくさい機能をサクッと実装できる機能を提供していることもあるので、この恩恵は捨てがたい...

実装がしんどい部分だけをMUIにしてみるなどの手段も候補に入れても良さそうですね。

12
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?