본문 바로가기

프론트엔드

absolute와 fixed로 다양한 스마트폰 너비 대응하기

반응형
  • 프로젝터: SNU FESTIVAL
  • 키워드: absolute, responsive web
  • 상황
    1. 보통 화면 레이아웃은 flex, grid 등의 css 속성을 이용하지만 축제 메인화면이라는 특수한 상황에 맞도록 디자이너와 함께 레이아웃을 고민했다. 결과적으로 아래와 같은 디자인이 확정되었다.
      축제 메인화면 모바일버전
    2. 통계상 80%의 유저가 모바일로 접속하기 때문에, 모든 기기에서 레이아웃이 깨지지 않도록 신경을 써야한다.
    3. 배경 이미지(island)를 화면에 꽉 차도록하고, 하위 요소(굿즈, 공연, 행사, 미니게임, 방명록 등)의 위치를 상대적으로 잡아야한다.
  • 해결방법
    1. 먼저 모든 기기에 대해 화면에 딱 맞게 배경이 그려져야한다. 보통은 '100%' 를 이용하여 표현하지만 이 경우엔 배경 이미지의 비율이 바뀌지 않고 항상 일정(늘어짐없이 디자인과 일치)해야하고, absolute로 위치를 잡을 하위 요소가 많았다(부모의 width, height 비율이 일정하지 않으면 하위 요소들의 위치도 깨짐. '100%', 'auto' 등의 속성은 사용 불가).
      따라서 실제 브라우저 width를 구하고, 디자이너가 준 width/height 비율과 맞도록 px을 직접 계산하여 넣어주었다.
        // 실제 디자인상 height/width = 2.1653
      <LayoutDiv width={theme.windowWidth} height={theme.windowWidth * 2.1653}>
        <IslandImg src={MobileIsland} ... />
        ...
      </>
      
      const Island = styled.img`
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%; // LayoutDiv에 전달한 px에 딱 맞도록
      `;


      배경을 넣은 모습


    2. 이제 하위 요소들의 위치는 absolute로 쉽게 잡을 수 있다.
      // windowWidth는 실제 브라우저 너비(document.documentElement.clientWidth)
      // 375px은 디자이너의 기준 너비(iPhone X)
      const ratio = useMemo(() => theme.windowWidth / 375, [theme.windowWidth]);
       기기의 너비에 따라 하위 요소의 크기도 변해야하므로 기준 너비(375px)에 대한 현재 너비 ratio를 구한다. 그리고 ratio를 이용하여 width를 정하고 디자인에 맞게 top, left속성도 정한다.
        // 188px은 디자인상 기준 너비
      <Landmark src={GuestBook} alt="방명록" top={87} left={20} width={188 * ratio} ... />
        
      const Landmark = styled.img`
        position: absolute;
        width: ${({ width }) => width}px;
        height: auto;
        ${props => props.top && css`top: ${props.top}%`};
        ${props => props.left && css`left: ${props.left}%`};
      `;
      부모 div의 width/height 비율이 일정함이 보장되어있으므로(px로 직접 계산) top, left에 '%'값을 부여하면 브라우저 너비에 관계없이 항상 똑같은 UI를 보여줄 수 있다.
      하위요소가 3개 추가된 화면

      같은 방법으로 10개의 하위요소를 추가하면 상황1에 있는 디자인과 똑같이 완성된다!
  • 한 걸음 더
    1. height/width = 2.1653으로 고정되어있는 상황이기 때문에, 세로 스크롤이 생기지 않을만큼 길면서도 비율이 2.1653보다 큰 기기일 경우 아래와 같이 빈 공간이 생길 수도 있다(실제로 이런 비율을 가진 기기를 찾진 못했다).


    2. Background color를 줘서 빈 공간과 island 배경을 자연스럽게 이어준다.
        <Background />
      
      export const Background = styled.div`
        position: fixed;
        width: 100%;
        height: 100%;
        background-color: #A2CCE9;
      `;



반응형