국민은행 액티브 시니어 온보딩 페이지 바로가기
GitHub 바로가기
목차
01. 챌린지 시작
02. 프로젝트 방향성
03. 개발조건
04. 코드 설명
05. 프로젝트 기획기간 인터렉티브 버튼 모음 제작
06. 마치며
기획자, 디자이너와 협업하는 것에 관심이 많아, 넘블이 주최한 '액티브 시니어를 위한 금융 앱 온보딩 페이지 제작 챌린지'에 참여했습니다.
기획자 2명, 디자이녀 1명, 프론트엔드 개발자인 저 4명이 한팀이 되어 프로젝트를 진행하였고, 액티브 시니어를 타겟으로 금융 앱 온보딩 페이지를 제작하라는 미션을 받았습니다.
기획자가 보는 웹, 디자이너가 보는 웹이 저와 어떤 차이가 있는지 궁금했고, 그런 다른 시각에서 시너지 효과가 날 수 있을 것이란 기대로 참여하게 되었습니다.
챌린지에 들어가기 앞서 이번 프로젝트에서 얻어가려 했던 부분은 협업이었습니다.
개발의 관점에서는 누가 보더라도 최대한 깔끔하게 이해할 수 있는 코드를 작성해보는 것,
팀원들과는 공유가 어렵지 않도록 하고, 다른 관점을 이해하고 그것이 프로젝트에 잘 담아지도록 노력하였습니다.
디자이너, 기획자와 함께 프로젝트를 하는 만큼,
기획과 디자인이 잘 보일 수 있는 방향으로 최대한 노력하였고, 공유가 원활할 수 있는 환경을 제공하고자 하였습니다.
코드를 작성에서 가장 중요하게 고려한 점은 다른 사람이 제 코드를 봤을 때 쉽게 이해할 수 있도록 작성해 보는 것 이었습니다.
애니메이션과 아이콘을 활용하여, 사용자의 반응 유도
작은 요소들이 많은 페이지였습니다. 각각을 디자이너가 요청한 위치, 시간대에 넣는 작업을 하며, 현실과 타협했던 디자인에서 벗어나 꼼꼼하게 페이지를 구현하는 경험을 할 수 있었습니다.
또한 lottie, 애니메이션등 시각적으로 새로운 형태를 구현해볼 수 있었습니다.
영상 및 애니메이션을 활용하여, 사용자가 직접 영상통화를 체험하는 듯한 경험 제공
영상, 대화 글귀, 버튼 등 컴포넌트들이 보여지는 타이밍을 맞추는 작업을 중점적으로 하였습니다.
추후, 영상의 로딩 시간을 단축시키고 성능을 향상시키고 싶습니다.
기능별, 페이지별 자동으로 넘어가는 것이 많은 페이지
최대한 자연스럽고 부드럽게 보여지도록 표현
편리성과 마찬가지로 자동으로 넘어가고 보여지는 페이지가 많은 페이지였습니다.
깃 페이지스를 활용하여 소통하고 수정하는 작업을 진행하며 디자이너와 더 깊이있는 협업을 진행 할 수 있던 페이지였습니다.
애니메이션과 아이콘을 활용하여, 사용자의 반응 유도
앞의 페이지들을 제작하며 수월하게 작업할 수 있었습니다. 이 부분도 마찬가지로 자동 스크롤이 올라가는 시간을 디자이너와 협업하며 제작할 수 있는 페이지였습니다.
애니메이션과 아이콘을 활용하여, 사용자의 반응 유도
제작 막바지에 전체적인 수정이 진행되었던 페이지입니다. 많이 남지 않은 시간으로 팀원들과 우선순위를 정하며 제작 하였습니다. 완성도에 대한 동료의 입장차와 이를 조율하는 과정을 경험할 수 있던 페이지였습니다.
스위치 아이콘을 제작하여, 사용자의 기능 인지 유도
스위치에 선택 시 안정적이지 못한 형태와, 아이콘이 있을 때 스위치가 안먹히는 에러 등 문제를 가장 많이 만났던 페이지입니다.
처음에는 완전한 기능의 스위치을 제작하였지만, 온보딩 페이지에 스위치를 켰다 컸다 하는 것이 유저 경험으로 좋지 않다는 판단되어, 스위치 클릭시 완료로 넘어가는 형식으로 다시 구현하였습니다.
//-- 애니메이션 --//
const fadeIn = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
transform: translateY(0);
}
`;
//-- 스타일 --//
const MainImageContainer = styled.div`
animation-duration: 0.75s;
animation-timing-function: ease-in-out;
animation-name: ${fadeIn};
animation-fill-mode: forwards;
`;
//-- 애니메이션 --//
const opacity = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`;
//-- 스타일 --//
const PortfolioContainer = styled.div`
position: absolute;
top: 32px;
left: 50%;
transform: translateX(-50%);
width: 312px;
height: 296px;
overflow: hidden;
z-index: 1;
div {
display: flex;
justify-content: center;
margin-top: 20px;
overflow: hidden;
}
animation-duration: 0.75s;
animation-timing-function: ease-in-out;
animation-name: ${opacity};
animation-fill-mode: backwards;
`;
// CSS
import styled from 'styled-components';
// 로티 에니메이션
import Lottie from 'lottie-react';
import click from '../assets/lottie/click.json';
const ClickIcon = styled.div`
position: absolute;
width: 200px;
left: 50%;
top: ${(props) => props.top};
transform: ${(props) => props.transform};
z-index: 5;
`;
const Click = ({ onClick, top, transform }) => {
return (
<>
<ClickIcon top={top} transform={transform}>
<Lottie
animationData={click}
loop={true}
style={{ width: 200 }}
onClick={onClick}
/>
</ClickIcon>
</>
);
};
export default Click;
- setInterval을 통해서 지정된 시간마다 txt에서 값을 받아와, 한 글자씩 넣어주는 로직을 구현하였습니다.
const Typing = styled.p`
font-family: 'Bold';
font-size: 21px;
line-height: 26px;
letter-spacing: -0.02em;
color: #222222;
`;
const TypingText = () => {
const txt = '노후연금 추천해줘';
const [isTypingTime, setIsTypingTime] = useState(false);
const [Text, setText] = useState('');
const [Count, setCount] = useState(0);
// 타이핑 시작 타이밍
useEffect(() => {
const timeout = setTimeout(() => {
setIsTypingTime(true);
}, 900);
return () => {
clearTimeout(timeout);
};
}, [isTypingTime]);
// 타이핑 속도
useEffect(() => {
if (isTypingTime) {
const interval = setInterval(() => {
setText(Text + txt[Count]);
setCount(Count + 1);
}, 260);
if (Count === txt.length) {
clearInterval(interval);
}
return () => clearInterval(interval);
}
});
return <>{isTypingTime === true && <Typing>{Text}</Typing>}</>;
};
const ReactSwitchButton = styled.span`
content: '';
position: absolute;
top: 2px;
left: 2px;
width: 45px;
height: 45px;
border-radius: 45px;
transition: 0.2s;
background: #fff;
box-shadow: 0 0 2px 0 rgba(10, 10, 10, 0.29);
`;
const ReactSwitchLabel = styled.label`
display: flex;
align-items: center;
justify-content: space-between;
width: 100px;
height: 50px;
background: grey;
border-radius: 100px;
position: relative;
transition: background-color 0.2s;
cursor: pointer;
&:active ${ReactSwitchButton} {
width: 60px;
}
`;
const ReactSwitchCheckbox = styled.input`
height: 0;
width: 0;
visibility: hidden;
&:checked + ${ReactSwitchLabel} {
background: rgb(254, 244, 148, 0.777);
${ReactSwitchButton} {
left: calc(100% - 2px);
transform: translateX(-100%);
}
}
`;
const Switch = () => {
const [value, setValue] = useState(false);
return (
<ButtonContainer>
<ReactSwitchCheckbox
id={`react-switch-new`}
type="checkbox"
checked={value}
onChange={() => {
setValue(!value);
}}
/>
<ReactSwitchLabel htmlFor={`react-switch-new`}>
<ReactSwitchButton />
</ReactSwitchLabel>
</ButtonContainer>
);
};
const ButtonSlide = keyframes`
from {
}
to {
left: calc(100%);
transform: translateX(-100%);
background-color: #f5bf41;
}
`;
const SwitchButton = styled.span`
content: '';
position: absolute;
left: 2px;
width: 24px;
height: 24px;
border-radius: 45px;
background: #888e98;
box-shadow: 5px 5px 12px rgba(144, 145, 146, 0.2);
${(props) =>
props.isChecked &&
css`
animation-duration: 0.2s;
animation-timing-function: ease-in;
animation-name: ${ButtonSlide};
animation-fill-mode: forwards;
`}
`;
const SwitchLabel = styled.div`
position: relative;
display: flex;
align-items: center;
justify-content: space-between;
width: 48px;
height: 16px;
background-color: ${(props) => (props.isChecked ? '#FAE585' : '#EFF1F3')};
border-radius: 100px;
transition: background-color 0.2s;
cursor: pointer;
`;
const ToggleButton = ({ isChecked }) => {
return (
<>
<SwitchLabel isChecked={isChecked}>
<SwitchButton isChecked={isChecked} />
</SwitchLabel>
</>
);
};
저는 기획 기간동안 개발자로서 제 할일을 찾기 시작했습니다. 그 결과 기획 기간 동안, 필요한 기능들을 구현해보고자 하였고, 그렇게 만들어진 것이 인터렉티브 버튼 모음이라는 미니프로젝트 입니다.
스위치 | 드래그 앤 드롭 |
---|---|
라이브러리 사용하지 않음 반응이 잘 표현되도록 스위치 제작 | react-beautiful-dnd 활용 제작 |
드롭 리스트 | 캐러셀 |
---|---|
react-beautiful-dnd 활용 제작 | 라이브러리 사용하지 않음 반응이 잘 표현되도록 스위치 제작 |
하나의 프로젝트에 얼마나 많은 사람들의 고민과 생각, 진심이 녹아있는지 다시금 깨달을 수 있었던 프로젝트였습니다.
프로젝트를 개발을 하는 동안, 좋은 생각과 디자인이 모인 집합체를 구현하는 것이 얼마나 매력적인가 생각이 들었고, 개발자가 꼭 되고 싶다고 생각했습니다.