반응형
- 프로젝터: SNU FESTIVAL
- 키워드: absolute, responsive web
- 상황
- 보통 화면 레이아웃은 flex, grid 등의 css 속성을 이용하지만 축제 메인화면이라는 특수한 상황에 맞도록 디자이너와 함께 레이아웃을 고민했다. 결과적으로 아래와 같은 디자인이 확정되었다.
- 통계상 80%의 유저가 모바일로 접속하기 때문에, 모든 기기에서 레이아웃이 깨지지 않도록 신경을 써야한다.
- 배경 이미지(island)를 화면에 꽉 차도록하고, 하위 요소(굿즈, 공연, 행사, 미니게임, 방명록 등)의 위치를 상대적으로 잡아야한다.
- 보통 화면 레이아웃은 flex, grid 등의 css 속성을 이용하지만 축제 메인화면이라는 특수한 상황에 맞도록 디자이너와 함께 레이아웃을 고민했다. 결과적으로 아래와 같은 디자인이 확정되었다.
- 해결방법
- 먼저 모든 기기에 대해 화면에 딱 맞게 배경이 그려져야한다. 보통은 '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에 딱 맞도록 `;
- 이제 하위 요소들의 위치는 absolute로 쉽게 잡을 수 있다.
기기의 너비에 따라 하위 요소의 크기도 변해야하므로 기준 너비(375px)에 대한 현재 너비 ratio를 구한다. 그리고 ratio를 이용하여 width를 정하고 디자인에 맞게 top, left속성도 정한다.// windowWidth는 실제 브라우저 너비(document.documentElement.clientWidth) // 375px은 디자이너의 기준 너비(iPhone X) const ratio = useMemo(() => theme.windowWidth / 375, [theme.windowWidth]);
부모 div의 width/height 비율이 일정함이 보장되어있으므로(px로 직접 계산) top, left에 '%'값을 부여하면 브라우저 너비에 관계없이 항상 똑같은 UI를 보여줄 수 있다.// 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}%`}; `;
같은 방법으로 10개의 하위요소를 추가하면 상황1에 있는 디자인과 똑같이 완성된다!
- 먼저 모든 기기에 대해 화면에 딱 맞게 배경이 그려져야한다. 보통은 '100%' 를 이용하여 표현하지만 이 경우엔 배경 이미지의 비율이 바뀌지 않고 항상 일정(늘어짐없이 디자인과 일치)해야하고, absolute로 위치를 잡을 하위 요소가 많았다(부모의 width, height 비율이 일정하지 않으면 하위 요소들의 위치도 깨짐. '100%', 'auto' 등의 속성은 사용 불가).
- 한 걸음 더
- height/width = 2.1653으로 고정되어있는 상황이기 때문에, 세로 스크롤이 생기지 않을만큼 길면서도 비율이 2.1653보다 큰 기기일 경우 아래와 같이 빈 공간이 생길 수도 있다(실제로 이런 비율을 가진 기기를 찾진 못했다).
- Background color를 줘서 빈 공간과 island 배경을 자연스럽게 이어준다.
<Background /> export const Background = styled.div` position: fixed; width: 100%; height: 100%; background-color: #A2CCE9; `;
- height/width = 2.1653으로 고정되어있는 상황이기 때문에, 세로 스크롤이 생기지 않을만큼 길면서도 비율이 2.1653보다 큰 기기일 경우 아래와 같이 빈 공간이 생길 수도 있다(실제로 이런 비율을 가진 기기를 찾진 못했다).
반응형
'프론트엔드' 카테고리의 다른 글
RxJS를 이용해 함수형으로 데이터 다루기 (0) | 2021.12.11 |
---|---|
Firebase storage로 첨부파일 다운로드 구현하기 (0) | 2021.12.06 |
svg mask fill 속성은 white로 지정하기 (0) | 2021.12.03 |
typescript Pick으로 확장성있게 타입 지정하기 (0) | 2021.12.01 |
번들링 최적화를 통해 import cost 줄이기(2) (0) | 2021.11.28 |