[Clone Project - 7] Footer, 드롭다운 버튼 구현

young_pallete·2021년 7월 14일
0

시작하며 🌈

일단 partners라는 컴포넌트를 구현한 글을 쓰려다가... 생각보다 기능이 너무 쉬웠습니다.
그래서 이는 넘어가고, 드롭다운 버튼을 직접 구현한 과정을 서술해보려 합니다!

본론 💬

일단 제가 클론한 프로그래머스의 Footer에 위치한 드롭다운 버튼은 다음과 같은 특징이 있었습니다.

먼저 데스크탑 화면 크기 시에는 저렇게 absolute position으로 별도로 위치했고,

태블릿 이하 화면 크기에서는 다음과 같이 밑으로 내려가는 것으로 보아, relative로 변화시킨 것 같았습니다.

솔직히 여기까지는 정말 쉬웠는데, 저를 당황스럽게 했던 건 다음과 같은 기능이었어요.

내용들이 다 보일 정도면, 다음과 같이 밑으로 내려가다가

이렇게 다시 위로 스크롤하면 위로 올라가는 기능이 있더라구요...
아고 머리야!😂

하지만 일단 문제가 주어졌으니, 해결은 해야겠고! 결국에는 해결해냈답니다 👏👏


따라서 html은 다음과 같이 작성했어요!

index.html

    <footer class="footer">
        <section class="footer__containter">
            <section class="footer__categories">
                <section class="footer__category">
                    <h5 class="footer__category-name">서비스</h5>
                    <a href="https://programmers.co.kr/">개발자용 프로그래머스</a>
                    <a href="https://business.programmers.co.kr/">기업용 프로그래머스</a>
                    <a href="https://school.programmers.co.kr/">프로그래머스 스쿨</a>
                </section>
                <section class="footer__category">
                    <h5 class="footer__category-name">약관</h5>
                    <a href="https://programmers.co.kr/privacy">개인정보 처리방침</a>
                    <a href="https://programmers.co.kr/tos">이용약관</a>
                </section>
                <section class="footer__category">
                    <h5 class="footer__category-name">문의</h5>
                    <a href="https://programmers.co.kr/zendesk/main">
                        <span>FAQ/문의</span>
                        <i class="fas fa-external-link-alt"></i>
                    </a>
                    <a href="https://programmers.zendesk.com/hc/ko/requests/new">
                        <span>교육 결제, 환불 관련 문의</span>
                        <i class="fas fa-external-link-alt"></i>
                    </a>
                    <a href="https://programmers.zendesk.com/hc/ko/requests/new">
                        <span>코딩 테스트(응시자) 문의</span>
                        <i class="fas fa-external-link-alt"></i>
                    </a>
                </section>
                <section class="footer__category">
                    <h5 class="footer__category-name">고객센터</h5>
                    <span>기업 서비스 : 02-539-1886</span>
                    <span>교육 내용 관련 문의 : 02-539-1885</span>
                    <span>제휴 및 서비스 운영, 기타 문의 : 02-539-1882</span>
                    <div class="footer__operation-time">
                        <span>문의하기 운영시간 : 오전 9시 ~ 오후 6시 (주말 및 공휴일 휴무)</span>
                        <span>점심시간 : 오후 12시 ~ 오후 1시</span>
                    </div>
                </section>
            </section>
            <section class="footer__dropdown">
                <button class="footer__dropdown-btn">
                    <span>패밀리사이트</span>
                    <div class="footer__dropdown-btn-arrow"></div>
                </button>
                <ul class="footer__family-sites">
                    <a href="https://www.grepp.co/" class="footer__family-site">그렙</a>
                    <a href="https://monito.io/" class="footer__family-site">모니토</a>
                    <a href="https://hashcode.co.kr/" class="footer__family-site">해시코드</a>
                </ul>
            </section>
            <section class="footer__developers">
                <h5 class="footer__developers-header">
                    2021 디벨로퍼스
                </h5>
                <p class="footer__me-info">이 프로젝트는 HTML, SCSS, TypeScript로 프로그래머스를 직접 클론한 프로젝트입니다. 제 정보는 다음과 같아요! 😘</p>
                <a href="" class="">Github 바로가기</a>
                <a href="">블로그 바로가기</a>
            </section>
        </section>
    </footer>

이번 건 아무래도 각자가 다 정보가 있기도 했고, 레이아웃 구조도 간단명료해서 시멘틱하게 작성하기 수월했습니다.😂😂

main.scss

그러나 CSS의 경우... 반응형이 워낙 많은지라 250줄이 되는 코드라 깔끔하게 주요 기능인 드롭다운 기능만 살펴보겠습니다!

    &__dropdown {
        position: absolute;
        top: 1rem;
        right: 1rem;
        width: 7rem;
        // background: white;
        &-btn {
            display: flex;
            align-items: center;
            padding: 0.375rem 0.5rem;
            border: 1px solid $border-gray-color;
            border-radius: 0.25rem;
            span {
                font-size: 0.6875rem;
                font-weight: 700;
                letter-spacing: -0.3px;
            }
            &-arrow {
                margin-left: 0.25rem;
                border: {
                    bottom: 3.5px solid black;
                    left: 3.5px solid transparent;
                    right: 3.5px solid transparent;
                }
                transform: rotate(180deg);
            }
            &--active {
                background: $border-gray-color;
            }
        }
        .footer__family-sites {
            display: none;
            background: white;
            position: absolute;
            z-index: 30;
            &.show-top {
                bottom: 1.75rem;
            }
            &--active {
                display: block;
            }
            width: 100%;
            padding: 0.5rem 0;
            border: 1px solid $border-gray-color;
            border-radius: 5px;
            font-size: $font-ms;
            box-shadow: 0 0 1rem $border-gray-color;
            .footer__family-site {
                display: block;
                border: none;
                padding: 0.125rem 1rem;
                color: black;
                font-weight: 700;
                &:hover {
                    cursor: pointer;
                    color: $blue-color;
                }
            }
        }
    }
    @include customMedia("tablet") {
        .footer__dropdown {
            right: 0;
            position: relative;
            .footer__family-sites {
                position: absolute;
            }
        }
    }

일단 다 간추렸을 때 이런 식으로 position값을 조절하며 구현할 수 있었어요.


Footer.ts

저는 일단 기준점을 잡았어요.

만약 버튼이 다 안보이는 상태라면 -> 위쪽으로 보이면 됩니다.
만약 버튼이 다 보이는 상태라면 -> 아래쪽으로 보이면 됩니다.

따라서 이를 어떤 기준점 하나를 잡고, 뷰포트에서 다 보이는지를 계속 감시하면 될 것 같다는 생각이 들었고, 따라서 Observer API 중, interserctionObserver를 사용했답니다!

interserctionObserver는 다음과 같은 인수를 받아요.

new intersectionObserver(cb, options)

  • cb(entries: 인스턴스의 배열, observer: 콜백이 실행되는 인스턴스)
  • options: {
    root: null(viewport) 가시성 검사를 위한 대상,
    rootMargin: 0 루트의 범위를 상하좌우로 늘리거나 줄일 수 있음,
    threshold: 1 얼마나 보여질 때 적용할 것인지
    }
interface optionFormat {
    root: any,
    rootMargin: string,
    threshold: number
}
interface Names {
    [name: string]: string
}
export default class Footer {
    private readonly names: Names;
    constructor() {
        this.names = {
            dropdownBtn: 'footer__dropdown-btn',
            familySites: 'footer__family-sites'
        }
        this.HandleEvent()
    }    
    HandleEvent() {
        const $dropdownBtn:HTMLElement = document.querySelector(`.${this.names.dropdownBtn}`);
        const $familySites:HTMLElement = document.querySelector(`.${this.names.familySites}`);
        let options:optionFormat = {
            root: null, // default: null (viewport)
            rootMargin: '0px 0px -50px 0px',
            threshold: 1,
        }
        let callback = (entries: any, observer: any) => {
            entries.forEach((entry: any) => {
                $familySites.classList.toggle('show-top', !entry.isIntersecting)
            });
        };
        let observer = new IntersectionObserver(callback, options);
        let target = $dropdownBtn;
        observer.observe(target);
        
        $dropdownBtn.addEventListener('click', (e) => {
            $dropdownBtn.classList.toggle(`${this.names.dropdownBtn}--active`);
            $familySites.classList.toggle(`${this.names.familySites}--active`);
        }) 
    }
}

저같은 경우, 일단 드롭다운 버튼을 기준점으로 잡은 후, 뷰포트를 통해 가시성을 관찰했어요.

이때, 드롭다운을 눌렀을 때 어느정도 보이는 크기를 고려하여 rootMargin을 setting하였습니다.

결과적으로, 드롭다운 내용들이 다 보여질 정도의 크기라면 밑으로 내려가게 하고, 아니라면 위로 올렸죠! (이는 보시면 아시겠지만, 클래스를 이용해서 구현해냈습니다!)

이정도가 딱 밑으로 위치하는 마지노선이네요!

마치며 👏

이런 식으로 하나하나 제대로 다져갔어야 했는데, 여태까지 공부방식은 너무나 급하기 그지없었던 것 같아요.

그래도 잘못된 부분을 알았다면! 고치는 게 제 성장을 위한 일이겠죠. 😊
일단 오늘은 이정도로 다시 프로젝트 회고를 마치고, 블로그 프로젝트를 유지보수해보러 가야겠어요.

만약 제 설명이 틀린 부분이 있거나, 더 효율적인 방안이 있다면 말씀해주시면 언제든지 환영합니다! 읽어주셔서 감사합니다 👍😁

profile
People are scared of falling to the bottom but born from there. What they've lost is nth. 😉

0개의 댓글