ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 44일차[framer 과제]
    카테고리 없음 2026. 5. 7. 20:31

    Framer로 에어비앤비 스타일 사이트 만들기 — 작업 기록

    🔗 결과물: https://appreciative-points-868576.framer.app/popular

    과제로 Framer를 이용해 에어비앤비 같은 숙소 서비스 사이트를 만들었다. AI 도움 받아가며 하루 만에 어찌어찌 완성했다. 막혔던 포인트가 꽤 많아서 다음에 또 비슷한 작업할 때 참고하려고 기록을 남긴다.

    과제 목표

    • CMS(데이터)를 만들고 화면에 연결
    • 목록 페이지 → 상세 페이지로 이어지는 구조
    • 공통 레이아웃(Header/Footer) 재사용
    • 조건에 따라 페이지 분기 (지역별, 인기 등)
    • SEO/공유 메타데이터 설정

    1. CMS 데이터 구조 설계

    가장 먼저 한 일은 데이터 구조 잡기. Framer의 CMS는 컬렉션 단위로 만든다.

    Properties 컬렉션 필드:

    • Name (Plain Text) — 숙소 제목
    • Slug (Slug) — URL용
    • Image (Image) — 대표 사진
    • Location (Plain Text) — 위치
    • Price (Number) — 1박 가격
    • Summary (Plain Text) — 짧은 요약
    • Description (Rich Text) — 상세 설명
    • Region (Option: 서울/부산/제주) — 지역 분기용
    • isHot (Toggle) — 인기 숙소 표시용

    지역 분기에 Region, 인기 숙소 분기에 isHot을 쓰는 게 핵심. 이 두 필드가 나중에 페이지 필터링에 다 활용된다.


    2. Header 가운데 정렬 — Grid가 답이었다

    처음에 헤더에 로고/메뉴/액션버튼을 배치했는데, "숙소·체험·서비스"가 가운데로 안 갔다. Stack의 Distribute: Space Between을 썼는데도 자꾸 로고 옆에 붙어버렸다.

    원인: Space Between은 "남는 공간을 균등 분배"하는 거지 정중앙 정렬이 아니다. 자식 너비에 따라 위치가 바뀐다.

    해결: Stack을 Grid로 바꾸고 3 컬럼(1fr 1fr 1fr) 으로 만든 뒤 각 자식에 Justify Self만 다르게.

    • 로고 → Start (왼쪽)
    • 메뉴 → Center (가운데)
    • 액션 → End (오른쪽)

    이렇게 하니까 화면 폭이 바뀌어도 항상 가운데 메뉴는 정중앙에 고정됐다. Framer에서 헤더 만들 땐 Grid가 표준 패턴이라는 걸 처음 알았다.


    3. 카드 사이즈 통일 — 코드 컴포넌트와 씨름(클로드가 해결해줌)

    Properties 목록 페이지를 만들었는데 카드들이 다 들쭉날쭉했다. 어떤 건 사진이 길고, 어떤 건 짧고. 사진마다 가로세로 비율이 달라서 그런 거였다.

    문제 1: 코드 컴포넌트(AccommodationCard)에 이미지 영역이 height: "60%" 로 돼있었음. 부모 높이의 60%인데, 부모(카드) 높이가 들쭉날쭉하니까 이미지도 같이 흔들림.

    해결: 이미지 높이를 고정 픽셀(220px)로 바꾸고, flexShrink: 0 추가.

    {/* Before */}
    height: "60%"
    
    {/* After */}
    height: imageHeight,  // prop으로 220px 받음
    flexShrink: 0,
    

    문제 2: 제목/요약 길이 때문에 카드 높이가 또 달라짐.

    해결: WebkitLineClamp 줄 수 제한을 prop으로 노출. Name Lines = 1, Summary Lines = 2로 고정하니까 카드 높이가 통일됐다.

    핵심 학습: objectFit: cover만 알면 되는 줄 알았는데, 컨테이너 높이가 변하면 그것도 무용지물이었다. 고정 높이 + flexShrink 0 + objectFit cover 3종 세트가 정답.


    4. 상세 페이지 레이아웃 — flex wrap의 함정

    상세 페이지에서 왼쪽엔 설명, 오른쪽엔 예약 카드를 넣고 싶었는데 자꾸 위아래로 쌓여버렸다.

    원인: 컨테이너가 display: flex + flexWrap: wrap이었는데, 내부 컨텐츠 합산 너비가 컨테이너보다 크면 자동으로 줄바꿈됨. 의도한 동작이긴 하지만 좁은 화면에서 항상 wrap돼버려서 답답했다.

    해결: flex → grid로 변경.

    display: "grid",
    gridTemplateColumns: "minmax(0, 1fr) 372px",
    gap: "48px",
    alignItems: "start",
    

    minmax(0, 1fr)의 0이 핵심이다. 이게 없으면 자식이 길어졌을 때 컬럼이 안 줄어들어 레이아웃이 깨진다.

    배운 점: 2단 고정 레이아웃은 flex보다 grid가 훨씬 안정적. flex는 아이템이 동적으로 늘어나는 경우에 좋고, grid는 의도한 그리드 구조를 강제할 때 좋다.


    5. 목록 버튼 만들기 — 가장 오래 걸린 작업

    상세 페이지에서 "목록" 버튼을 누르면 이전 페이지로 돌아가게 하고 싶었다.

    제일 오래 걸렸던 부분인데..결국 실패 아몰랑


    6. 조건부 페이지 — Region/isHot 필드 활용

    가장 재밌었던 부분. 같은 Properties 컬렉션을 다른 필터로 보여주기.

    • /seoul 페이지: Properties 필터링 → Region equals "서울"
    • /busan 페이지: Region equals "부산"
    • /jeju 페이지: Region equals "제주"
    • /popular 페이지: isHot equals true

    페이지를 4개 따로 만들 필요 없이 Collection List의 Filter만 다르게 걸면 끝. 


    7. 연관 숙소 섹션 — Current Item이 핵심

    상세 페이지 하단에 "이 지역의 다른 숙소" 추천 섹션 만들기. 이게 가장 어려웠다.

    핵심 개념: Detail Page 안에서 Collection List의 필터를 걸 때 "Current Item" 변수를 쓸 수 있다. Variable 추가 시 → Set Variable → Region 필드 선택.

    필터 두 개 적용:

    1. Region Equals → Region (Variable) — 같은 지역
    2. Slug Not Equals → Slug (Variable) — 본인 제외

    이 둘을 같이 걸어야 "본인 빼고 같은 지역 숙소만" 추천된다.

    추천 카드 디자인은 따로 만들지 않고 AccommodationCard 컴포넌트를 그대로 재사용. 단, Image Height만 220 → 140으로 줄여서 본 상품보다 시각적으로 작게 보이게 했다. 이게 정보 위계상 더 자연스럽다.


    8. 가운데 정렬 — Stack + Wrap + Center

    추천 숙소가 2개일 때 Grid 3 컬럼이라 왼쪽으로 쏠리는 문제. 해결책은 Layout: Stack(가로) + Wrap: Yes + Distribute: Center.

    이렇게 하면:

    • 1개 → 가운데 1개
    • 2개 → 가운데 2개
    • 3개 → 꽉 채워서 3개
    • 4개 이상 → 자동 줄바꿈

    Grid는 셀 개수가 고정되지만 Stack은 컨텐츠 개수에 따라 자연스럽게 흐른다. 개수가 변하는 카드 그리드는 Stack이 더 유연하다.


    9. SEO 동적 메타데이터

    Detail Page의 SEO는 일반 페이지와 다르게 CMS 필드를 변수로 바인딩할 수 있다.

    • Title: {Name} | {Region} | AIRbnb
    • Description: {Summary}
    • OG Image: {Image} 바인딩

    이렇게 해두면 숙소 100개여도 메타데이터가 자동으로 100개 다르게 만들어진다. 이게 정적 사이트 빌더의 진짜 매력 같다.


    10. 마지막 함정 — Draft 페이지

    Publish하고 새 탭에서 열어보니 인기/서울/제주/부산 탭이 작동을 안 했다. 편집기 미리보기에선 잘 됐는데.

    원인: 해당 페이지들이 모두 DRAFT 상태였다. Framer에서 Draft 페이지는 Publish해도 실제 사이트에 포함되지 않는다. Preview는 Draft도 보여주니까 모르고 지나가기 쉽다.

    해결: 각 페이지 우클릭 → Publish Page → 다시 사이트 Publish.

    이건 진짜 모르면 한참 헤맬 함정. 항상 Pages 패널에서 DRAFT 라벨 다 사라졌는지 확인하고 게시할 것.


    오늘 배운 것 정리

    기술적인 것:

    • Framer의 CMS는 컬렉션 + 필터의 조합으로 거의 모든 분기를 만들 수 있다
    • Detail Page 안에서는 Current Item 변수가 핵심 도구
    • Layout은 상황에 따라 Grid / Stack을 갈라 써야 한다 (정형 = Grid, 가변 = Stack)
    • objectFit cover는 컨테이너 크기가 고정돼야 의미 있다

    작업 태도:

    • 처음부터 완벽하게 하려 하지 말고 최소 단위로 작동시킨 뒤 점점 확장
    • 막힐 때 캡처해서 물어보면 빠르게 풀린다
    • Draft → Published 같은 작은 함정에서 시간 다 잡아먹힘

    다음에 비슷한 거 만들 때:

    1. CMS 컬렉션 하나만 먼저 만들기 
    2. 데이터 5~10개만 입력하고 화면 연결 확인
    3. Header/Footer 컴포넌트화
    4. 필터로 분기 페이지 만들기
    5. 코드 컴포넌트는 마지막에 손대기
    6. Publish 전 Draft 다 풀기 ← 이게 제일 중요

    코드 한 줄 못 짜는데 코드 컴포넌트도 만지고, CMS 데이터 구조도 잡고, SEO까지 설정해봤다. AI 도움 받았다고 해도 직접 손으로 만든 사이트가 진짜 동작하는 걸 보니까 뿌듯하다. 다음 과제도 이렇게 정리하면서 가야겠다.

Designed by Tistory.