[인스타클론] js와 css를 이용한 이미지 크로스페이드

unu·2021년 5월 16일
0

JavaScript

목록 보기
4/4

인스타그램의 로그인 페이지 오늘은 인스타그램 로그인 페이지의 이미지 크로스페이드를 따라해보려한다.
<div class="screen-images">
    <img class="screenshot 1" src="img/screenimage1.jpg" alt="screen1"/>
    <img class="screenshot 2" src="img/screenimage2.jpg" alt="screen2"/>
    <img class="screenshot 3" src="img/screenimage3.jpg" alt="screen3"/>
    <img class="screenshot 4" src="img/screenimage4.jpg" alt="screen4"/>
    <img class="screenshot 5" src="img/screenimage5.jpg" alt="screen5"/>
</div>

시행착오를 많이 겪었다.

방법 1

클래스를 붙였다 떼는 방식
유튜브에 검색해서 따라했는데, 출처를 확인할 수가 없다..

const firstSlide = document.querySelector('.screenshot:first-child');//첫번째 슬라이드는 .screenshot의 첫번째 자식이다.

setInterval(slide, 4000); //슬라이드 함수를 4초에 한 번씩 실행시킬 것

function slide(){
	const showingClass = "showing";
	const currentSlide = document.querySelector(`.${showingClass}`);
	if(currentSlide){ //커런트 슬라이드가 있다면 이어서, 없다면 끝으로
		firstSlide.classList.remove(showingClass);
      		//첫번째 슬라이드의 showing제거
		const nextSlide = currentSlide.nextElementSibling;
      	//커런트슬라이드의 형제요소는 넥스트 슬라이드
		if(nextSlide){ //넥스트 슬라이드가 있다면
			currentSlide.classList.remove(showingClass);
          		//커런트 슬라이드의 showing제거
			nextSlide.classList.add(showingClass);
          		//넥스트 슬라이드를 커런트 슬라이드로.
		}else{ //넥스트 슬라이드가 없다면
			currentSlide.classList.remove(showingClass);
          		//커런트 슬라이드의 showing제거
			firstSlide.classList.add(showingClass);
			//첫번째 슬라이드를 커런트 슬라이드로
		}
	}else{ //커런트슬라이드가 없다면 첫번째슬라이드가 커런트슬라이드가 된다.
		firstSlide.classList.add(showingClass)
	}
}

문제: 이미지 하나하나의 페이드만 되고 크로스페이드가 안된다.

방법 2

배열api를 이용해서 이미지 순환시키기

const imageArr = ["img/screenimage1.jpg","img/screenimage2.jpg","img/screenimage3.jpg","img/screenimage4.jpg","img/screenimage5.jpg"];
//이미지 주소를 배열로 만든다.

const first = document.querySelector('.screenshot:nth-child(1)');
const second = document.querySelector('.screenshot:nth-child(2)');
const third = document.querySelector('.screenshot:nth-child(3)');
const fourth = document.querySelector('.screenshot:nth-child(4)');
const fifth = document.querySelector('.screenshot:nth-child(5)');
//1,2,3,4,5번째 슬라이드를 각각 선언해주고

first.setAttribute("src", imageArr[0]);
second.setAttribute("src", imageArr[1]);
third.setAttribute("src", imageArr[2]);
fourth.setAttribute("src", imageArr[3]);
fifth.setAttribute("src", imageArr[4]);
//각각의 src도 imageArr의 인덱스를 통해 설정해준다.

iterateImage 함수를 통해 imageArr의 인덱스를 순환시킨다.

function iterateImage(){
	const firstElement = imageArr.shift();
  	//firstElement는 imageArr.shift 값이다.
  	//shift() 메서드는 배열에서 첫 번째 요소를 제거하고, 제거된 요소를 반환한다.
  
	imageArr.push(firstElement);
  	//push() 메서드는 배열의 끝에 하나 이상의 요소를 추가하고, 배열의 새로운 길이를 반환한다.
	// → shift된 첫번째 요소를 배열의 맨 뒤로 push한 새로운 배열이 반환된다. 
	
  	first.setAttribute("src", imageArr[0]);
	second.setAttribute("src", imageArr[1]);
	third.setAttribute("src", imageArr[2]);	
  	fourth.setAttribute("src", imageArr[3]);
	fifth.setAttribute("src", imageArr[4]);
	//이미지 태그는 가만히 있고, 태그 안의 src값만 순환하며 설정된다.
  
  	return imageArr;
}


setInterval(iterateImage, 5000);

문제: 이미지 순환의 문제는 없는데 크로스 페이드가 먹히지 않는다. 정확히는 처음한번만 fade-out 된다.

.screenshot {
  position: absolute;
  width: 240px;
  height: 427px;
  opacity: 1;
  z-index: 0;
}
 /*첫번째 슬라이드는 opacity 100% → 0% .*/
.screenshot:first-child {
  z-index: 2;
  opacity: 1;
  animation: fade-out 5s linear;
}
.screenshot:nth-child(2) {
  z-index: 1;
  opacity: 1;
}
@keyframes fade-out {
  /*점점 사라진다.*/
  0%,
  80% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

이유는 이미지 태그가 움직이는 게 아니라서 그런 것 같다. 첫번째 스크린샷의 이미지태그에 애니메이션을 적용했는데 변화하는 건 이미지 태그가 아니라 src라서...

방법 3

방법 1을 참고해서 변형했다.
1) showClass, waitClass라는 2개의 클래스 달아주기
크로스페이드 트랜지션을 위해서는 보였다가 사라지는 이미지와 뒤에서 대기하는 이미지, 두 개의 엘리먼트가 필수적이다. 때문에 방법 1에서와 다르게 wait 클래스를 추가했다.

<div class="screen-images">
     <img class="screenshot 1 show" src="img/screenimage1.jpg" alt="screen1"/>
     <img class="screenshot 2 wait" src="img/screenimage2.jpg" alt="screen2"/>
     <img class="screenshot 3" src="img/screenimage3.jpg" alt="screen3"/>
     <img class="screenshot 4" src="img/screenimage4.jpg" alt="screen4"/>       
     <img class="screenshot 5" src="img/screenimage5.jpg" alt="screen5"/>
</div>

2) 클래스 돌리기
방법 1을 변형한 if문 알고리즘을 생각하다가 백번 정도 막혀서 처음에 사용했던 알고리즘을 두번 쓰기로 했다.

const firstSlide = document.querySelector('.screenshot:first-child');

setInterval(showSlide, 4900);
setInterval(waitSlide, 4900);

function showSlide(){
	const showClass = "show";
	const currentSlide = document.querySelector(`.${showClass}`);
	if(currentSlide){ //커런트 슬라이드가 있다면 이어서, 없다면 끝으로
		firstSlide.classList.remove(showClass);
      		//첫번째 슬라이드의 show제거
		const nextSlide = currentSlide.nextElementSibling;
      		//커런트슬라이드의 형제요소는 넥스트 슬라이드
		if(nextSlide){ //넥스트 슬라이드가 있다면
			currentSlide.classList.remove(showClass);
          		//커런트슬라이드의 show제거
			nextSlide.classList.add(showClass); 
          		//넥스트 슬라이드를 커런트 슬라이드로
		}else{ //넥스트 슬라이드가 없다면
			currentSlide.classList.remove(showClass);
			firstSlide.classList.add(showClass);
          		//첫번째 슬라이드를 커런트 슬라이드로
		}
	}else{ //커런트슬라이드가 없다면 첫번째 슬라이드가 커런트슬라이드가 된다.
		firstSlide.classList.add(showClass)
	}
}

function waitSlide(){
	const waitClass = "wait"
	const waitSlide = document.querySelector(`.${waitClass}`);
	if(waitSlide){ //웨잇슬라이드가 있다면 이어서, 없다면 끝으로
		secondSlide.classList.remove(waitClass);
      		//첫번째 슬라이드의 wait제거
		const nextSlide = waitSlide.nextElementSibling;
      		//웨잇슬라이드의 형제요소는 넥스트 슬라이드
		if(nextSlide){ //넥스트 슬라이드가 있다면
			waitSlide.classList.remove(waitClass);
			nextSlide.classList.add(waitClass);
          		//넥스트 슬라이드를 웨잇슬라이드로
		}else{ //넥스트 슬라이드가 없다면
			waitSlide.classList.remove(waitClass);
			firstSlide.classList.add(waitClass);
          		//첫번째 슬라이드를 웨잇슬라이드로
		}
	}else{ //웨잇슬라이드가 없다면 첫번째 슬라이드가 웨잇슬라이드가 된다.
		firstSlide.classList.add(waitClass)
	}
}

두 함수가 아주 비슷하기 때문에 재사용이 가능하도록 합쳐서 바꾸었다.

최종_최종.js

const firstSlide = document.querySelector('.screenshot:first-child');
const showClass = "show";
const waitClass = "wait";

setInterval(function(){slide(showClass), slide(waitClass)}, 4900);
//4.9초 마다 두 함수 실행

function slide(theClass){
	const theSlide = document.querySelector(`.${theClass}`);
  	//theSlide는 theClass가 선택자인 엘리먼트
	if(theSlide){ //theSlide가 있다면 이어서, 없다면 끝으로
		firstSlide.classList.remove(theClass);
      		//첫번째 슬라이드의 thsClass제거
		const nextSlide = theSlide.nextElementSibling;
      		//theSlide의 형제요소는 넥스트 슬라이드
		if(nextSlide){ //넥스트 슬라이드가 있다면
			theSlide.classList.remove(theClass);
			nextSlide.classList.add(theClass);
          		//넥스트 슬라이드를 theSlide로
		}else{ //넥스트 슬라이드가 없다면
			theSlide.classList.remove(theClass);
			firstSlide.classList.add(theClass);
          		//첫번째 슬라이드를 theSlide로
		}
	}else{ //theSlide가 없다면 첫번째 슬라이드가 theSlide가 된다.
		firstSlide.classList.add(theClass)
	}
}

코드가 깔끔해졌다!😄
[TIL]

  • 이번에 배운 것, 초기 기획을 잘 해야 시간 허비를 안한다.
  • 복잡한 알고리즘을 소화 못하겠다고 해도 이렇게 돌아보니 결국 간결하고 합리적인 코드 만들 수 있었다.
  • setInterval에서 매개변수를 넣고 싶다거나 하나이상의 함수를 넣고 싶을 때는 익명함수를 쓴다.
  • 배열api는 유사배열에서 안먹히지만 꼼수가 있으니 때에 맞게 사용.
  • element.nextElementSibling: 엘리먼트의 바로 옆에 있는 형제 엘리먼트, 없다면 null이 뜬다.
  • @keyframe{}
profile
나 미대 나온 개발자야~

0개의 댓글