서울특별시청

전태수·2023년 7월 11일
0

project

목록 보기
1/7
post-thumbnail

📂 서울특별시청 클론코딩

  • 사이트명: 서울특별시청
  • 라이브러리: swiper, jquery
  • 사용언어: html, css, js
  • 유형: 적응형 PC

✅ Check Point

  • 서울특별시청 클론코딩
  • window.open() 를 이용한 새창열기
  • IR기법
  • 탭버튼 클릭시 활성화되어 슬라이드의 체인지 연동
  • 웹 표준, 웹 접근성에 맞게 tabindex, wai-aria(aria-label)등을 활용하여 마크업
  • CSS 이미지 스프라이트(Image Sprite) 기법 사용
  • 슬라이드 재생/정지
  • 키보드 이벤트(keydown)

1. window.open() 를 활용한 새창열기

⌨ 자바스크립트 window 객체의 open() 함수로 웹브라우저에서 새창(팝업창)을 열 수 있다.

window.open [name]

  • target="_blank" : 팝업을 새창에서 엽니다. target을 설정하지 않을 경우 default로 설정됩니다.
  • target="_parent" : 부모창에서 팝업이 열립니다.
  • target="_self" : 현재 페이지에서 팝업이 열립니다.
  • target="_top" : 현재 페이지에서의 최상의 페이지에서 팝업이 열립니다.

window.open [option]

  • fullscreen : 팝업 전체화면 출력 여부 (no,yes) ( IE에서만 작동 )
  • toolbar : 상단 도구창 출력 여부 (no,yes) ( IE, FireFox에서만 작동 )
  • scrollbars : 팝업 스크롤바 사용 여부 (no,yes)
  • resizeable : 팝업창 리사이즈 가능 여부 (no,yes) ( 크롬에서는 작동 안함)
  • location : 메뉴 아이콘 출력 여부 (no,yes) ( Opera에서만 작동 )
  • menubar : 메뉴 출력 여부 (no,yes)
  • width : 팝업창의 가로길이
  • height : 팝업창의 세로 길이
  • top : 창의 화면 위에서부터 팝업 위치 설정
  • left : 창의 화면 왼쪽에서부터 팝업 위치 설정

🔷 HTML

<div class="lang-area">
   <span class="blind">언어 선택</span> // 접근성 위한 blind 처리
   <select name="" class="select-lang" id="langList">
          <option value="https://www.naver.com/">ENGLISH</option> //링크는 네이버 링크로 설정
          <option value="https://land.naver.com/">日本語</option>
          <option value="https://finance.naver.com/">简体中文</option>
          <option value="https://map.naver.com/v5/">繁体中文</option>
          <option  value="">WorldWide</option>
   </select>
   <input type="button" value="GO" class="btn-select" id="langBtn" aria-label="다국어 페이지로 이동-새창"></input>
</div>
  • 접근성을 위해 IR기법으로 '언어선택' 을 .blind로 넣었고, 스크린리더가 읽을 수 있도록 처리했다.
  • 접근성 추후 과정 설명을 위해 aria-label="다국어 페이지로 이동-새창" 넣음.

⭐ WAI-ARIA란?

WAI-ARIAWeb Accessibility Initiative’s Accessible Rich Internet Applications의 약자로, 스크린리더가 브라우저를 읽을 때 각 요소가 어떤 역할을 하는지 무슨 의미로 존재하는지 알 수 있도록 하기 위해 만들어진 기술이다. 또, 자바스크립트나 다른 동적 언어로 인해 페이지의 요소가 바뀌더라도 새로고침을 하지 않아도 스크린 리더가 바뀐 요소를 읽어준다.

스크린 리더란 브라우저를 시각적으로 읽는 것이 불편한 사용자를 위해 컴퓨터 화면을 낭독해주는 소프트웨어다. 우리가 웹페이지를 만들 때 시멘틱 태그를 사용하지 않고, 시각적으로 꾸미기 위해 일부 속성을 사용하지 않는다면 스크린 리더 사용자가 이 웹페이지를 읽거나 사용하기가 굉장히 어려울 것이다.

예를 들어, 카카오톡 화면 하단의 홈, 채팅, 뷰, 쇼핑, 더보기 버튼에 아무런 아이콘이 없다면 우리가 사용하는 데 있어서 굉장히 불편할 것이다. 우리가 각 버튼 아이콘을 div 태그로만 감싸놓고 아무런 설명도 붙이지 않는다면 스크린 리더 사용자는 이 버튼이 버튼인지, 링크인지, 그냥 이미지인지 구분하기가 어려울 것이다.

사실 aria는 액세스 가능한 도움말이나 설명 텍스트를 추가할 수 있는 유일한 방법이다.

  1. aria-label을 사용하여 액세스 가능한 레이블로 사용할 문자열을 지정할 수 있다.
  2. aria-label은 label요소처럼 다른 네이티브 레이블링 매커니즘을 모두 무시한다.
  3. 텍스트 대신 그래픽을 사용하는 버튼과 같이, 요소의 목적을 시각적으로 표시할 때, aria-label 속성을 사용할 수 있다.

🔶 SCRIPT

$('#langBtn').click(function(){
   url=$('#langList').val()
   window.open(url);
})
  • #langList의 value값을 url에 담고, window.open(url)에 넣어 새창으로 열리는 스크립트 완성.

2. 탭버튼 클릭(활성화)하면 슬라이드 체인지 연동

🔷 HTML

<section class="sc-slide">
	<span class="blind">슬라이드 영역</span>
    <div class="group-nav">
    	<a href="" role="button" class="btn-nav news active" data-idx="1" aria-selected="true"><span>주요뉴스</span></a>
        <a href="" role="button" class="btn-nav citizen" data-idx="5" aria-selected="flase"><span>시민참여</span></a>
    </div>
    <div class="group-slide">
    	<div class="swiper">
        	<div class="swiper-wrapper">
            	<div class="swiper-slide">
                   <a href="">
                     <figure>
                     	<img src="./assets/images/mainSlide-img01.jpg" alt>
                     </figure>
                     <p class="desc">
                     	<span class="blind">주요뉴스</span>
                     	영유아 발달 걱정된다면? '서울아이발달지원센터' 무료 검사
                     </p>
                   </a>
                </div>
                 .
                 .
               <-- 이하 swiper-slide 생략 -->
       	  </div>
      </div>
 	</div>
 </section>

🌈 CSS

.sc-slide .group-nav {
    display: flex;
    flex-direction:column;
    position: absolute;
    width: 80px;
    top: 0;
    left: 0;
    height: 100%;
}

.sc-slide .group-nav .btn-nav {
    flex:1;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    position: relative;
    background: #d2e1e9;
    color: #333;
    font-size:14px;
    font-weight:700;
    
}
.sc-slide .group-nav .btn-nav.active {
    background: #0158a8;
    color:#fff;
}
.sc-slide .group-nav .btn-nav.active:after {
    content: " ";
    position: absolute;
    z-index: 10;
    left: 99%;
    top: 50%;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 25px 0 25px 32px;
    border-color: transparent transparent transparent #0158a8;
    margin-top: -25px;
}

.sc-slide .group-nav .btn-nav:before{
    content:"";
    width: 50px;
    height: 50px;
    margin: 0 9px 10px;
    border-radius: 50%;
}
.sc-slide .group-nav .btn-nav.news:before {background-position:0 0; }
.sc-slide .group-nav .btn-nav.citizen:before {background-position:-50px 0;}


.sc-slide .group-slide {margin-left: 80px;}
  • 좌측에 탭버튼(.group-nav)을 absolute로 띄워 자리하게 하고 우측 슬라이드(.group-slide)를 margin-left:80px; 통해 탭 영역만큼 띄워줌.

🔶 SCRIPT


const mainSlide = new Swiper('.sc-slide .swiper',{
    loop:true,
    autoplay: {
        delay: 3300,
        disableOnInteraction: false,
    },

    pagination:
    {
    	el:'.fraction',
    	type:"fraction"
    },
   	navigation:{
    	nextEl:'.next',
    	prevEl:'.prev'
        },
        on:{
            "slideChange":function(){
                if(this.realIndex >= 4){
                    $('.sc-slide .group-nav .btn-nav.citizen').addClass('active').siblings().removeClass('active')           
                }else{
                    $('.sc-slide .group-nav .btn-nav.news').addClass('active').siblings().removeClass('active')
                }
            }
        }

    });

    $('.sc-slide .group-nav .btn-nav').click(function(e){
        e.preventDefault(); //a태그의 이벤트를 막아준다
        idx=$(this).data('idx');
        $(this).addClass('active').siblings().removeClass('active');

        mainSlide.slideTo(idx)

     });
 
  • 탭버튼(.group-nav .btn-nav)을 클릭했을 때, 슬라이드의 index 번호로 체인지될 수 있게 연동했다.
  • on:{} 콜백함수를 활용하여, const mainSliderealIndex 를 구하고, if else를 통해 원하는 슬라이드 번호(4)에서 탭 활성화가 되면서 슬라이드 역시 연동되어 변경되도록 하였다.

swiper 콜백함수 종류

3. 슬라이드 재생/정지

🔷 HTML

<div class="control-area">
	<div class="fraction">99/99</div>
	<div class="btn-wrap">
		<button class="btn-nav prev"><span class="blind">이전</span></button>
		<button class="btn-nav autoplay aria-label="자동재생 정지"><span class="blind">자동재생 정지</span></button>
		<button class="btn-nav next"><span class="blind">다음</span></button>
	</div>
</div>

🌈 CSS

.sc-slide .control-area{
    position: absolute;
    z-index: 10;
    bottom: 4px;
    right: 3px;
    display: flex;
    align-items: center;
    height: 32px;
    color: #fff;
}
.sc-slide .control-area:before {
    content:"";
    position: absolute;
    top: 7px;
    right: 68px;
    width: 1px;
    height: 18px;
    background:rgba(255,255,255,.5);
}

.sc-slide .control-area .fraction{font-size: 13px; width:auto;}
.sc-slide .control-area .btn-wrap{
    display: flex;
    margin-left: 25px;
}
.sc-slide .control-area .btn-nav{
    width: 20px; 
    height: 20px;
}

.sc-slide .control-area .prev {
    background-position: -241px -284px;
}
.sc-slide .control-area .autoplay{background-position: -283px -284px;}
.sc-slide .control-area .autoplay.active{background-position: -269px -284px;}
.sc-slide .control-area .next{background-position: -255px -284px;}
  • btn-nav 에 속하는 .prev, .autoplay, .next 들은 .btn-wrap으로 묶어 마크업 했다.
  • .btn-wrap의 .autoplay , .next , .prev 각 아이콘은 이미지 스프라이트(Image Sprite) 기법으로 넣었따.

🔶 SCRIPT

$('.sc-slide .autoplay').click(function(){
        if($(this).hasClass('active')) {
            $(this).removeClass('active').attr('aria-label','자동재생 정지');
            mainSlide.autoplay.start();
        }else{
            $(this).addClass('active').attr('aria-label','자동재생 적용');
            mainSlide.autoplay.stop();
        }
    });
  • if~else 조건문을 통해 각각의 슬라이드 start와 stop의 조건을 걸어줬다.
  • 접근성을 위해 .autoplayaria-label의 텍스트를 변경할 수 있도록 했다.(스크린 리더기)

4. 키보드 이벤트(keydown)/접근성

🔶 SCRIPT

$('.sc-related .sub-item a').keydown(function(e){
        const key = e.keyCode;
    
      if(key === 9){
          const isShiftPressed = e.shiftKey;
          const isLastChild = $(this).parent().is(':last-child');
            
          if ((isShiftPressed && !isLastChild) || (!isShiftPressed && isLastChild)) {
             $('.sc-related .btn-related').removeClass('active').siblings('.sub-area').slideUp(200);
       }
    }
});
  • 키보드 이벤트(Keyboard Event)는 사용자가 키를 누르거나 키를 놓을 때 발생한다. 키를 누를 때는 keydown 타입의 이벤트가 발생하고, 키를 놓을 때는 keyup 타입의 이벤트가 발생한다.
  • 현재 코드에서는 키보드의 tab키를 눌렀을 때 이벤트를 발생하게 해야 하기 때문에, keycode로 찾은 결과, tab키는 9번에 해당되므로 if문에서 === 9 조건문을 넣어줬다.
  • shift+tab 을 눌렀을 때 slideUp 이 되게 하였고, tab키가 .sub-item a:last-child에 도달했을 때 slideUp이 되는 이벤트 조건을 넣었다.
  • 📌 키보드 이벤트 객체에는 눌리거나 놓아진 키에 대한 다양한 메타정보가 담겨 있다. 예를 들어 key 속성에는 키 값이, code 속성에는 코드 값이, shiftKey 속성에는 쉬프트키가 함께 눌렸는지 여부가 저장된다.
profile
Publisher

0개의 댓글