서울시청 클론코딩

오혜림·2022년 7월 27일
1
post-thumbnail

서울시청 Clone coding

1. 체크포인트

1. 웹 접근성

1-1) WAI-ARIA
1-2) 스킵 네비게이션
1-3) 탭 메뉴 tab keydown으로 닫는 기능

1-1. WAI-ARIA

스크린 리더를 사용하는 사용자들에게 페이지를 새로고침 하지 않고도 페이지의 내용과 데이터가 바뀌는 영역에 역할, 속성, 상태 정보를 추가하여 동적인 컨텐츠에 보다 원활하게 접근하고 페이지에 접근성을 높여 여러 사용자들에게 원활한 페이지 이용을 도와준다.

(ex. 버튼을 클릭하여 페이지 새로고침이나 링크 이동으로 페이지가 전환되는 것이 아닌 컨텐츠 내용이나 구조가 바뀌는 상황에서 페이지 전환 상태나 정보를 WAI-ARIA로 알려줌)

그러나 올바르지 못한 ARIA를 사용할 바엔 ARIA를 사용하지 않는 편이 좋다. 스크린리더를 사용하여 페이지에 접근하는 경우 ARIA의 정보에 의지하게 되는데 바르지 못한 정보를 제공하게 되는 경우 스크린리더 사용자의 페이지 접근에 치명적인 영향을 주게된다.

  • 탭메뉴로 구성된 ul>li>a에 각 tablist>presentation>tab 속성 추가

  • 검색창 입력 영역인 form 태그에 search 속성 추가

1-2. 스킵 네비게이션

웹 페이지의 정보량이 많을 때, 정보를 얻기까지 수도 없이 많은 tab, 방향키 입력이 필요할 것이다. 이러한 접근성이 부족한 내용을 해결하기 위해 사용하는 것이 스킵 네비게이션이다.
네비게이션 영역의 많은 링크들을 건너뛰고 바로 컨텐츠 정보를 탐색하기 위해 사용하는 용도를 가지고 있다.

  • 스킵 네비게이션의 목적이 네비게이션 영역을 스킵하기 위해서 혹은 주요 서비스로 페이지 초입에서 바로 접근하기 위해 사용하는 것 -> 가능한 body태그 맨 처음으로 위치 시키는 것이 좋다.

  • 탭키를 누르면 이렇게 스킵 네비게이션이 보이고 엔터를 누르면 해당 섹션 이동

1-3.탭 메뉴 tab keydown으로 닫는 기능

  • keyup -키보드에서 손을 땠을 때 실행 -> 주로 실시간 검색 시 사용
  • keydown - 키보드를 눌렀을 때 실행 || 키보드를 누르고 있을 때 한번만 실행됨
  • keypress - 키보드를 눌렀을 때 실행 || 키보드를 누르고 있을 때 계속 실행됨
  1. 첫번째 sub-item을 keydown을 눌렀을 때
  2. keyCode 호출하는 변수 선언
  3. 만약 tab키와 shift키가 눌리면 해당 site-item slideUp -> if조건문

  1. 마지막 sub-item을 keydown을 눌렀을 때
  2. keyCode 호출하는 변수 선언
  3. 만약 tab 만 눌리면 해당 site-item slideUp -> 이때 e.shiftKey는 눌리지 않는다는 조건도 같이 조건문에 적어야함
    $('.sc-site .sub-list .sub-item:first-child').keydown(function(e){
        const key = e.keyCode;
        if(key === 9 && e.shiftKey){
            $('.sub-list-wrap').stop().slideUp();
            $(this).parents('.sub-list-wrap').siblings().find('.ic-arrow').removeClass('active');
            $(this).parents('.sub-list-wrap').siblings().removeClass('active');
        }
    })
    $('.sc-site .sub-list .sub-item:last-child').keydown(function(e){
        const key = e.keyCode;
        if(key === 9 && !e.shiftKey){
            $('.sub-list-wrap').stop().slideUp();
            $(this).parents('.sub-list-wrap').siblings().find('.ic-arrow').removeClass('active');
            $(this).parents('.sub-list-wrap').siblings().removeClass('active');
        }
    })
  • 9 : keyCode console.log로 입력하면 tab키의 번호는 9번으로 출력됨

2. 탭 & 슬라이드

2-1) 메인 탭 슬라이드 마크업 & swiper slide
2-2) 셀렉트 창 선택 후 버튼 클릭 시 새창 이동
2-3) 하단 탭 네비게이션 슬라이드 토글
2-4) fixed top 버튼

2-1. 메인 탭 슬라이드 마크업 & swiper slide

  1. swiper slide 적용
  2. 탭버튼 컨트롤
  3. 자동재생 컨트롤

마크업

<div class="slide slide1 active">
  <h3 class="sc-title-tab"><a href="#">쥬요뉴스</a></h3>
     <div class="content">
         <div class="swiper"> /*swiper 넣기*/
             <div class="swiper-wrapper">
                  <div class="swiper-slide">

             <div class="slide-control">
                  <div class="fraction"></div>
                  <a href="#" class="btn prev" role="button"><span class="blind">이전</span></a>
                  <div class="auto-play">
                    <a href="#" class="btn play" role="button"><span class="blind">재생할것</span></a>
                    <a href="#" class="btn pause active" role="button"><span class="blind">정지할것</span></a>
                  </div>
                  <a href="#" class="btn next" role="button"><span class="blind">다음</span></a>
             </div>
            </div>
         </div>
       </div>
//swiper slide 적용
 const slide1 = new Swiper(".slide1 .swiper", {
        loop:true,
        autoplay: {
          delay: 2000,
          disableOnInteraction: false,
        },
        pagination: {
          el: ".fraction",
          type: "fraction",
        },
        navigation: {
          nextEl: ".next",
          prevEl: ".prev",
        },
    });
   const slide2 = new Swiper(".slide2 .swiper", {
        loop:true,
        autoplay: {
          delay: 2000,
          disableOnInteraction: false,
        },
        pagination: {
          el: ".fraction",
          type: "fraction",
        },
        navigation: {
          nextEl: ".next",
          prevEl: ".prev",
        },
    });
    slide2.autoplay.stop(); // 처음엔 slide2 재생 멈춤 상태로 선언
    const slide3 = new Swiper(".slide3 .swiper", {
        slidesPerView: 3,
        spaceBetween: 43,
        loop:true,
        autoplay: {
          delay: 2000,
          disableOnInteraction: false,
        },
        pagination: {
          el: ".fraction",
          type: "fraction",
        },
        navigation: {
          nextEl: ".next",
          prevEl: ".prev",
        },
    });

    // 탭버튼 컨트롤
    $('.sc-visual .sc-title-tab').click(function(e){ // h3 클릭 시
        e.preventDefault();
        $(this).parent().addClass('active').siblings().removeClass('active');

        if($(this).parent().hasClass('slide1')){ // 주요뉴스일때
            slide2.autoplay.stop(); // 반대되는 시민참여 자동재생 정지
            if ($('.slide1 .play').hasClass('active')) { // 주요뉴스 재생 상태면
                slide1.autoplay.stop(); // 멈추고
            } else {
                slide1.autoplay.start(); // 주요뉴스 멈춤 상태면 재생
            }
        }else{ // 시민참여일때
            slide1.autoplay.stop(); // 반대되는 주요뉴스 자동재생 정지
            if ($('.slide2 .play').hasClass('active')) { // 시민참여 재생 상태면
                slide2.autoplay.stop(); // 멈추고
            } else {
                slide2.autoplay.start(); // 시민참여 멈춤 상태면 재생
            }
        }
    })
    // 자동재생 컨트롤
    $('.slide1 .auto-play').click(function(e){ // .auto-play 클릭 시
        e.preventDefault();
        if ($(this).find('.play').hasClass('active')) { // 재생 상태면
            slide1.autoplay.start(); // 자동재생
            $(this).find('.pause').addClass('active').siblings().removeClass('active'); // 멈춤 버튼 나타내고 재생 버튼 숨기기
        } else { // 멈춤 상태면
            slide1.autoplay.stop(); // 멈춤
            $(this).find('.play').addClass('active').siblings().removeClass('active'); // 재생 버튼 숨기고 멈춤 버튼 나타내기
        }
    })
    $('.slide2 .auto-play').click(function(e){
        e.preventDefault();
        if ($(this).find('.play').hasClass('active')) {
            slide2.autoplay.start();
            $(this).find('.pause').addClass('active').siblings().removeClass('active');
        } else {
            slide2.autoplay.stop();
            $(this).find('.play').addClass('active').siblings().removeClass('active');
        }
    })
    $('.slide3 .auto-play').click(function(e){
        e.preventDefault();
        if ($(this).find('.play').hasClass('active')) {
            slide3.autoplay.start();
            $(this).find('.pause').addClass('active').siblings().removeClass('active');
        } else {
            slide3.autoplay.stop();
            $(this).find('.play').addClass('active').siblings().removeClass('active');
        }
    })

2-2. 셀렉트 창 선택 후 버튼 클릭 시 새창 이동

  1. 셀렉트 창 옆에 위치한 Go버튼을 눌렀을 때 -> click event
  2. 셀렉트 창에 선택된 벨류 값을 변수로 선언하고 -> val
  3. 윈도우 새창으로 열어주기 -> window.open()
<div class="language-area">
    <label for="lang" class="blind">지역선택</label>
    <select id="lang">
      <option value="http://english.seoul.go.kr/?SSid=101_01">ENGLISH</option>
      <option value="http://japanese.seoul.go.kr/?SSid=101_02">日本語</option>
      <option value="http://chinese.seoul.go.kr/?SSid=101_04">简体中文</option>
      <option value="http://tchinese.seoul.go.kr/?SSid=101_03">繁体中文</option>
      <option value="http://world.seoul.go.kr/">WorldWide</option>
    </select>
    <button type="submit" class="btn-lang" id="langBtn">GO</button>
</div>
$(function(){
    $('#langBtn').click(function(){
        const Url = $('#lang').val();
        window.open(Url);
    });
})

2-3. 하단 탭 네비게이션 슬라이드토글

  1. site-item 의 a를 클릭했을 때 -> click event
  2. 모든 sub-list-wrap들 다 닫아주고 -> slideUp
  3. 해당하는 a의 형제요소인 sub-list-wrap을 슬라이드 토글 -> slideToggle

  1. 만약 해당하는 site-item > a의 자식요소 i에 .active가 있으면 .active를 제거하고 .active가 없으면 모든 i에 .active를 제거 후, 해당하는 a의 자식요소 i에 .active 추가 -> if else 조건문, addClass(),removeClass()
  2. 만약 해당하는 site-item > a의 자식요소에 .active있으면 .active제거하고 .active가 없으면 모든 site-item > a에 .active 제거 후 해당하는 site-item > a에 .active 추가
<li class="site-item">
  <a href="#">직속기관·사업소
  <i class="ic-arrow"><span class="blind">항목열기</span></i>
  </a>
  <div class="sub-list-wrap">
    <ul class="sub-list">
      <li class="sub-item"><a href="#">서울시립대학교</a></li>
    </ul>
  </div>
.site-item{
        width: 33.333%;
        border-left: 1px solid #d0d0d0;
        background: #f7f7f7;
        color: #333;
        text-align: center;
        &:last-child{
            border-right: 1px solid #d0d0d0;
        }
        & > a{
            position: relative;
            display: block;
            width: 100%;
            height: 100%;
            padding: 16px 0;
            &.active{
                background-color: #e2e2e2;
            }
        }
        .ic-arrow{
            position: absolute;
            top: 20px;
            display: inline-block;
            height: 9px;
            width: 9px;
            margin-left: 11px;
            border-style: solid;
            border-color: #373737;
            border-width: 0px 2px 2px 0px;
            transform: rotate(-135deg);
            transition: all .3s cubic-bezier(0.075, 0.82, 0.165, 1);
            transform-origin: center center;
            &.active{
                top: 20px;
                transform: rotate(45deg);
                transform-origin: center center;
            }
        }
    $('.site-item > a').click(function(e){
        e.preventDefault(); // click이벤트 막기
        $('.sub-list-wrap').stop().slideUp();
        $(this).siblings().stop().slideToggle();

        if($(this).find('.ic-arrow').hasClass('active')){
            $(this).find('.ic-arrow').removeClass('active');
        }else{
            $('.ic-arrow').removeClass('active');
            $(this).find('.ic-arrow').addClass('active');
        }

        if($(this).hasClass('active')){
            $(this).removeClass('active');
        }else{
            $('.site-item > a').removeClass('active');
            $(this).addClass('active');
        }
    })

2-4. fixed top 버튼

  1. .btn-top 숨겨놨다가 .active 추가시 나타나게 css 처리
  2. 스크롤 위치값이 0인 변수를 선언하고
  3. 윈도우 창 스크롤을 했을 때 -> $(window).scroll(fuction(){})
  4. 현재 스크롤 위치값 변수 선언 -> .scrollTop()
  5. 만약 현재 스크롤 위치값이 0보다 크면 .active 클래스 추가 -> if else 조건문, addClass(),removeClass()
  .btn-top{
        position: fixed;
        bottom: -100px;
        left: 50%;
        display: block;
        margin-left: 600px;
        opacity: 0;
        transition: 1s;
        z-index: 1000000;
        &::after{
            content: '';
            display: inline-block;
            vertical-align: top;
            width: 34px;
            height: 34px;
            background-image: url(../images/top.png);
            background-repeat: no-repeat;
        }
        &.active{
            bottom: 98px;
            opacity: 1;
        } 
    }
let lastScroll = 0;

    $(window).scroll(function(){
        current = $(this).scrollTop();
        if(current > lastScroll){
            $('.btn-top').addClass('active');
        }else{
            $('.btn-top').removeClass('active');
        }
    });
profile
퍼블리싱 코딩기록

0개의 댓글