밀도

밀도 (Density)

Material UI 컴포넌트에 밀도를 적용하는 방법을 알려드릴게요. 컴포넌트 사이의 간격과 크기를 조절해서 더 빽빽하거나 여유로운 레이아웃을 만들 수 있어요.

출처: 문서

본문

밀도 적용하기 (Applying density)

이 섹션에서는 밀도를 어떻게 적용하는지 설명해 드릴게요. 다만 애플리케이션에서 밀도를 사용할 때 고려해야 할 사용 사례나 주의점까지는 다루지 않아요. Material Design 가이드라인에 이 주제를 더 자세히 다루는 종합 가이드가 있으니 참고해 주세요.

밀도 구현하기 (Implementing density)

일부 컴포넌트는 props를 통해 더 높은 밀도를 적용할 수 있어요. 컴포넌트 페이지마다 각 컴포넌트에 높은 밀도를 적용한 예제가 최소 하나씩은 있답니다.

컴포넌트에 따라 밀도는 더 낮은 간격(spacing)으로 적용되기도 하고, 단순히 크기를 줄이는 방식으로 적용되기도 해요.

다음 컴포넌트들은 더 높은 밀도를 적용하는 props를 갖고 있어요:

테마 밀도 탐색하기 (Explore theme density)

이 도구를 사용하면 spacing과 컴포넌트 props를 통해 밀도를 적용해 볼 수 있어요. 이리저리 둘러보면서 Material UI 컴포넌트의 전체적인 느낌에 어떻게 영향을 주는지 확인해 보세요.

높은 밀도를 활성화하면 docs에 커스텀 테마가 적용돼요. 이 테마는 데모용일 뿐이에요. 이 테마를 애플리케이션 전체에 적용해서는 안 돼요 — 사용자 경험에 부정적인 영향을 줄 수 있기 때문이죠. Material Design 가이드라인에 밀도를 적용하지 말아야 할 때의 예시가 나와 있어요.

테마는 다음 옵션으로 구성돼 있어요:

const theme = createTheme({
  components: {
    MuiButton: {
      defaultProps: {
        size: 'small',
      },
    },
    MuiFilledInput: {
      defaultProps: {
        margin: 'dense',
      },
    },
    MuiFormControl: {
      defaultProps: {
        margin: 'dense',
      },
    },
    MuiFormHelperText: {
      defaultProps: {
        margin: 'dense',
      },
    },
    MuiIconButton: {
      defaultProps: {
        size: 'small',
      },
    },
    MuiInputBase: {
      defaultProps: {
        margin: 'dense',
      },
    },
    MuiInputLabel: {
      defaultProps: {
        margin: 'dense',
      },
    },
    MuiListItem: {
      defaultProps: {
        dense: true,
      },
    },
    MuiOutlinedInput: {
      defaultProps: {
        margin: 'dense',
      },
    },
    MuiFab: {
      defaultProps: {
        size: 'small',
      },
    },
    MuiTable: {
      defaultProps: {
        size: 'small',
      },
    },
    MuiTextField: {
      defaultProps: {
        margin: 'dense',
      },
    },
    MuiToolbar: {
      defaultProps: {
        variant: 'dense',
      },
    },
  },
});
import * as React from 'react';
import Box from '@mui/material/Box';
import Input from '@mui/material/Input';
import Typography from '@mui/material/Typography';
import Button from '@mui/material/Button';
import IconButton from '@mui/material/IconButton';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch from '@mui/material/Switch';
import IncreaseIcon from '@mui/icons-material/AddCircleOutlined';
import DecreaseIcon from '@mui/icons-material/RemoveCircleOutlined';
import {
  DispatchContext,
  ThemeOptionsContext,
} from '@mui/internal-core-docs/ThemeContext';
import { useTranslate } from '@mui/internal-core-docs/i18n';
import { setDocsSpacing, resetDocsSpacing } from '@mui/internal-core-docs/branding';

const minSpacing = 0;
const maxSpacing = 20;

export default function DensityTool() {
  const [spacingUnit, setSpacingUnit] = React.useState(8);
  const dispatch = React.useContext(DispatchContext);
  const themeOptions = React.useContext(ThemeOptionsContext);
  const handleDensityChange = (event) => {
    dispatch({
      type: 'SET_DENSE',
      payload: event.target.checked,
    });
  };

  const handleSpacingChange = (event, value) => {
    let spacing = value || +event.target.value;

    //  If the entered value is greater than maxSpacing, setting up maxSpacing as value
    if (spacing > maxSpacing) {
      spacing = maxSpacing;
    }
    //  If the entered value is less than minSpacing, setting up minSpacing as value
    if (spacing < minSpacing) {
      spacing = minSpacing;
    }

    setSpacingUnit(spacing);
    setDocsSpacing(spacing);
  };

  const resetDensity = () => {
    setSpacingUnit(8);
    resetDocsSpacing();
    dispatch({ type: 'RESET_DENSITY' });
  };

  const t = useTranslate();

  return (
    <Box
      sx={{
        width: '100%',
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'flex-start',
        gap: 2,
      }}
    >
      <FormControlLabel
        control={
          <Switch
            checked={themeOptions.dense}
            onChange={handleDensityChange}
            value="dense"
            color="secondary"
          />
        }
        label={t('useHighDensity')}
      />
      <Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
        <Typography id="input-slider" gutterBottom>
          {t('spacingUnit')}
        </Typography>
        <Box sx={{ display: 'flex', alignItems: 'center' }}>
          <IconButton
            aria-label={t('decreaseSpacing')}
            onClick={() => {
              setSpacingUnit(spacingUnit - 1);
              setDocsSpacing(spacingUnit - 1);
            }}
            disabled={spacingUnit === minSpacing}
          >
            <DecreaseIcon />
          </IconButton>
          <Input
            value={spacingUnit}
            margin="dense"
            onChange={handleSpacingChange}
            inputProps={{
              step: 1,
              min: minSpacing,
              max: maxSpacing,
              type: 'number',
              'aria-labelledby': 'input-slider',
            }}
          />
          <IconButton
            aria-label={t('increaseSpacing')}
            onClick={() => {
              setSpacingUnit(spacingUnit + 1);
              setDocsSpacing(spacingUnit + 1);
            }}
            disabled={spacingUnit === maxSpacing}
          >
            <IncreaseIcon />
          </IconButton>
        </Box>
      </Box>
      <Button variant="contained" onClick={resetDensity}>
        {t('resetDensity')}
      </Button>
    </Box>
  );
}

더 알아보기 (Learn more)