[준승's portfolio] 3차 배포 스프린트

황준승·2022년 10월 25일
0
post-thumbnail

🌈 구현 기간
기간 1 : (스크롤 시 페이드인 효과 구현) 2022.09.23 ~ 2022.09.26,
기간 2 : (모바일 반응형 구현) 2022.10.23 ~ 2022.10.25

🌈 배포
https://hwjs-portfolio.vercel.app/

🌈 기능 추가
1. 스크롤 시 페이드인 효과 구현
2. 모바일 반응형 구현
3. 기본 폰트 변경

📌 주요 기능

1. 페이드 인 효과 구현

홈 화면

홈화면의 세 문장의 자기소개를 한 줄씩 시간 차로 페이드인 효과를 구현

구현 방법

  • 페이드인 애니메이션 생성
import { css, keyframes } from 'styled-components';

// 페이드인 애니메이션 생성
const fadeIn = keyframes`
  from { opacity: 0 }
  to { opacity: 1 }
`;

// 페이드인 애니메이션 적용
export const fadeInAnimated = css`
  opacity: 0;
  animation: ${fadeIn} 1s both; 
`;
  • 원하는 컴포넌트에 페이드인 애니메이션 적용, props값을 통해 delay 값 추가
const IntroduceName = styled.strong<{ delay : number }>`
  font-size: 5rem;
  text-decoration: underline;
  text-decoration-color: ${oc.teal[6]};

  ${fadeInAnimated}
	
  ${(props) => {
    return css`
      animation-delay: ${props.delay}s;
    `;
  }}
  
  ...
`;

... 

// 적용
const Introduce: React.FC<ReactProps> = () => {
  return (
    <IntroduceResponsive>
	 	  // ...
          <IntroduceTitle>
            기록과 공유를 좋아하는
          </IntroduceTitle>
          <IntroduceTitle>
            <IntroduceName delay={0.5}>황준승</IntroduceName> 입니다.
          </IntroduceTitle>
          <IntroduceDescription delay={1}>프론트엔드 개발자를 꿈꾸고 있습니다.</IntroduceDescription>
          <IntroduceDescription delay={1.5}>배운 것을 기록하고 공유하는 것을 좋아합니다.</IntroduceDescription>
          <IntroduceDescription delay={2}>
            다른 사람들이 이해하기 쉽게 기록하고 공유하려고 노력합니다.
          </IntroduceDescription>
        </IntroduceTextBox>
   		// ..
    </IntroduceResponsive>
  );
};

위의 코드 처럼 delay 값을 통해 각 컴포넌트의 페이드인 효과를 시간 차로 두어 순차적으로 페이드인 효과가 나타나도록 구현하였다.

이력서 화면

스크롤 시 해당 컴포넌트가 화면에 나타날 시 페이드인 효과를 부여, 책장을 넘기는 효과와 비슷한 효과를 나타내려고 했다.

고민
해당 코드 구현 시 브라우저 뷰포트 높이, 스크롤 높이 등을 고려하여 해당 컴포넌트가 뷰포트 내에 들어왔는 지 확인하려고 하였다.

하지만 이는 성능적인 문제가 있어 이를 보완, 개선한 Observer API를 사용하였다. 자세한 내용은 아래 글을 참조하자

내가 작성한 관련 글 - 스크롤 시 페이드 인 효과 구현 성능 비교

구현 방법
Observer API관련 스크롤 페이드인 효과가 여러 컴포넌트에 다양하게 쓰일 수 있다고 생각해 FadeInSection 컴포넌트를 나누어 구현하였다.

type FadeInSectionStyleProps = {
  isVisible : boolean;
};

const FadeInSectionStyle = styled.article<FadeInSectionStyleProps>`
  ${Container}
  opacity: 0;

  ${(props) => {
    return props.isVisible && css`
      ${fadeInAnimated}
    `;
  }}
`;

const FadeInSection: React.FC<ReactProps> = ({ children }) => {
  const dom = useRef<HTMLElement>(null);

  const [visible, setVisible] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver((entries) => {
      if (entries[0].isIntersecting) {
        setVisible(true);
        if (dom.current) observer.unobserve(dom.current);
      }
    });

    if (dom.current) observer.observe(dom.current);
  }, []);

  return (<FadeInSectionStyle ref={dom} isVisible={visible}>{children}</FadeInSectionStyle>);
};

export default FadeInSection;

설명
js는 dom의 직접 접근이 가능하지만 styled-components를 사용하는 react의 경우 dom의 직접 접근이 불가능하다.

대신 useRef를 사용하여 dom 접근이 가능하며 스크롤 이벤트 발생시 useEffect에 의해 해당 dom에 접근, 비교하여 visiable 변수를 변경 가능하다.

이때 뷰포트에 해당 컴포넌트가 보여진다면 visiable 변수가 true로 변경되어 페이드인 효과가 나타나면서 화면에 보이게 된다.

마지막으로 해당 컴포넌트를 내가 페이드인 효과를 구현하고자 하는 컴포넌트에 감싸면 구현 완료

const ResumeTemplate: React.FC = () => {
  const { current } = useRef([
    { id: 1, text: 'edu' },
    { id: 2, text: 'pj' },
    { id: 3, text: 'share' },
  ]);

  return (
    <ResumeTemplateContainer>
      {
        current.map((template) => {
          return (
            <FadeInSection key={template.id}>
              {
                template.text === 'edu' && <Education />
              }
              {
                template.text === 'pj' && <Project />
              }
              {
                template.text === 'share' && <Share />
              }
            </FadeInSection>
          );
        })
      }
    </ResumeTemplateContainer>
  );
};

2. 모바일 반응형 구현

헤더와 같은 내용을 모바일 화면에서 볼 경우 해당 컨텐츠 내용이 다 들어가지 않고 넘쳐나 모바일 환경일 경우 다른 레이아웃으로 구현하도록 하였습니다.

학습한 것
Q. 미디어 쿼리 사용 시 분기 점 min, max 무엇을 쓸까?
A. 모바일 퍼스트 : min, 데스크탑 퍼스트: max

모바일 퍼스트(min)
모바일에 대한 스타일링이 우선 적용, 분기점이 낮은 순서대로 작성한다.

	
.title { font-size: 12px; }
 
@media (min-width: 640px) {
  .title { font-size: 14px; }
}
 
@media (min-width: 768px) {
  .title { font-size: 16px; }
}
 
@media (min-width: 1024px) {
  .title { font-size: 18px; }
}

데스크탑 퍼스트(max)
분기점이 높은 순서부터 작성합니다. 이 경우 뷰포트 값이 작아질수록 스타일을 덮어쓰는 방식

/* Desktop First */
 
.title { font-size: 18px; }
 
@media (max-width: 1023px) {
  .title { font-size: 16px; }
}
 
@media (max-width: 767px) {
  .title { font-size: 14px; }
}
 
@media (max-width: 639px) {
  .title { font-size: 12px; }
}

특정 뷰포트 지정
특정 뷰포트 범위를 지정하여 스타일링 합니다.

.title { font-size: 18px; }

@media only screen and (min-width: 768px) and (max-width: 1024px) {
  .title { font-size: 16px; }
}

구현

  • 헤더 전체 - 뷰포트 > 1200px(sizes.width) ? 1200 : 100%

  • 헤더 : 모바일 환경일 경우 navbar가 수평이 아닌 수직으로 + 다크모드 버튼 위치 수정

  • 푸터 : 모바일 환경일 경우 @Copyright 구문 제거

  • 프로젝트 페이지 : 뷰포트에 따른 grid 위치 변경
    태블릿보다 큰 화면 : 3분할
    태블릿 화면 : 2분할
    모바일 화면 : 1분할

  • 그 외: 다양한 뷰포트에 따라 글씨 크기를 줄이고 키웠다.

이번 기능 구현을 통해서 좀 UX/UI 그리고 좀 더 동적인 UI를 구현해보았습니다.

profile
다른 사람들이 이해하기 쉽게 기록하고 공유하자!!

0개의 댓글