Seoul city PC 클론코딩

yunazzi·2024년 3월 7일
post-thumbnail

📌 Seoul city PC

  • 사이트명 : 서울시청 PC
  • 작업기간 : 2일
  • 사용언어 : HTML5,CSS3,Jquery
  • 라이브러리 : Swiper
  • 분류 : PC 적응형 웹사이트
  • URL : https://yunazzi.github.io/seoul/

Point ✅

✔️ 속성 value값으로 주소이동 (window.open())
✔️ 구조 및 검색엔진
✔️ 사용자 편의성을 위한 본문 바로가기버튼, 태그의 나열순서, key down이벤트, 맨위로 버튼
✔️ 탭버튼 클릭시 활성화되어 슬라이드의 체인지 연동


🔖 속성 value값으로 주소이동 (window.open())

select박스로 각 나라별 언어를 옵션으로 두고 선택할 수 있고, go버튼을 누르면 선택한 옵션에 해당하는 홈페이지로 이동한다.

① select 박스를 구성하고, option의 value값에 이동할 url을 넣어준다.

//html
<div class="lang-area">
	<label for="lang"><span class="blind">언어선택</span></label>
	<select name="" id="lang">
		<option value="https://english.seoul.go.kr/?SSid=101_01">ENGLISH</option>
		<option value="https://japanese.seoul.go.kr/?SSid=101_02">日本語</option>
		<option value="https://chinese.seoul.go.kr/?SSid=101_04">简体中文</option>
		<option value="https://tchinese.seoul.go.kr/?SSid=101_03">繁体中文</option>
		<option value="https://world.seoul.go.kr/">WorldWide</option>
	</select>
	<button class="btn-go">GO</button>
</div>

② .btn-go를 클릭하면, #lang의 value값으로 저장된 변수url을 새창으로 연다.

//javascript
$('.lang-area .btn-go').click(function(){
	url = $('#lang').val();
	window.open(url);
})

url = $('#lang').val(); - #lang요소의 value값을 가져와 'url'변수에 저장한다.
window.open(url); - 'url'변수에 저장된 주소를 새 창으로 연다.


🔖 구조 및 검색엔진

IR기법(Image Replacement)/WAI-ARIA

이미지를 볼 수 없는 사용자들에게 대체텍스트를 제공하는 기법, 검색엔진과 스크린리더에는 노출이 되면서 시각적으로만 숨겨짐.

☑️ 각 섹션 제목이 시각적으로 보이지 않는 경우에도 IR기법 처리

//로고 예시
<h1 class="logo"><a href=""><span class="blind">서울특별시 로고</span></a></h1>
//제목 예시
<section class="sc-visual">
	<h2 class="blind">뉴스 및 참여</h2>
</section>

☑️ 검색엔진 상 노출이 중요하지 않은 부분은 aria-label로 처리

<button class="prev" aria-label="이전슬라이드"></button>
<button class="play" aria-label="자동재생 시작"></button>
<button class="pause" aria-label="자동재생 일시정지"></button>
<button class="next" aria-label="다음슬라이드"></button>

☑️중복되는 정보는 따로 기재하지 않는다.

예시 > .desc이 이미지 내용을 설명하고 있기 때문에 alt값을 입력하지 않음

<li class="swiper-slide">
	<a href="">
		<img src="이미지" alt>
		<p class="desc">새해 복 많이 받으세요 2024 갑진년 설 연휴 종합정보</p>
	</a>
</li>

⚠️ 주의 - <img alt=""> 형식은 입력되지 않은 정보로 인식하므로, <img alt>와 같은 형식으로 등호와 따옴표도 확실하게 지워야함.

🔖 사용자 편의성을 위한 본문 바로가기버튼, 태그의 나열순서, key down이벤트, 맨위로 버튼

① 본문 바로가기버튼

스크린리더를 이용하는 사용자는 매 페이지 이동시마다 헤더부터 다시 읽어야하는 상황이 발생한다.
그리고 탭버튼을 불필요하게 많이 눌러야하는데 본문 바로가기버튼을 만들어서 헤더의 내용을 건너뛸 수 있게 해주면 이런 불편함을 해소할 수 있다.

ⓐ a 태그를 이용해 버튼을 만들어주고, href 속성은 main 태그의 id값과 맞춰준다.

<div id="skipNav">
	<a href="#main">본문내용</a>
</div>

<main class="container" id="main"></main>

ⓑ CSS를 이용해서 평소에는 가려져 있다가 tab버튼을 눌러 포커스가 잡히면 버튼이 보이도록 해준다.

#skipNav a{
position: absolute; top: 0; left: 0; 
width: 200px; height: 50px; line-height: 50px; 
background: #000; color: #fff; text-align: center; 
transform: translateY(-100%); 
}
#skipNav a:active, 
#skipNav a:focus{ transform: translateY(0%); }

② 태그의 나열순서

영역제목 옆에 전체보기 버튼이 있는 경우라도 아래순으로 읽는 것이 자연스럽다.
ⓐ 영역의 제목
ⓑ 영역의 내용들
ⓒ 영역 전체보기 버튼

마크업 시 위 순서를 고려하여 코딩하는 것이 사용자에게 더 편리함 !
더보기 버튼은 position:absolute를 이용하여 위치를 따로 잡아준다.

<section class="sc-board event">
	<h2 class="headline">이벤트 신청</h2>
	<ul>
		<li>
			<span class="title-wellfare">복지</span>
			<a href="" class="desc">서울시보건환경연구원의 3대 주요 뉴스 투표 이벤트</a>
		</li>
        ...
	</ul>
    <a href="" class="more-btn"><span class="blind">더보기</span></a>
</section>

③ key down이벤트

사용자의 편의성을 위해서 키보드 접근만으로도 탭을 쉽게 여닫을수 있도록 스크립트를 구성했다.

$('.sc-relate .btn').click(function(){
	if ($(this).hasClass('on')) {
		$('.sc-relate .btn').removeClass('on').siblings().stop().slideUp()
	}else {
		$('.sc-relate .btn').removeClass('on').siblings().stop().slideUp()
		$(this).addClass('on').siblings().stop().slideDown()
	}
})

.sc-relate .btn을 클릭하면, 클릭한 버튼에 .on이 있으면, 버튼에 .on을 제거하고 슬라이드가 닫히게 버튼에 .on이 없으면, 내가 클릭한 곳에 .on을 추가하고 슬라이드가 위로 올라오게 설정해준다.

🖍 키보드 이벤트 편의성

//첫번째 버튼에서 shift+tab 버튼 누를시 닫히기
$('.sc-relate .sub li:first-child').keydown(function(e){
	// shift - 16 / tab - 9
	if (e.keyCode === 9 && e.shiftKey) {//shift키 유무 눌렀냐 안눌렀냐
		$('.sc-relate .btn').removeClass('on').siblings().stop().slideUp()
	}
})

$('.sc-relate .sub li:first-child').keydown(function(e){ - .sc-relate요소안에서 .sub내에 있는 첫번째 li요소에 키를 누를때마다 이벤트함수 실행
if (e.keyCode === 9 && e.shiftKey) - 눌린 키가 (tab = 9)tab키 + shift키가 눌렸다면 (참일 경우), .sc-relate .btn에 .on을 제거하고 형제(.sub)들을 슬라이드업한다.

.
(→ 동시에 눌러야지만 참의 조건이 활성화되고 shift + tab을 누르면 왼쪽으로 움직이고, 첫번째 li요소에 있을때 shift+tab을 같이 누르면, 슬라이드 창이 닫힘)


// 마지막 버튼에서 tab 버튼 누를시 닫히기
$('.sc-relate .sub li:last-child').keydown(function(e){
	if (e.keyCode === 9 && !e.shiftKey) {
		$('.sc-relate .btn').removeClass('on').siblings().slideUp()
	}
})

$('.sc-relate .sub li:last-child').keydown(function(e){ - .sc-relate요소안에서 .sub내에 있는 마지막 li요소에 키를 누를때마다 이벤트함수 실행
if (e.keyCode === 9 && !e.shiftKey) - 눌린 키가 (tab=9)tab키 + shift키가 눌리지 않았다면 (참일경우), .sc-relate .btn에 .on을 제거하고 형제(.sub)들을 슬라이드업한다.

.
(→ tab키만 눌려야지만 참의 조건이 활성화되고 tab을 누르면 오른쪽으로 움직이고, 마지막 li요소에있을때 tab키를 누르면, 슬라이드창이 닫힘)

④ 맨위로 가기 버튼

스크롤다운을 하면 gotop버튼이 나타나고, 버튼을 클릭하면 페이지 맨 위로 가는 버튼구성

//html
<div class="btn-gotop">
  <a href="">
    <span class="blind">페이지 상단으로</span>
  </a>
</div>

position:fixedbottom, left를 이용하여 페이지 우측하단에 고정시켜주고, opacity, bottom, transition 속성을 활용하여 버튼이 떠오르면서 페이드인 / 아웃이 되도록 구성해준다.

//css
.btn-gotop{
position: fixed; z-index: 10000; opacity: 0;
margin-left: 600px; transition: 1s; 
width: 34px; height: 34px; bottom: -10%; left: 50%;
background-image: url(../images/btn_top.png); 
background-repeat: no-repeat; 
}
.btn-gotop.show{ opacity: 1; bottom: 10%; }
//javascript
$(window).scroll(function(){
	curr = $(this).scrollTop();
	if (curr>=20) {
		$('.btn-gotop').addClass('show');
	} else {
		$('.btn-gotop').removeClass('show');
	}
})

$('.btn-gotop').click(function(){
	window.scrollTo({top:0,behavior:"smooth"});
})

현재의 스크롤값을 변수 curr에 담고, 현재값이 20 보다 크거나 같으면 (참일 경우) .btn-gotop버튼에 .show을 추가하고(페이드인 되게끔 opacity, bottom 속성값을 바꿈) 거짓일 경우 .btn-gotop에 .show를 제거한다.

.btn-gotop을 클릭하면 윈도우를 top:0값으로 이동(맨위로 이동), behavior:"smooth" 부드럽게 움직인다.

🔖 탭버튼 클릭시 활성화되어 슬라이드의 체인지 연동

아래 동영상에서 보이듯 주요뉴스와 시민참여 탭에 해당하는 슬라이드로 이동하게 된다.
또한 prev, next버튼으로 슬라이드를 좌우로 움직이고 일시정지 버튼으로도 슬라이드 재생,멈춤을 할 수 있다. (슬라이드를 좌우로 넘기면서도 컨트롤 가능)
<동영상>

//html
<section class="sc-visual">
	<h2 class="blind">뉴스 및 참여</h2>
	<div class="tab-nav">
		<button class="tab news active" data-idx="0">주요뉴스</button>
		<button class="tab citizen" data-idx="3">시민참여</button>
	</div>
	<div class="swiper main-slide"> // index - 0
		<ul class="swiper-wrapper">
			<li class="swiper-slide">
				<a href="">
					<img src="이미지" alt>
					<p class="desc">떡국 먹고 뭐하니? 특별한 문화행사가 연휴 내내 열려용~</p>
				</a>
			</li>
			<li class="swiper-slide"> // index - 3
				<a href="">
					<img src="이미지" alt>
					<p class="desc">츄릅~ 서울라면 2종 출시…성수동 '서울 굿즈샵'에서 공개</p>
				</a>
			</li>
		</ul>
		<!-- control -->
		<div class="control-area">
			<div class="fraction">99/99</div>
			<button class="btn-prev"><span class="blind">이전버튼</span></button>
			<button class="btn-autoplay" data-slide="0"><span class="blind">일시정지버튼</span></button>
			<button class="btn-next"><span class="blind">다음버튼</span></button>
		</div>
	</div>
</section>

① 탭으로 페이지이동

//javascript
const mainSlide = new Swiper('.main-slide',{
        autoplay:{
            delay:5000,
            disableOnInteraction:false
        },
        loop:true,
        pagination:{
            el:".fraction",
            type:"fraction"
        },
        navigation:{
            nextEl:".btn-next",
            prevEl:".btn-prev"
        }
    })

    $('.tab-nav .tab').on('click',function(){    
        idx = $(this).data('idx');
    
        $(this).addClass('active').siblings().removeClass('active');
        //슬라이드 특정번째로 이동
        // mainSlide.slideTo(idx) 루프가 아닐때
        mainSlide.slideToLoop(idx) /* 루프가 있을때 */
    })

    mainSlide.on("slideChange",function(){
        // console.log(this.realIndex);
        idx = $('.tab.citizen').data('idx')

        if (this.realIndex >= idx) {
            $('.tab.citizen').addClass('active').siblings().removeClass('active');
        } else {
            $('.tab.news').addClass('active').siblings().removeClass('active');
        }
    })

pagination:fraction - 페이지 번호를 표시할 요소를 지정해주는 페이지네이션
idx = $(this).data('idx');- 클릭된 요소(this)의 data-idx속성을 idx변수에 저장
navigation:{nextEl:".btn-next"} - 네비게이션 다음요소의 클래스
navigation:{prevEl:".btn-prev"} - 네이게이션 이전요소의 클래스

data-idx속성은 클릭된 탭의 인덱스를 나타냄
$(this).addClass('active').siblings().removeClass('active'); - 클릭된 탭(this)에 .active를 추가하고, 해당탭의 형제요소들에서 .active를 제거한다.
mainSlide.slideToLoop(idx) - 슬라이드를 특정 인덱스를 이동시킴(idx)
slideToLoop() 함수는 Swiper 슬라이더를 루프로 이동시키는 데 사용된다.


```css .sc-visual .tab-nav .tab.active{ background: #0158a8; color: #fff; } ```

🖍 mainslide를 슬라이드바꾸기
.tab의 .citizen(시민참여 탭)의 data-idx의 값을 변수 idx에 담는다 (값 = 3)

먄약 현슬라이드의 realIndex가 idx(3)값보다 크거나 같으면 (참일경우),(3,4)
.tab.citizen(시민참여 탭)에 .active를 추가하고 형제요소들에 .active를 제거한다.
(active = 파란색으로 바탕칠함)

반대일 경우(realIndex가 3보다 작음),(0,1,2)
.tab.news(뉴스 탭)에 .active를 추가하고 형제요소들에 .active를 제거한다.
(active = 파란색으로 바탕칠함)


🖍 mainslide 버튼클릭으로 슬라이드바꾸기

//html
<section class="sc-visual">
	<h2 class="blind">뉴스 및 참여</h2>
	<div class="tab-nav">
		<button class="tab news active" data-idx="0">주요뉴스</button>
		<button class="tab citizen" data-idx="3">시민참여</button>
	</div>
	<div class="swiper main-slide"> // index - 0
		<ul class="swiper-wrapper">
			<li class="swiper-slide">
				<a href="">
					<img src="이미지" alt>
					<p class="desc">떡국 먹고 뭐하니? 특별한 문화행사가 연휴 내내 열려용~</p>
				</a>
			</li>
			<li class="swiper-slide"> // index - 3
				<a href="">
					<img src="이미지" alt>
					<p class="desc">츄릅~ 서울라면 2종 출시…성수동 '서울 굿즈샵'에서 공개</p>
				</a>
			</li>
		</ul>
		<!-- mainslide control -->
		<div class="control-area">
			<div class="fraction">99/99</div>
			<button class="btn-prev"><span class="blind">이전버튼</span></button>
			<button class="btn-autoplay" data-slide="0"><span class="blind">일시정지버튼</span></button>
			<button class="btn-next"><span class="blind">다음버튼</span></button>
		</div>
	</div>
</section>
		<!--bannerSlide control-->
		<div class="control-area">
			<div class="fraction">99/99</div>
			<button class="btn-prev"><span class="blind">이전버튼</span></button>
			<button class="btn-autoplay" data-slide="1"><span class="blind">일시정지버튼</span></button>
			<button class="btn-next"><span class="blind">다음버튼</span></button>
		</div> 
//javascript
slideArr=[mainSlide,bannerSlide];
    $('.btn-autoplay').click(function(){
        idx=$(this).data('slide');

        if ($(this).hasClass('on')) {
            $(this).removeClass('on')
            slideArr[idx].autoplay.start()
        } else {
            $(this).addClass('on')
            slideArr[idx].autoplay.stop()
        }
    })

slideArr=[mainSlide,bannerSlide]; - 이 부분은 mainSlide와 bannerSlide를 포함하는 배열 slideArr를 생성하고, 이 배열은 각 슬라이드에 대한 참조를 유지한다.

$('.btn-autoplay').click(function(){ - .btn-autoplay를 클릭하면 함수가 작동된다.
idx=$(this).data('slide'); - .btn-autoplay의 data-slide를 idx변수에 담아 저장한다.(mainSlide의 data-slide=0,bannerSlide의 data-slide=1)
if ($(this).hasClass('on')) { - 만약에 this(.btn-autoplay)에 .on을 가지고있다면(참일 경우), this에 .on을 제거하고 해당슬라이드에 자동재생을 시작한다.
else { - 반대라면(거짓일 경우), this에 .on을 추가하고 해당슬라이드에 자동재생을 멈춘다.

참고사이트
https://blog.munilive.com/posts/keyboard-keycode-value.html
https://stackoverflow.com/questions/33374130/event-keycode-13-not-working-in-firefox
https://velog.io/@sutrong7/swiper-%ED%83%AD-%EB%B2%84%ED%8A%BC-%EB%88%84%EB%A5%B4%EB%A9%B4-%ED%8A%B9%EC%A0%95-%EC%8A%AC%EB%9D%BC%EC%9D%B4%EB%93%9C%EB%A1%9C-%EC%9D%B4%EB%8F%99
https://velog.io/@yooahreum7473/작성테스트

profile
뚝딱뚝딱 열심히 공부 중 이예요!

0개의 댓글