단비의 코딩 공부 blog

[Vanilla JS]study 13일차 - 웹 컨텐츠 제작 - 드롭 다운 메뉴 본문

javascript&jquery

[Vanilla JS]study 13일차 - 웹 컨텐츠 제작 - 드롭 다운 메뉴

황굽달 2023. 3. 21. 09:51

1. 아래로 떨어지는 유형

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8" />
        <title>패밀리사이트 - 아래로 떨어지는 유형</title>
        <link rel="stylesheet" href="fs01.css" />
    </head>
    <body>
        <header></header>
        <section></section>
        <footer>
            <!-- 패밀리사이트 전체묶음 -->
            <div class="fSite">
                <!-- 초점을 받기 위해 버튼 태그 -->
                <button id="fsBtn">
                    FAMILYSITE
                    <span class="icon"><img src="down_icon.png" alt="다운아이콘"></span>
                </button>
                <!-- 클릭시 보여질 리스트 -->
                <ul>
                    <!-- _blank : 새창으로 주소를 열기 -->
                    <li><a href="http://www.naver.com" target="_blank">네이버</a></li>
                    <li><a href="http://www.daum.net" target="_blank">다음</a></li>
                    <li><a href="http://www.nate.com" target="_blank">네이트</a></li>
                    <li><a href="http://www.google.com" target="_blank">구글</a></li>
                </ul>
            </div>
        </footer>
        <script src="fs01.js"></script>
    </body>
</html>

 

/* base */
*{ padding: 0; margin: 0; font-size: 12px; color: #666666; }
li{ list-style: none; }
a{ text-decoration: none; }

/* layout */
header{ width: 1000px; height: 100px; margin: 0 auto; background-color: coral; }
section{ width: 1000px; height: 700px; margin: 0 auto; background-color: antiquewhite; }
footer{ width: 1000px; height: 200px; margin: 0 auto; background-color: lightblue; position: relative; } /* fSite의 위치 컨트롤 위해서 사용 */

/* fSite */
.fSite{ width: 150px; height: 130px; position: absolute; top: 10px; right: 10px; }
.fSite button{ width: 150px; height: 30px; border: 1px solid #CCCCCC; border-bottom: none; box-sizing: border-box; color: #FFFFFF; background-color: #333333; text-align: left; padding-left: 10px; line-height: 29px; cursor: pointer; }
.fSite button .icon{ float: right; display: block; width: 30px; height: 100%; border-left: 1px solid #CCCCCC; box-sizing: border-box; padding: 5px 0; text-align: center; }

/* 하위 리스트 */
.fSite ul{
    position: absolute; top: 30px; left: 0;
    width: 150px; padding: 0 10px;  
    border: 1px solid #ccc;
    height: 0; /* 안보이게 처리 */
    overflow: hidden;
    box-sizing: border-box; background-color: #333333;

    transition: 0.3s ease-out; /* 변화에 시간차처리 */
}
.fSite li{ margin-bottom: 5px; }
.fSite li a{ color: #FFFFFF; }/* 글자관련은 최종적으로 a가 지정 */

/* 버튼 활성화 처리 : 자바스크립트에서 클래스 컨트롤 */
.fSite button.active .icon{ transform: rotate(180deg); border-left: none; border-right: 1px solid #CCCCCC; } /* 아이콘 180도 회전 */
.fSite button.active + ul{ height: 100px; padding: 10px; } /* 높이를 처리 */

 

//버튼을 클릭하면 버튼 자신에게 active클래스 추가 혹은 제거하시오.

//1. 문서객체 선택
const fsBtn = document.getElementById('fsBtn');

//2. 클릭이벤트
fsBtn.addEventListener('click', function(){
    this.classList.toggle('active');
});

//웹접근성 - 키보드 접근성
//tab키는 : 초점의 정방향
//shift + tab키 : 초점의 역방향

//초점을 받는 태그 : a, button, select, input, testarea

//3. 리스트의 마지막 a태그에서 키보드를 눌렀을 때, tab키일 때 active클래스를 제거
const lastLink = fsBtn.nextElementSibling.lastElementChild.firstElementChild;

//4. 키보드 이벤트 - shift키 눌렸는지 확인해야 해서 keydown이벤트 처리
lastLink.addEventListener('keydown', function(e){
    //e : 이벤트 객체 - 눌린 키의 정보를 담는 객체
    //탭키의 키코드 : 9
    //shiftkey : 쉬프트키가 눌렸다면 true를 반환, 그렇지 않으면 false를 반환

    if(e.keyCode == 9){ //tab키를 눌렀을 때
        if(!e.shiftKey){
            fsBtn.classList.remove('active'); // 버튼의 active 클래스 제거
        }
    }
});


2. 패밀리 사이트

<!DOCTYPE html>
<html lang="ko">
    <head>
        <meta charset="UTF-8" />
        <title>패밀리사이트</title>
        <link rel="stylesheet" href="fs02.css" />
    </head>
    <body>
        <header></header>
        <section></section>
        <footer>
            <div class="fSite">
                <button id="fsBtn">
                    FAMILYSITE
                    <span class="icon"><img src="down_icon.png" alt="다운아이콘"></span>
                </button>
                <ul>
                    <!-- tabindex : 요소의 탭순서를 지정 -->
                    <!-- -1 : 초점받던 태그가 탭을 받지 못함 -->
                    <!-- 0 : 초점받지 못한 태그가 초점을 받고, 탭순서는 순서대로 자연스럽게 처리 -->
                    <!-- 초기상태에서 안보이지만 탭키 누르면 초점이 가기 위해 무너지기 때문에 초점을 못가게 막음 -->
                    <li><a href="http://www.naver.com" target="_blank" tabindex="-1">네이버</a></li>
                    <li><a href="http://www.daum.net" target="_blank" tabindex="-1">다음</a></li>
                    <li><a href="http://www.nate.com" target="_blank" tabindex="-1">네이트</a></li>
                    <li><a href="http://www.google.com" target="_blank" tabindex="-1">구글</a></li>
                </ul>
            </div>
        </footer>
        <script src="fs02.js"></script>
    </body>
</html>

 

/* base */
*{ padding: 0; margin: 0; font-size: 12px; color: #666666; }
li{ list-style: none; }
a{ text-decoration: none; }

/* layout */
header{ width: 1000px; height: 100px; margin: 0 auto; background-color: coral; }
section{ width: 1000px; height: 700px; margin: 0 auto; background-color: antiquewhite; }
footer{ width: 1000px; height: 100px; margin: 0 auto; background-color: lightblue; position: relative; } /* fSite의 위치 컨트롤 위해서 사용 */

/* fSite */
.fSite{
    width: 150px; height: 130px; position: absolute; top: -90px; right: 10px;
    overflow: hidden; /* 현재 요소 영역에서 넘어간 자손을 안보이게 처리 */
}
.fSite button{ width: 150px; height: 30px; border: 1px solid #CCCCCC; box-sizing: border-box; color: #FFFFFF; background-color: #333333; text-align: left; padding-left: 10px; line-height: 29px; cursor: pointer; position: absolute; top: 100px; z-index: 10; } /* 버튼이 위쪽에 보여야 함 */
.fSite button .icon{ float: right; display: block; width: 30px; height: 100%; border-right: 1px solid #CCCCCC; box-sizing: border-box; padding: 5px 0; text-align: center; transform: rotate(180deg); }
.fSite ul{
    padding: 10px; width: 150px; height: 100px; box-sizing: border-box; border: 1px solid #CCCCCC; background-color: #333333; border-bottom: none;
    position: absolute; /* 형요소인 버튼보다 위쪽에 위치해야해서 변경 */

    top: 100px; /* 처음 위치는 내려가 있어야 함 */
    z-index: 9; /* 리스트가 아래 쪽에 보여야 함 */

    transition: 0.3s ease-in-out; /* css의 변화에 시간차 처리 */
}

.fSite li{ margin-bottom: 5px; }
.fSite li a{ color: #FFFFFF; }/* 글자관련은 최종적으로 a가 지정 */

/* 활성버튼 */
.fSite button.active .icon{ transform: rotate(0deg); border-right: none; border-left: 1px solid #CCCCCC; }
.fSite button.active + ul{ top: 0; }

 

//버튼을 클릭하면 버튼 자신에게 active클래스 추가 혹은 제거하시오.

//1. 문서객체 선택
const fsBtn = document.getElementById('fsBtn');

//2. 클릭이벤트
fsBtn.addEventListener('click', function(){
    this.classList.toggle('active');

    //active클래스를 받았다면, a 태그가 초점을 받고, 그렇지않다면 초점을 받지 않게 처리
    //setAttribute('속성명',값) : 문서객체의 태그 속성을 변경
    //contains('클래스명') : 해당 클래스를 갖고 있으면 true반환, 그렇지 않으면false를 반환

    //a태그를 문서객체로 선택 - 복수로 전부 선택
    const activeLink = this.nextElementSibling.getElementsByTagName('a');

    //클래스 유무여부
    const has = this.classList.contains('active');
   
    if(has){  //active클래스를 갖고 있다면
        for(let i=0;i<activeLink.length;i++){
            activeLink[i].setAttribute('tabindex','0');  //문자열로 담아줘야함 - 전부 초점처리
        }
    }else{  //active클래스를 갖고 있지 않다면
        for(let i=0;i<activeLink.length;i++){
            activeLink[i].setAttribute('tabindex','-1');  //문자열로 담아줘야함 - 전부 초점받지 못하게 처리
        }
    }
});

//3. 키보드 이벤트 (웹접근성)
const lastLink = fsBtn.nextElementSibling.lastElementChild.firstElementChild;

lastLink.addEventListener('keydown', function(e){
    if(e.keyCode == 9){ // tab키를 눌렀을 때
        if(!e.shiftKey){  // 시프트키를 누르지 않았다며
            fsBtn.classList.remove('active'); // 버튼의 active 클래스 제거

            //모든 a태그를 다시 선택
            const activeLink = this.parentNode.parentNode.getElementsByTagName('a');
           
            for(let i=0;i<activeLink.length;i++){
                activeLink[i].setAttribute('tabindex','-1');  //문자열로 담아줘야함 - 전부 초점받지 못하게 처리
            }
        }
    }
});