Element Plus 그리드 시스템 개요
Vue 3 환경에서 Element Plus는 24개의 열(Column)을 기반으로 하는 유연한 그리드 레이아웃 시스템을 제공합니다. 이를 통해 복잡한 UI도 쉽게 구조화할 수 있으며, el-row와 el-col 컴포넌트를 조합하여 다양한 화면 크기에 대응하는 반응형 디자인을 구축할 수 있습니다.
el-row 컴포넌트 주요 속성
행(Row)을 정의하는 el-row는 열들의 배치 방식과 간격을 제어합니다.
- gutter: 열 사이의 간격(픽셀 단위)을 지정합니다. 기본값은 0입니다.
- type: 레이아웃 모드를 설정합니다.
flex를 사용하여 플렉스박스 레이아웃을 활성화할 수 있습니다. - justify:
type="flex"일 때 수평 정렬 방식을 결정합니다 (예:start,center,end,space-between). - align:
type="flex"일 때 수직 정렬 방식을 결정합니다 (예:top,middle,bottom). - tag: 렌더링될 사용자 정의 HTML 태그를 설정합니다. 기본값은
div입니다.
el-col 컴포넌트 주요 속성
열(Column)을 정의하는 el-col은 각 요소가 차지하는 너비와 위치를 조절합니다.
- span: 열이 차지하는 칸 수를 지정합니다 (최대 24). 기본값은 24입니다.
- offset: 열 왼쪽에 여백으로 남길 칸 수를 설정합니다.
- push / pull: 열을 오른쪽이나 왼쪽으로 이동시켜 순서를 변경할 때 사용합니다.
- 반응형 속성 (xs, sm, md, lg, xl): 다양한 뷰포트 너비에 따라 동적으로 span이나 offset을 적용할 수 있습니다. 숫자 또는 객체(예:
{span: 4, offset: 2})를 전달합니다.xs: 768px 미만sm: 768px 이상md: 992px 이상lg: 1200px 이상xl: 1920px 이상
기본 그리드 레이아웃 예제
다음은 20px의 간격을 두고 화면을 3등분하는 기본적인 그리드 구조입니다.
<template>
<el-row :gutter="20">
<el-col :span="8">
<div class="grid-content">섹션 A</div>
</el-col>
<el-col :span="8">
<div class="grid-content">섹션 B</div>
</el-col>
<el-col :span="8">
<div class="grid-content">섹션 C</div>
</el-col>
</el-row>
</template>
<style scoped>
.grid-content {
background-color: #f0f2f5;
padding: 20px;
text-align: center;
border-radius: 4px;
}
</style>
반응형 레이아웃을 적용한 로그인 폼 구현
그리드 시스템을 활용하여 화면 크기에 따라 중앙 정렬되는 반응형 로그인 폼을 만들어 보겠습니다. Vue 3의 <script setup> 문법을 사용하여 코드를 간결하게 작성했습니다.
<template>
<el-row justify="center" class="login-container">
<el-col :xs="24" :sm="18" :md="12" :lg="8">
<el-card shadow="hover">
<template #header>
<h3 style="text-align: center; margin: 0;">시스템 로그인</h3>
</template>
<el-form
:model="credentials"
:rules="validationRules"
ref="authFormRef"
label-position="top"
>
<el-form-item label="아이디" prop="userId">
<el-input
v-model="credentials.userId"
prefix-icon="User"
placeholder="아이디를 입력하세요"
/>
</el-form-item>
<el-form-item label="비밀번호" prop="userPw">
<el-input
v-model="credentials.userPw"
type="password"
prefix-icon="Lock"
placeholder="비밀번호를 입력하세요"
show-password
/>
</el-form-item>
<el-form-item label="보안 문자" prop="securityCode">
<el-row :gutter="10">
<el-col :span="16">
<el-input
v-model="credentials.securityCode"
placeholder="문자를 입력하세요"
/>
</el-col>
<el-col :span="8">
<img
:src="captchaImageUrl"
alt="Captcha"
class="captcha-img"
@click="regenerateCaptcha"
/>
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-button type="primary" style="width: 100%;" @click="handleLogin">
로그인
</el-button>
</el-form-item>
</el-form>
</el-card>
</el-col>
</el-row>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { ElMessage } from 'element-plus';
const authFormRef = ref(null);
const credentials = ref({
userId: '',
userPw: '',
securityCode: '',
});
const validationRules = {
userId: [{ required: true, message: '아이디는 필수 입력 항목입니다.', trigger: 'blur' }],
userPw: [
{ required: true, message: '비밀번호를 입력해 주세요.', trigger: 'blur' },
{ min: 6, message: '비밀번호는 최소 6자 이상이어야 합니다.', trigger: 'blur' }
],
securityCode: [{ required: true, message: '보안 문자를 입력하세요.', trigger: 'blur' }],
};
const captchaImageUrl = ref('');
const regenerateCaptcha = () => {
const timestamp = Date.now();
captchaImageUrl.value = `/api/v1/auth/captcha?_t=${timestamp}`;
};
const handleLogin = async () => {
if (!authFormRef.value) return;
try {
await authFormRef.value.validate();
ElMessage.success('인증 성공! 대시보드로 이동합니다.');
// 실제 API 호출 로직 수행
} catch (error) {
ElMessage.error('입력 값을 다시 확인해 주세요.');
}
};
onMounted(() => {
regenerateCaptcha();
});
</script>
<style scoped>
.login-container {
margin-top: 50px;
}
.captcha-img {
width: 100%;
height: 32px;
cursor: pointer;
border-radius: 4px;
border: 1px solid #dcdfe6;
}
</style>
위 코드에서는 el-row의 justify="center" 속성을 활용해 폼을 화면 중앙에 배치했습니다. 또한 el-col에 반응형 속성(:xs, :sm, :md, :lg)을 적용하여 모바일부터 데스크톱 환경까지 최적화된 너비를 자동으로 계산하도록 구현했습니다. 보안 문자 입력 영역에서는 중첩된 el-row와 el-col을 사용하여 입력창과 이미지를 비율에 맞게 분할했습니다.