오늘도 출근해서 상사 분들과 이런 저런 이야기를 나눴습니다. 개발 업계에서 20년 조금 넘게 계시는 분께서 이런 말씀을 하시더군요.
이제는 진짜. 반응형 AI의 시대를 넘어서 AI Agent의 시대로 넘어왔어. 그리고 AI개발자도 많이 양산되겠지만.
이제는 GPT, Cursor, AntiGravity 등 AI를 얼마나 잘 다루는 개발자인지가 중요할꺼야.
제가 계속해서 언급하던 그 말과 정확히 동일한 말씀을 하셨습니다. 하물며 과거에는 ‘스마트’ 라는 단어를 붙인 제품들이 인기였지만. 이제는 ‘AI’ 라는 단어가 들어간 제품들이 즐비하다는 말씀을 하시더라구요. 지극히 공감이 가는 부분이었습니다.
이전처럼 단순한 작업도 하드코딩하거나 디자인 하나하나를 꾸며가며 명령어를 쓰는 시대는 확실히 지나갔습니다. AI 툴만 잘 다루면 비전공자가 아닌 ‘비개발자’ 도 프롬프트 몇 줄이면 왠만한 홈페이지, 템플릿은 뚝딱하고 만들어 내는 시대니까요.
각설하고. 항상 여러분께 주장 해오던 대로 저는 개발자이기에 우리가 어떻게 하면 이런 AI를 잘 다룰 수 있을지. 어떤 상황에 어떤 AI를 써야 하는지. 그 부분을 저는 여러분들과 함께 고민하고 논하면서 글을 열까 합니다.
“이제는 실제 서비스 품질 수준으로 다듬기”
지난 시간까지 개발 분야 3대 AI인 Chat GPT, Cursor AI, Google AntiGravity를 활용해서 반응형 로그인 페이지를 만들어 보았습니다.
1편에서는 GPT·Cursor·AntiGravity가 로그인 페이지 코드를 생성하는 모습을 비교했고,
2편에서는 반응형 디자인과 레이아웃 확장을 통해 “AI가 단순 코드를 넘어 구조까지 조정할 수 있는지” 확인해 보았습니다.
이번 Part3에서는
- UI 디테일 조정
- 입문자·비전공자가 가장 어려워하는 개념 정리
- 세 AI의 실력 차이 분석
- 실제 서비스 품질에 가까운 로그인 페이지 완성하기
까지 진행해 볼까 합니다. 단순히 “로그인 화면을 만들어 본다”는 수준을 넘어서, 실제 서비스에 가까운 UI를 만들기 위해 어떤 디테일을 챙겨야 하는지, 그리고 GPT·Cursor·AntiGravity 중 어떤 AI가 어떤 상황에서 더 유리한지 입문자와 개발자 모두 쉽게 이해할 수 있도록 자세히 다뤄보겠습니다.오늘도 저 제로와 함께 달려봅시다.

본 이미지의 저작권은 블로그 주인 제로에게 있습니다.
[외부 링크] — AI 3종 바로가기
아래는 이번 실습에 사용된 AI 툴들의 공식 페이지 링크입니다.
각 도구는 특성이 다르므로 한 번씩 직접 체험해 보시면 차이를 더 명확히 느끼실 수 있습니다.
🔗 1. ChatGPT (GPT-4.1 / GPT-5.1)
🔗 2. Cursor AI (AI 기반 개발 IDE)
🔗 3. Google AntiGravity / Gemini 3.0
1. 이번 Part 3의 핵심 목표
Part 3의 목적은 다음 네 가지입니다.
1) 로그인 페이지를 “서비스 수준”으로 개선하기
단순한 코드가 아니라
- placeholder 색상
- input 포커스 효과
- 버튼 hover 스타일
- 모바일 반응형 UX
- 입력 오류 메시지 출력 구조
까지 아우르는 “실무형 UI”로 발전시킵니다.
2) 입문자·비개발자가 혼동하는 핵심 개념 정리
HTML/CSS가 처음이면 margin/padding, px/rem, flexbox 축처럼 기본 개념에서 자주 막히기 때문에 이번 편에서 확실히 잡아드립니다.
3) AI 도구 3종 비교
동일한 프롬프트를 입력했을 때 GPT, Cursor, AntiGravity의 반응이 어떻게 다른지 실전 개발 기준으로 분석합니다.
4) 스스로 확장 가능한 코드 구조 이해
다음 Part 4(JavaScript 기능 추가)로 자연스럽게 연결될 수 있게 코드 구조를 ‘확장 가능한 형태’로 구성합니다.
2. AI도구를 활용해보자.
AI에게 전달한 프롬프트
세 AI에게 아래와 같은 동일한 프롬프트를 입력했습니다.
“로그인 페이지 UI를 실제 서비스처럼 다듬어 주세요.
placeholder 개선, input focus 효과, hover 스타일, 모바일 반응형 포함.
HTML/CSS를 분리하고 구조적으로 확장 가능하게 만들어 주세요.”



각 AI가 만들어준 페이지 및 소스코드 비교
이제 각 AI가 만들어준 페이지를 빌드해서 눈으로 봐야겠죠? 바로 보도록 하겠습니다.
Tip) 커서는 본인이 띄워주기도 하고 Antigravity도 비슷한데. GPT는 어떻게 보나요?
-> VS Code 에 붙여넣고 로컬로 봅니다. (아래 링크를 참고하세요!)
[개발환경 입문] VS Code란? 입문자가 알아야 할 핵심 기능과 장점
[입문] HTML/CSS란? (프론트엔드 1편) – AI 시대, 기본을 아는 사람의 경쟁력
[입문] HTML/CSS 사용 (프론트엔드 2편) – 첫 웹페이지 만들기
GPT 제작 HTML 소스코드
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>로그인</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="login-wrapper">
<div class="login-container">
<h1 class="login-title">로그인</h1>
<form class="login-form">
<div class="form-group">
<input type="text" class="form-input" placeholder="아이디를 입력하세요" required />
</div>
<div class="form-group">
<input type="password" class="form-input" placeholder="비밀번호를 입력하세요" required />
</div>
<button type="submit" class="login-btn">로그인</button>
</form>
<div class="login-extra">
<a href="#" class="link">아이디 찾기</a>
<span class="divider">|</span>
<a href="#" class="link">비밀번호 찾기</a>
</div>
</div>
</div>
</body>
</html>
GPT 제작 HTML 소스코드 설명
✔ <div class="login-wrapper">
- 페이지 전체를 감싸는 최상단 컨테이너
- 가운데 정렬을 위한 구조
<body>
<div class="login-wrapper">
...
</div>
</body>
✔ <div class="login-container">
- 실제 로그인 박스의 UI를 감싸는 영역
- 흰색 박스, 그림자, 둥근 모서리 등 실제 서비스 형태의 카드 UI 역할
<div class="login-container">
...
</div>
✔ <h1 class="login-title">로그인</h1>
- 로그인 폼의 제목
- 크고 중앙 정렬됨
✔ <form class="login-form">
입력란(input)과 버튼(button)을 담는 폼 태그
이 안에 실제 로그인 기능이 들어가게 됨 (나중에 action=… 추가 가능)
✔ 입력창 2개 (ID / PW)
<div class="form-group">
<input type="text" class="form-input" placeholder="아이디를 입력하세요" required />
</div>
<div class="form-group">
<input type="password" class="form-input" placeholder="비밀번호를 입력하세요" required />
</div>
form-group: 입력창 하나를 담는 묶음form-input: 입력창 공통 스타일을 적용하기 위한 클래스placeholder: 흐리게 보이는 안내문구required: 반드시 입력해야 제출 가능한 HTML 기본 기능
✔ 로그인 버튼
<button type="submit" class="login-btn">로그인</button>
- 클릭하면 폼을 제출하는 버튼
- CSS로 hover, press 효과 추가됨
✔ 로그인 보조 링크 (아이디 찾기 등)
<div class="login-extra">
<a href="#" class="link">아이디 찾기</a>
<span class="divider">|</span>
<a href="#" class="link">비밀번호 찾기</a>
</div>
- “아이디 찾기”, “비밀번호 찾기” 같은 추가 메뉴
- 가운데 정렬한 simple footer 느낌 UI
GPT 제작 CSS 소스코드
/* 기본 스타일 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Noto Sans KR', sans-serif;
}
body {
background: #f5f6fa;
display: flex;
height: 100vh;
justify-content: center;
align-items: center;
}
/* 전체 wrapper */
.login-wrapper {
width: 100%;
padding: 20px;
display: flex;
justify-content: center;
}
/* 로그인 컨테이너 */
.login-container {
background: #ffffff;
width: 100%;
max-width: 380px;
padding: 40px 35px;
border-radius: 16px;
box-shadow: 0 8px 20px rgba(0,0,0,0.08);
}
/* 제목 */
.login-title {
text-align: center;
font-size: 26px;
margin-bottom: 30px;
font-weight: 600;
}
/* input 그룹 */
.form-group {
margin-bottom: 20px;
}
/* 입력창 */
.form-input {
width: 100%;
padding: 14px 16px;
font-size: 15px;
border: 1.5px solid #dcdde1;
border-radius: 10px;
transition: all 0.25s ease;
}
/* placeholder */
.form-input::placeholder {
color: #a5a5a5;
}
/* input focus 효과 */
.form-input:focus {
border-color: #4a88ff;
background: #f0f6ff;
outline: none;
box-shadow: 0 0 0 3px rgba(74,136,255,0.15);
}
/* 버튼 */
.login-btn {
width: 100%;
padding: 15px 0;
font-size: 16px;
font-weight: 600;
background: #4a88ff;
color: white;
border: none;
border-radius: 12px;
cursor: pointer;
transition: background 0.25s ease, transform 0.15s ease;
}
/* hover 효과 */
.login-btn:hover {
background: #3a73e8;
transform: translateY(-2px);
}
/* extra link */
.login-extra {
margin-top: 18px;
text-align: center;
font-size: 14px;
color: #777;
}
.login-extra .link {
text-decoration: none;
color: #4a88ff;
transition: color 0.2s ease;
}
.login-extra .link:hover {
color: #2d5fcc;
}
.divider {
margin: 0 6px;
color: #ccc;
}
/* 반응형 (모바일) */
@media (max-width: 480px) {
.login-container {
padding: 30px 25px;
border-radius: 12px;
}
.login-title {
font-size: 22px;
margin-bottom: 24px;
}
.form-input {
padding: 13px 14px;
font-size: 14px;
}
.login-btn {
padding: 13px 0;
font-size: 15px;
}
}
GPT 제작 CSS 소스코드 설명
✔ 전체 초기화
* { margin: 0; padding: 0; box-sizing: border-box; }
- 모든 브라우저에서 스타일이 다르게 보이지 않도록 기본 여백 제거
- box-sizing 설정으로 width 계산을 쉬움
✔ 배경(Body)
body {
background: #f5f6fa;
display: flex;
height: 100vh;
justify-content: center;
align-items: center;
}
- 페이지 전체를 세로/가로 가운데 정렬
- 부드러운 밝은 회색 배경
✔ 로그인 백그라운드 Wrapper
.login-wrapper {
width: 100%;
padding: 20px;
display: flex;
justify-content: center;
}
- 모바일에서 좌우 여백이 생기도록 패딩 적용
✔ 로그인 카드 UI
.login-container {
background: #ffffff;
max-width: 380px;
padding: 40px 35px;
border-radius: 16px;
box-shadow: 0 8px 20px rgba(0,0,0,0.08);
}
- 흰색 카드 스타일
- 둥근 모서리(서비스 UI 느낌)
- 그림자 효과로 떠보이는 느낌
- PC/모바일에서 크기 자동 조절
✔ 입력창 스타일
.form-input {
width: 100%;
padding: 14px 16px;
border: 1.5px solid #dcdde1;
border-radius: 10px;
transition: all 0.25s ease;
}
- 넓이 100% → 화면에 꽉 차게
- 부드러운 모서리
transition으로 부드러운 애니메이션 효과
✔ placeholder
.form-input::placeholder {
color: #a5a5a5;
}
- 연한 회색으로 UX 개선
✔ 입력창 focus(클릭) 시 효과
.form-input:focus {
border-color: #4a88ff;
background: #f0f6ff;
box-shadow: 0 0 0 3px rgba(74,136,255,0.15);
}
입력창 클릭하면
- 파란색 테두리
- 연파란 배경
- 약한 그림자
→ 실제 서비스 앱 같은 고급 UI 효과
✔ 로그인 버튼
.login-btn {
background: #4a88ff;
color: white;
border-radius: 12px;
}
✔ hover 효과
.login-btn:hover {
background: #3a73e8;
transform: translateY(-2px);
}
- 마우스를 올리면 버튼이 살짝 올라가는 느낌
→ 서비스 UI에서 흔히 쓰는 인터랙션
✔ 반응형 처리 (모바일)
@media (max-width: 480px) {
...
}
- 480px 이하(스마트폰)일 때 적용
- 패딩 축소
- 제목/글자 크기 축소
- 전체적으로 더 컴팩트하게
실제 서비스 모바일 화면처럼 자연스럽게 줄어듦.
GTP 생성 홈페이지 확인

본 이미지의 저작권은 블로그 주인 제로에게 있습니다.
Cursor 제작 HTML 소스코드
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="로그인 페이지">
<title>로그인</title>
<link rel="stylesheet" href="styles/login.css">
</head>
<body>
<div class="login-container">
<div class="login-wrapper">
<!-- 로고 영역 -->
<div class="login-header">
<h1 class="login-title">로그인</h1>
<p class="login-subtitle">서비스에 오신 것을 환영합니다</p>
</div>
<!-- 로그인 폼 -->
<form class="login-form" id="loginForm" novalidate>
<!-- 이메일/아이디 입력 -->
<div class="form-group">
<label for="email" class="form-label">이메일 또는 아이디</label>
<div class="input-wrapper">
<input
type="text"
id="email"
name="email"
class="form-input"
placeholder="이메일 또는 아이디를 입력하세요"
autocomplete="username"
required
aria-label="이메일 또는 아이디 입력"
>
<span class="input-icon email-icon" aria-hidden="true"></span>
</div>
<span class="error-message" id="emailError" role="alert"></span>
</div>
<!-- 비밀번호 입력 -->
<div class="form-group">
<label for="password" class="form-label">비밀번호</label>
<div class="input-wrapper">
<input
type="password"
id="password"
name="password"
class="form-input"
placeholder="비밀번호를 입력하세요"
autocomplete="current-password"
required
aria-label="비밀번호 입력"
>
<span class="input-icon password-icon" aria-hidden="true"></span>
<button
type="button"
class="password-toggle"
id="passwordToggle"
aria-label="비밀번호 표시/숨김"
tabindex="0"
>
<span class="eye-icon eye-open"></span>
</button>
</div>
<span class="error-message" id="passwordError" role="alert"></span>
</div>
<!-- 자동 로그인 및 비밀번호 찾기 -->
<div class="form-options">
<label class="checkbox-wrapper">
<input
type="checkbox"
id="rememberMe"
name="rememberMe"
class="checkbox-input"z
>
<span class="checkbox-label">자동 로그인</span>
</label>
<a href="#" class="forgot-password-link">비밀번호 찾기</a>
</div>
<!-- 로그인 버튼 -->
<button type="submit" class="login-button" id="loginButton">
<span class="button-text">로그인</span>
<span class="button-loader" aria-hidden="true"></span>
</button>
<!-- 소셜 로그인 구분선 -->
<div class="divider">
<span class="divider-text">또는</span>
</div>
<!-- 소셜 로그인 버튼들 -->
<div class="social-login">
<button type="button" class="social-button google-button" aria-label="구글로 로그인">
<span class="social-icon google-icon"></span>
<span class="social-text">Google로 로그인</span>
</button>
<button type="button" class="social-button naver-button" aria-label="네이버로 로그인">
<span class="social-icon naver-icon"></span>
<span class="social-text">Naver로 로그인</span>
</button>
<button type="button" class="social-button kakao-button" aria-label="카카오로 로그인">
<span class="social-icon kakao-icon"></span>
<span class="social-text">Kakao로 로그인</span>
</button>
</div>
<!-- 회원가입 링크 -->
<div class="signup-link-wrapper">
<span class="signup-text">계정이 없으신가요?</span>
<a href="#" class="signup-link">회원가입</a>
</div>
</form>
</div>
</div>
<script src="scripts/login.js"></script>
</body>
</html>
Cursor 제작 HTML 소스코드 설명
- 전체 레이아웃
- body 안에 login-container → login-wrapper 순으로 감싸는 구조입니다.
- 나중에 다른 페이지에도 같은 레이아웃을 재사용하기 쉽게 만든 “껍데기” 레벨입니다.
- 헤더 영역
- div.login-header
- h1.login-title : “로그인” 제목
- p.login-subtitle : “서비스에 오신 것을 환영합니다” 설명문
- 헤더만 따로 분리해 둔 이유는, 나중에 로고, 서브텍스트, 언어 선택 등을 쉽게 추가할 수 있게 하기 위해서입니다.
- 로그인 폼 (form#loginForm.login-form)
- 이메일/아이디 입력 그룹 (div.form-group)
- label.form-label + input#email.form-input
- span.input-icon.email-icon : 아이콘용 엘리먼트 (현재 CSS에서 숨김 처리, 필요시 다시 살릴 수 있음)
- span#errorEmail.error-message : 에러 메시지 출력용
- 비밀번호 입력 그룹
- label.form-label + input#password.form-input
- span.input-icon.password-icon
- button#passwordToggle.password-toggle : “눈 아이콘” 버튼, 비밀번호 표시/숨김
- span#errorPassword.error-message
- 옵션 영역 (div.form-options)
- input#rememberMe.checkbox-input + span.checkbox-label : 자동 로그인
- a.forgot-password-link : 비밀번호 찾기 링크
- 로그인 버튼
- button#loginButton.login-button
- 안에 span.button-text (텍스트), span.button-loader (로딩 스피너) 분리 → 나중에 JS로 상태 제어 용이
- 이메일/아이디 입력 그룹 (div.form-group)
- 소셜 로그인 영역 (div.social-login)
- button.social-button.google-button
- button.social-button.naver-button
- button.social-button.kakao-button
- 각 버튼 안에 span.social-icon + span.social-text 로 구성 → 아이콘/텍스트를 CSS·JS에서 쉽게 조작 가능.
- 회원가입 영역
- div.signup-link-wrapper
- span.signup-text + a.signup-link
- 로그인 아래에 항상 붙는 “회원가입 유도” 블록을 컴포넌트처럼 분리해 둔 형태입니다.
- 스크립트 연결
- 마지막에 scripts/login.js를 연결해서
- 비밀번호 표시/숨김
- 폼 검증
- 버튼 로딩 상태를 제어하게 되어 있습니다.
Cursor 제작 CSS 소스코드
/* ============================================
로그인 페이지 스타일시트
============================================ */
/* CSS 변수 정의 - 확장 가능한 구조 */
:root {
/* 색상 팔레트 */
--primary-color: #4F46E5;
--primary-hover: #4338CA;
--primary-active: #3730A3;
--secondary-color: #6366F1;
--success-color: #10B981;
--error-color: #EF4444;
--warning-color: #F59E0B;
/* 텍스트 색상 */
--text-primary: #1F2937;
--text-secondary: #6B7280;
--text-tertiary: #9CA3AF;
--text-inverse: #FFFFFF;
/* 배경 색상 */
--bg-primary: #FFFFFF;
--bg-secondary: #F9FAFB;
--bg-tertiary: #F3F4F6;
--bg-overlay: rgba(0, 0, 0, 0.5);
/* 테두리 색상 */
--border-default: #E5E7EB;
--border-focus: #4F46E5;
--border-error: #EF4444;
--border-hover: #D1D5DB;
/* 그림자 */
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
/* 간격 */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
--spacing-2xl: 3rem;
/* 폰트 크기 */
--font-xs: 0.75rem;
--font-sm: 0.875rem;
--font-base: 1rem;
--font-lg: 1.125rem;
--font-xl: 1.25rem;
--font-2xl: 1.5rem;
--font-3xl: 1.875rem;
/* 전환 효과 */
--transition-fast: 150ms ease-in-out;
--transition-base: 200ms ease-in-out;
--transition-slow: 300ms ease-in-out;
/* 테두리 반경 */
--radius-sm: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-xl: 1rem;
--radius-full: 9999px;
}
/* ============================================
기본 리셋 및 전역 스타일
============================================ */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 16px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
color: var(--text-primary);
background: var(--bg-secondary);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: var(--spacing-md);
line-height: 1.5;
}
/* ============================================
로그인 컨테이너
============================================ */
.login-container {
width: 100%;
max-width: 440px;
animation: fadeInUp 0.5s ease-out;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.login-wrapper {
background: var(--bg-primary);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-md);
padding: var(--spacing-2xl);
width: 100%;
max-width: 100%;
}
/* ============================================
헤더 영역
============================================ */
.login-header {
text-align: left;
margin-bottom: var(--spacing-2xl);
}
.login-title {
font-size: var(--font-3xl);
font-weight: 700;
color: var(--text-primary);
margin-bottom: var(--spacing-sm);
letter-spacing: -0.025em;
}
.login-subtitle {
font-size: var(--font-base);
color: var(--text-secondary);
font-weight: 400;
}
/* ============================================
폼 그룹
============================================ */
.login-form {
width: 100%;
}
.form-group {
margin-bottom: var(--spacing-lg);
}
.form-label {
display: block;
font-size: var(--font-sm);
font-weight: 500;
color: var(--text-primary);
margin-bottom: var(--spacing-sm);
letter-spacing: -0.01em;
}
/* ============================================
입력 필드 래퍼
============================================ */
.input-wrapper {
position: relative;
display: flex;
align-items: center;
}
.form-input {
width: 100%;
padding: 0.875rem 1rem 0.875rem 2.75rem;
font-size: var(--font-base);
color: var(--text-primary);
background-color: var(--bg-primary);
border: 2px solid var(--border-default);
border-radius: var(--radius-md);
outline: none;
transition: all var(--transition-base);
font-family: inherit;
}
/* Placeholder 스타일 개선 */
.form-input::placeholder {
color: var(--text-tertiary);
opacity: 1;
font-size: var(--font-sm);
transition: opacity var(--transition-fast);
}
.form-input:focus::placeholder {
opacity: 0.6;
}
/* Focus 효과 - 부드러운 전환과 그림자 */
.form-input:focus {
border-color: var(--border-focus);
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
outline: none;
transform: translateY(-1px);
}
.form-input:hover:not(:focus) {
border-color: var(--border-hover);
}
/* 에러 상태 */
.form-input.error {
border-color: var(--border-error);
}
.form-input.error:focus {
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}
/* 비활성화 상태 */
.form-input:disabled {
background-color: var(--bg-tertiary);
color: var(--text-tertiary);
cursor: not-allowed;
opacity: 0.6;
}
/* ============================================
입력 아이콘
============================================ */
.input-icon {
position: absolute;
left: 0.875rem;
width: 1.25rem;
height: 1.25rem;
pointer-events: none;
z-index: 1;
}
.email-icon::before {
content: '';
display: block;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%236B7280'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207'/%3E%3C/svg%3E");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
transition: opacity var(--transition-fast);
}
.form-input:focus ~ .input-icon.email-icon::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%234F46E5'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M16 12a4 4 0 10-8 0 4 4 0 008 0zm0 0v1.5a2.5 2.5 0 005 0V12a9 9 0 10-9 9m4.5-1.206a8.959 8.959 0 01-4.5 1.207'/%3E%3C/svg%3E");
}
.password-icon::before {
content: '';
display: block;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%236B7280'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z'/%3E%3C/svg%3E");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.form-input:focus ~ .input-icon.password-icon::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%234F46E5'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z'/%3E%3C/svg%3E");
}
/* ============================================
비밀번호 표시/숨김 토글
============================================ */
.password-toggle {
position: absolute;
right: 0.875rem;
background: none;
border: none;
cursor: pointer;
padding: var(--spacing-xs);
display: flex;
align-items: center;
justify-content: center;
color: var(--text-secondary);
transition: color var(--transition-fast);
z-index: 1;
}
.password-toggle:hover {
color: var(--text-primary);
}
.password-toggle:focus {
outline: 2px solid var(--border-focus);
outline-offset: 2px;
border-radius: var(--radius-sm);
}
.eye-icon {
width: 1.25rem;
height: 1.25rem;
display: block;
}
.eye-open::before {
content: '';
display: block;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%236B7280'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M15 12a3 3 0 11-6 0 3 3 0 016 0z'/%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z'/%3E%3C/svg%3E");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.eye-icon.eye-closed::before {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%236B7280'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.29 3.29m0 0L3 10.29m3.29-3.29l13.29 13.29M10.29 21l3.29-3.29m0 0l3.29 3.29M21 21l-3.29-3.29m0 0L21 13.71'/%3E%3C/svg%3E");
}
/* ============================================
에러 메시지
============================================ */
.error-message {
display: block;
font-size: var(--font-xs);
color: var(--error-color);
margin-top: var(--spacing-xs);
min-height: 1.25rem;
opacity: 0;
transform: translateY(-4px);
transition: all var(--transition-base);
}
.error-message.show {
opacity: 1;
transform: translateY(0);
}
/* ============================================
폼 옵션 (자동 로그인, 비밀번호 찾기)
============================================ */
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-xl);
font-size: var(--font-sm);
}
.checkbox-wrapper {
display: flex;
align-items: center;
cursor: pointer;
user-select: none;
}
.checkbox-input {
width: 1rem;
height: 1rem;
margin-right: var(--spacing-sm);
cursor: pointer;
accent-color: var(--primary-color);
transition: transform var(--transition-fast);
}
.checkbox-input:hover {
transform: scale(1.1);
}
.checkbox-label {
color: var(--text-secondary);
font-size: var(--font-sm);
cursor: pointer;
}
.forgot-password-link {
color: var(--primary-color);
text-decoration: none;
font-size: var(--font-sm);
font-weight: 500;
transition: color var(--transition-fast);
}
.forgot-password-link:hover {
color: var(--primary-hover);
text-decoration: underline;
}
.forgot-password-link:focus {
outline: 2px solid var(--border-focus);
outline-offset: 2px;
border-radius: var(--radius-sm);
}
/* ============================================
로그인 버튼
============================================ */
.login-button {
width: 100%;
padding: 0.875rem 1.5rem;
font-size: var(--font-base);
font-weight: 600;
color: var(--text-inverse);
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
border: none;
border-radius: var(--radius-md);
cursor: pointer;
transition: all var(--transition-base);
position: relative;
overflow: hidden;
margin-bottom: var(--spacing-lg);
box-shadow: var(--shadow-md);
font-family: inherit;
letter-spacing: -0.01em;
}
.login-button::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
transition: left var(--transition-slow);
}
.login-button:hover::before {
left: 100%;
}
.login-button:hover {
background: linear-gradient(135deg, var(--primary-hover) 0%, #5B52E8 100%);
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
.login-button:active {
transform: translateY(0);
box-shadow: var(--shadow-md);
}
.login-button:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.3), var(--shadow-lg);
}
.login-button:disabled {
background: var(--bg-tertiary);
color: var(--text-tertiary);
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.login-button:disabled::before {
display: none;
}
.button-loader {
display: none;
width: 1rem;
height: 1rem;
border: 2px solid rgba(255, 255, 255, 0.3);
border-top-color: var(--text-inverse);
border-radius: 50%;
animation: spin 0.6s linear infinite;
margin-left: var(--spacing-sm);
}
.login-button.loading .button-text {
opacity: 0.7;
}
.login-button.loading .button-loader {
display: inline-block;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* ============================================
구분선
============================================ */
.divider {
display: flex;
align-items: center;
text-align: center;
margin: var(--spacing-xl) 0;
color: var(--text-tertiary);
font-size: var(--font-sm);
}
.divider::before,
.divider::after {
content: '';
flex: 1;
border-bottom: 1px solid var(--border-default);
}
.divider-text {
padding: 0 var(--spacing-md);
}
/* ============================================
소셜 로그인 버튼
============================================ */
.social-login {
display: flex;
flex-direction: column;
gap: var(--spacing-sm);
margin-bottom: var(--spacing-xl);
}
.social-button {
width: 100%;
padding: 0.75rem 1rem;
font-size: var(--font-sm);
font-weight: 500;
color: var(--text-primary);
background: var(--bg-primary);
border: 2px solid var(--border-default);
border-radius: var(--radius-md);
cursor: pointer;
transition: all var(--transition-base);
display: flex;
align-items: center;
justify-content: center;
gap: var(--spacing-sm);
font-family: inherit;
position: relative;
overflow: hidden;
}
.social-button::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(0, 0, 0, 0.05);
transform: translate(-50%, -50%);
transition: width 0.3s ease, height 0.3s ease;
}
.social-button:hover::before {
width: 300px;
height: 300px;
}
.social-button:hover {
border-color: var(--border-hover);
box-shadow: var(--shadow-sm);
transform: translateY(-1px);
}
.social-button:active {
transform: translateY(0);
}
.social-button:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
}
.social-icon {
width: 1.25rem;
height: 1.25rem;
display: block;
flex-shrink: 0;
}
.google-icon::before {
content: '';
display: block;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%234285F4' d='M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z'/%3E%3Cpath fill='%2334A853' d='M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z'/%3E%3Cpath fill='%23FBBC05' d='M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z'/%3E%3Cpath fill='%23EA4335' d='M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z'/%3E%3C/svg%3E");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.naver-icon::before {
content: '';
display: block;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%2303C75A' d='M16.273 12.845L7.376 0H0v24h7.726V11.156L16.624 24H24V0h-7.727v12.845z'/%3E%3C/svg%3E");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.kakao-icon::before {
content: '';
display: block;
width: 100%;
height: 100%;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000000' d='M12 3C6.48 3 2 6.48 2 10.8c0 2.64 1.8 4.98 4.5 6.3L5.4 21l4.2-2.4c.6.1 1.2.1 1.8.1 5.52 0 10-3.48 10-7.8S17.52 3 12 3z'/%3E%3C/svg%3E");
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.social-text {
position: relative;
z-index: 1;
}
/* ============================================
회원가입 링크
============================================ */
.signup-link-wrapper {
text-align: left;
font-size: var(--font-sm);
color: var(--text-secondary);
}
.signup-text {
margin-right: var(--spacing-xs);
}
.signup-link {
color: var(--primary-color);
text-decoration: none;
font-weight: 600;
transition: color var(--transition-fast);
}
.signup-link:hover {
color: var(--primary-hover);
text-decoration: underline;
}
.signup-link:focus {
outline: 2px solid var(--border-focus);
outline-offset: 2px;
border-radius: var(--radius-sm);
}
/* ============================================
모바일 반응형 스타일
============================================ */
@media (max-width: 640px) {
:root {
--spacing-2xl: 2rem;
}
body {
padding: var(--spacing-sm);
align-items: flex-start;
padding-top: var(--spacing-xl);
}
.login-wrapper {
padding: var(--spacing-xl) var(--spacing-lg);
border-radius: var(--radius-lg);
}
.login-title {
font-size: var(--font-2xl);
}
.login-subtitle {
font-size: var(--font-sm);
}
.form-input {
padding: 0.75rem 0.875rem 0.75rem 2.5rem;
font-size: var(--font-sm);
}
.input-icon {
left: 0.75rem;
width: 1.125rem;
height: 1.125rem;
}
.login-button {
padding: 0.75rem 1.25rem;
font-size: var(--font-sm);
}
.social-button {
padding: 0.625rem 0.875rem;
font-size: var(--font-xs);
}
.form-options {
flex-direction: column;
align-items: flex-start;
gap: var(--spacing-sm);
}
.forgot-password-link {
align-self: flex-end;
}
}
@media (max-width: 480px) {
.login-wrapper {
padding: var(--spacing-lg) var(--spacing-md);
}
.login-title {
font-size: var(--font-xl);
}
.social-login {
gap: var(--spacing-xs);
}
}
/* ============================================
접근성 개선
============================================ */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* ============================================
다크 모드 지원 (선택적)
============================================ */
@media (prefers-color-scheme: dark) {
:root {
--text-primary: #F9FAFB;
--text-secondary: #D1D5DB;
--text-tertiary: #9CA3AF;
--bg-primary: #1F2937;
--bg-secondary: #111827;
--bg-tertiary: #374151;
--border-default: #374151;
--border-hover: #4B5563;
}
body {
background: linear-gradient(135deg, #1F2937 0%, #111827 100%);
}
}
Cursor 제작 CSS 소스코드 설명
- 전역 설정과 테마 변수
- :root
- 색상, 폰트 크기, 간격, 그림자, border-radius, transition을 전부 CSS 변수로 선언해 둔 부분입니다.
- 예: –primary-color, –bg-primary, –font-sm, –shadow-md …
- 나중에 다른 브랜드 컬러로 교체할 때 변수만 바꾸면 전체 테마가 바뀜.
- 다크 모드, 브랜드 A/B 테스트 등에 바로 대응 가능.
- :root
- 리셋 & 전역 스타일
- * { margin:0; padding:0; box-sizing:border-box; }
- body 전역 폰트/배경/라인하이트 설정.
- body에서 display:flex; align-items:center; justify-content:center;로 페이지 중앙에 카드 형태의 로그인 박스를 위치시킵니다.
- 레이아웃 관련
- login-container / login-wrapper
- login-container : 최대 너비를 제한 (max-width: 440px)
- login-wrapper
- 흰색 배경(–bg-primary), 둥근 모서리, 그림자(–shadow-md)로 카드 느낌
- 내부 패딩을 넉넉히 줘서 폼들이 붙어 보이지 않게 함
- 헤더 (login-header, login-title, login-subtitle)
- login-header : 제목/설명을 한 블록으로 묶어 margin 하단 부여
- login-title : 굵은 글씨 + 큰 폰트
- login-subtitle : 흐린 회색 텍스트로 보조 설명 느낌
- 입력 필드 UI
- .form-group / .form-label
- 그룹마다 margin-bottom을 줘서 세로 간격을 통일
- .form-label은 작은 글씨 + 약간 굵게 → 가독성 좋게
- .input-wrapper & .form-input
- .input-wrapper : input/아이콘/토글버튼을 한 줄에 정렬하는 래퍼
- .form-input :
- width 100%, 패딩, border-radius, 1px 테두리
- :focus 시 border 색을 –border-focus로 바꾸고 살짝 그림자를 줘서 집중된 상태를 명확히 보여줌
- ::placeholder : 회색, 작은 폰트, focus 시 투명도 변경
- 에러/비활성 상태
- .form-input.error : 빨간 테두리(–border-error)
- .error-message :
- 기본은 opacity:0 + 살짝 위로 올라간 상태
- .show 클래스가 붙으면 opacity:1 + 위치 내려감 → 부드러운 에러 표시 애니메이션
- 입력 아이콘 / 비밀번호 토글
- .input-icon : 원래는 왼쪽 아이콘용인데, 현재는 display:none; 처리 (심플한 스타일을 위해 숨김)
- .password-toggle :
- input 오른쪽에 있는 버튼
- .eye-icon에 eye-open / eye-closed 클래스를 토글해서 SVG 아이콘을 바꿈
- 옵션 영역 & 링크
- 자동 로그인 + 비밀번호 찾기 (form-options)
- display:flex; justify-content:space-between;
- 체크박스(.checkbox-input)는 accent-color로 기본 브라우저 체크 스타일을 최소한으로 꾸밈.
- 비밀번호 찾기 링크(.forgot-password-link)는 메인 컬러로 표시, hover 시 밑줄.
- 자동 로그인 + 비밀번호 찾기 (form-options)
- 회원가입 영역 (signup-link-wrapper)
- 작은 글자 + 기본 회색
- 회원가입 링크는 메인 컬러, hover 시 색 진하게 + 밑줄
- 버튼 스타일
- .login-button
- 전체 너비, 적당한 높이, border-radius
- 배경은 –bg-secondary(연한 회색), hover 시 –bg-tertiary로 살짝 진하게
- JS에서 .loading 클래스를 붙이면 button-loader가 보이고, 텍스트 투명도 조정.
- 소셜 버튼 (.social-login, .social-button)
- .social-login : display:flex; flex-direction:row; justify-content:space-between;
- 세 개의 버튼을 가로로 나란히 배치
- .social-button :
- flex:1 로 너비를 균등 분배
- 얇은 테두리 + 연한 배경
- hover 시 배경만 살짝 진하게 (심플한 스타일)
- .google-icon, .naver-icon, .kakao-icon :
- 각 서비스의 로고를 인라인 SVG data URL로 넣어, 별도 이미지 파일 없이 아이콘 표현
- 반응형 & 접근성
- 반응형 (@media (max-width: 640px / 480px))
- 모바일에서
- login-wrapper 패딩 축소
- 제목/글자 크기 줄이기
- 소셜 버튼 간격/패딩 조정
- form-options를 세로 방향으로 재배치
- 접근성
- prefers-reduced-motion 지원: 애니메이션/트랜지션을 최소화
- prefers-color-scheme: dark에서 기본 색상 팔레트를 다크톤으로 변경 (다크 모드 지원)
Cursor 제작 홈페이지

본 이미지의 저작권은 블로그 주인 제로에게 있습니다.
AntiGravity 제작 HTML 소스코드
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>로그인</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="login-container">
<div class="login-header">
<h2>환영합니다</h2>
<p>서비스 이용을 위해 로그인해주세요</p>
</div>
<form class="login-form">
<div class="input-group">
<input type="text" id="username" name="username" placeholder=" " required>
<label for="username">아이디</label>
</div>
<div class="input-group">
<input type="password" id="password" name="password" placeholder=" " required>
<label for="password">비밀번호</label>
</div>
<button type="submit" class="login-btn">로그인</button>
</form>
</div>
</body>
</html>
AntiGravity 제작 HTML 소스코드 설명
HTML은 의미론적(Semantic) 구조와 접근성, 그리고 확장성을 고려하여 작성되었습니다.
- 컨테이너 구조 (
.login-container):- 화면 중앙에 카드를 배치하기 위한 최상위 래퍼입니다.
- 내부에 헤더(
login-header)와 폼(login-form)을 분리하여 구조를 명확히 했습니다.
- 플로팅 라벨 패턴 (
.input-group):input과label을 하나의 그룹으로 묶었습니다.- 중요:
input을label보다 먼저 배치했습니다. 이는 CSS의+(인접 형제 선택자)를 사용하여 입력 필드의 상태(포커스 등)에 따라
라벨의 스타일을 변경하기 위함입니다. placeholder=" "(공백): 브라우저가placeholder-shown상태를 감지할 수 있도록 의도적으로 공백을 넣었습니다.
이를 통해 “입력값이 없을 때”와 “있을 때”를 CSS로 구분합니다.
AntiGravity 제작 CSS 소스코드
/* Modern Reset & Variables */
:root {
--primary-color: #4f46e5;
--primary-hover: #4338ca;
--bg-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
--glass-bg: rgba(255, 255, 255, 0.95);
--text-color: #1f2937;
--text-light: #6b7280;
--error-color: #ef4444;
--success-color: #10b981;
--border-radius: 16px;
--transition: all 0.3s ease;
--shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: var(--bg-gradient);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
/* Login Container */
.login-container {
width: 100%;
max-width: 400px;
background: var(--glass-bg);
backdrop-filter: blur(10px);
border-radius: var(--border-radius);
box-shadow: var(--shadow);
padding: 40px;
animation: slideUp 0.5s ease-out;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.login-header {
text-align: center;
margin-bottom: 32px;
}
.login-header h2 {
color: var(--text-color);
font-size: 28px;
font-weight: 700;
margin-bottom: 8px;
}
.login-header p {
color: var(--text-light);
font-size: 14px;
}
/* Form Elements */
.input-group {
position: relative;
margin-bottom: 24px;
}
.input-group input {
width: 100%;
padding: 16px;
border: 2px solid #e5e7eb;
border-radius: 12px;
font-size: 16px;
color: var(--text-color);
background: transparent;
transition: var(--transition);
outline: none;
}
.input-group label {
position: absolute;
left: 16px;
top: 50%;
transform: translateY(-50%);
color: var(--text-light);
font-size: 16px;
pointer-events: none;
transition: var(--transition);
background: var(--glass-bg);
padding: 0 4px;
}
/* Floating Label Effect */
.input-group input:focus,
.input-group input:not(:placeholder-shown) {
border-color: var(--primary-color);
}
.input-group input:focus+label,
.input-group input:not(:placeholder-shown)+label {
top: 0;
font-size: 12px;
color: var(--primary-color);
font-weight: 600;
}
/* Button */
.login-btn {
width: 100%;
padding: 16px;
background: var(--primary-color);
color: white;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: var(--transition);
box-shadow: 0 4px 6px -1px rgba(79, 70, 229, 0.2);
}
.login-btn:hover {
background: var(--primary-hover);
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(79, 70, 229, 0.3);
}
.login-btn:active {
transform: translateY(0);
}
/* Mobile Responsiveness */
@media (max-width: 480px) {
.login-container {
padding: 32px 24px;
}
.login-header h2 {
font-size: 24px;
}
}
AntiGravity 제작 CSS 소스코드 설명
최신 CSS 기능을 활용하여 프리미엄 디자인(Glassmorphism)과 반응형, 애니메이션을 구현했습니다.
- CSS 변수 (
:root):- 색상, 그림자, 테두리 반경 등을 변수로 정의하여 유지보수가 쉽고 테마 변경이 용이하도록 설계했습니다.
--bg-gradient: 배경에 그라데이션을 적용하여 깊이감을 주었습니다.
- 글래스모피즘 (Glassmorphism):
.login-container에background: rgba(255, 255, 255, 0.95)와backdrop-filter: blur(10px)를 사용하여 마치
유리에 비친 듯한 흐릿하고 투명한 효과를 냈습니다.
- 중앙 정렬:
body에display: flex,justify-content: center,align-items: center를 사용하여 로그인 카드가 항상 화면 정중앙에
오도록 했습니다.
- 인터랙티브 애니메이션:
- 플로팅 라벨:css.input-group input:focus + label,
.input-group input:not(:placeholder-shown) + label { … }입력창을 클릭하거나(:focus) 내용이 있을 때(:not(:placeholder-shown)), 라벨이 위로 올라가고(top: 0) 작아지는(font-size: 12px) 애니메이션을 구현했습니다. - 등장 애니메이션:
@keyframes slideUp을 사용하여 페이지 로드 시 카드가 부드럽게 위로 떠오르는 효과를 주었습니다. - 버튼 효과: 마우스를 올리면(
:hover) 버튼이 살짝 위로 떠오르며 그림자가 진해지는 입체적인 효과를 추가했습니다.
- 플로팅 라벨:css.input-group input:focus + label,
- 모바일 반응형 (
@media):- 480px 이하의 작은 화면에서는 패딩을 줄여 공간을 확보하고, 폰트 크기를 조절하여 가독성을 유지했습니다.
AntiGravity 제작 홈페이지

본 이미지의 저작권은 블로그 주인 제로에게 있습니다.
AI 반응 정리
| AI | 특징 | 사용 추천 |
|---|---|---|
| GPT | 설명이 뛰어나고 입문자 친화적. 안정적 코드. | 처음 배우는 사람 / 튜토리얼 |
| Cursor | 유지보수가 쉬운 구조적 코드 생성. 실무형. | 개발자 / 프로젝트 실사용 |
| AntiGravity | 매우 빠름. 단순한 화면 구성에 유리. | 프로토타입 / 빠른 시안 제작 |
입문자에게는 GPT, 실무자에게는 Cursor, 빠른 실행에는 AntiGravity가 고효율입니다.
Tip) 제가 의도한 것이 아니었지만 Cursor는 Js 파일까지 생성했습니다. 똑같은 프롬프트지만 생산하는 결과물이 다릅니다.
Tip) 소스코드 설명 문체 또한 AI를 비교하기 위해 있는 그대로를 가져왔습니다. 설명하는 문체 또한 서로 다릅니다.
3. 입문자·비전공자를 위한 핵심 개념 해설
HTML/CSS를 배우는 가장 큰 장벽은 “기본 개념이 너무 추상적”이라는 점입니다.
이번 Part에서는 진짜 꼭 필요한 다섯 개념만 선별해 간단하게 정리했습니다.
✔ (1) margin vs padding
| 구분 | 의미 | 예시 |
|---|---|---|
| padding | 내부 여백 | input 내부 텍스트 간격 |
| margin | 외부 간격 | input과 버튼 사이 간격 |
👉 UI가 붙어보이거나 답답하면 padding
👉 요소끼리 너무 붙어 있으면 margin
Cursor는 margin/padding 최적화를 매우 잘합니다.
✔ (2) px, em, rem 차이
| 단위 | 기준 | 특징 |
|---|---|---|
| px | 고정 크기 | 입문자에게 쉬움 |
| em | 부모 기준 | 상대적이라 다소 헷갈림 |
| rem | 브라우저 기본 | 반응형에 가장 안정적 |
GPT는 rem 기반 코드를 자주 생성합니다.
✔ (3) 반응형 단위 %, vw, vh
- % : 부모 크기 기준
- vw/vh : 화면(뷰포트) 기준
- 모바일 UI 구성 시 매우 중요
✔ (4) flexbox 핵심
- 가로 방향(default) 정렬
flex-direction: column→ 세로 정렬justify-content: 메인축align-items: 보조축
로그인 페이지는 대부분 column 구조입니다.
✔ (5) media query 작동 방식
@media (max-width: 480px) {
...
}
✔ 화면이 480px 이하일 때만 적용되는 조건문
✔ 모바일 UI가 깨지지 않게 하는 핵심 기술
✔ AntiGravity는 media query 반영 속도가 매우 빠름
4. AI를 더 잘 활용하는 3가지 프롬프트
✔ ① 구조 분석 요청
아래 코드의 문제점과 개선점을 개발자 관점에서 분석해 주세요.
→ Cursor AI가 가장 잘함
✔ ② 초보자 설명 요청
이 코드를 비전공자도 이해할 수 있게 쉽게 설명해 주세요.
→ GPT가 압도적으로 잘함
✔ ③ 기능 추가 요청
비밀번호 보이기/숨기기 기능을 JS로 추가해 주세요.
→ AntiGravity가 빠름
5. Part 3를 마치며
이번 Part 3까지 오셨다면, “AI가 만든 코드를 그대로 사용하는 단계”를 넘어
AI가 생성한 코드를 내가 원하는 형태로 다듬고 해석하는 능력까지 갖추신 것입니다.
이 능력은 단순한 스킬을 넘어 앞으로 웹개발, 부업 디자인, 프론트엔드, 블로그 제작 등 거의 모든 디지털 작업에 활용됩니다.
특히 GPT·Cursor·AntiGravity의 성격 차이를 이해하면,
‘어떤 작업을 어떤 AI에 맡겨야 효율적인지’ 판단하는 실력이 확실히 올라갑니다.
다음 편 예고
다음 Part 4에서는 드디어
✔ 입력 검증
✔ 아이디 저장(localStorage)
✔ 비밀번호 토글
✔ 오류 메시지 출력
같은 실제 기능 구현(JavaScript) 에 들어갑니다. 많은 기대 부탁드립니다!