밀도
밀도 (Density)
Material UI 컴포넌트에 밀도를 적용하는 방법을 알려드릴게요. 컴포넌트 사이의 간격과 크기를 조절해서 더 빽빽하거나 여유로운 레이아웃을 만들 수 있어요.
출처: 문서
본문
밀도 적용하기 (Applying density)
이 섹션에서는 밀도를 어떻게 적용하는지 설명해 드릴게요. 다만 애플리케이션에서 밀도를 사용할 때 고려해야 할 사용 사례나 주의점까지는 다루지 않아요. Material Design 가이드라인에 이 주제를 더 자세히 다루는 종합 가이드가 있으니 참고해 주세요.
밀도 구현하기 (Implementing density)
일부 컴포넌트는 props를 통해 더 높은 밀도를 적용할 수 있어요. 컴포넌트 페이지마다 각 컴포넌트에 높은 밀도를 적용한 예제가 최소 하나씩은 있답니다.
컴포넌트에 따라 밀도는 더 낮은 간격(spacing)으로 적용되기도 하고, 단순히 크기를 줄이는 방식으로 적용되기도 해요.
다음 컴포넌트들은 더 높은 밀도를 적용하는 props를 갖고 있어요:
- Button
- Fab
- FilledInput
- FormControl
- FormHelperText
- IconButton
- InputBase
- InputLabel
- ListItem
- OutlinedInput
- Table
- TextField
- Toolbar
테마 밀도 탐색하기 (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)
- Material Design — 밀도 적용 지침 (Applying density)
- Button · Fab · Table 등 밀도 props를 지원하는 컴포넌트 API