[CSS] 다양한 CSS Slide Animation

css3

이번에는 오직 CSS만 사용하여 여러 종류의 슬라이드를 만들어보도록 하겠습니다.

이 포스트를 접하기 이전에 다음 내용들을 먼저 읽어보고 익히길 바랍니다.

  1. css animation : https://www.w3schools.com/css/css3_animations.asp
  2. only css slide : http://junil-hwang.com/blog/only-css-slide/




자동 가로 슬라이드

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    *{margin:0;padding:0;}
    ul,li{list-style:none;}
    .slide{height:300px;overflow:hidden;}
    .slide ul{width:calc(100% * 4);display:flex;animation:slide 8s infinite;} /* slide를 8초동안 진행하며 무한반복 함 */
    .slide li{width:calc(100% / 4);height:300px;}
    .slide li:nth-child(1){background:#ffa;}
    .slide li:nth-child(2){background:#faa;}
    .slide li:nth-child(3){background:#afa;}
    .slide li:nth-child(4){background:#aaf;}
    @keyframes slide {
      0% {margin-left:0;} /* 0 ~ 10  : 정지 */
      10% {margin-left:0;} /* 10 ~ 25 : 변이 */
      25% {margin-left:-100%;} /* 25 ~ 35 : 정지 */
      35% {margin-left:-100%;} /* 35 ~ 50 : 변이 */
      50% {margin-left:-200%;}
      60% {margin-left:-200%;}
      75% {margin-left:-300%;}
      85% {margin-left:-300%;}
      100% {margin-left:0;}
    }
  </style>
</head>
<body>
  <div class="slide">
    <ul>
      <li></li>
      <li></li>
      <li></li>
      <li></li>
    </ul>
  </div>
</body>
</html>

여기서 핵심이 되는 내용은 다음과 같습니다.

  1. display:flex로 li를 가로로 나열함
  2. ul width = slide width * li count
  3. li width = slide width = ul width / li count * 100%
  4. @keyframes에서 100%를 li count로 등분하여 진행함 (25%간격)
  5. @keyframes의 0%와 100%가 이어짐

뒤에 나올 세로 슬라이드와 페이드 슬라이드도 위의 내용을 조금씩 응용한 형태입니다.



자동 세로 슬라이드

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    *{margin:0;padding:0;}
    ul,li{list-style:none;}
    .slide{height:300px;overflow:hidden;}
    .slide ul{height:calc(100% * 4);animation:slide 8s infinite;}
    .slide li{height:calc(100% / 4);}
    .slide li:nth-child(1){background:#ffa;}
    .slide li:nth-child(2){background:#faa;}
    .slide li:nth-child(3){background:#afa;}
    .slide li:nth-child(4){background:#aaf;}
    @keyframes slide {
      0% {margin-top:0;}
      10% {margin-top:0;}
      25% {margin-top:-300px;}
      35% {margin-top:-300px;}
      50% {margin-top:-600px;}
      60% {margin-top:-600px;}
      75% {margin-top:-900px;}
      85% {margin-top:-900px;}
      100% {margin-top:0;}
    }
  </style>
</head>
<body>
  <div class="slide">
    <ul>
      <li></li>
      <li></li>
      <li></li>
      <li></li>
    </ul>
  </div>
</body>
</html>

여기서 핵심이 되는 내용은 다음과 같습니다.

  1. ul height = slide height * li count
  2. li height = slide height = ul height / li count * 100%
  3. @keyframes에서 100%를 li count로 등분하여 진행함 (25%간격)
  4. @keyframes의 0%와 100%가 이어짐
  5. margin의 경우 width 너비 상속받는다. 즉, margin-top:-100%; 로 할 경우, width만큼 위로 올라가게 된다. 따라서 세로 슬라이드를 할 때는 퍼센트 코딩이 아닌 px 코딩으로 해야한다.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .wrap{width:200px;border:1px;padding:20px;border:1px solid #000;}
    .wrap>div{width:30px;height:30px;border:1px solid #000;margin-top:50%;}
  </style>
</head>
<body>
  <div class="wrap">
    <div></div>
  </div>
</body>
</html>

margin-top:50%;로 했더니 margin-top이 100px이 되었다. 위의 내용으로 알 수 있는 것은 margin은 width를 상속받는 다는 것이다. 얼핏 생각했을 때 margin-top은 height를 상속받는다고 생각할 수도 있지만, margin은 엄연히 따지면 하나의 속성입니다. margin-left가 width의 너비에 영향을 받는다는 것은, margin-top 또한 width의 너비에 영향을 받는다는 것입니다.


자동 페이드 슬라이드

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    *{margin:0;padding:0;}
    ul,li{list-style:none;}
    .slide{height:300px;overflow:hidden;}
    .slide ul{position:relative;height:100%;}
    .slide li{position:absolute;left:0;right:0;top:0;bottom:0;opacity:0;animation:fade 8s infinite;}
    .slide li:nth-child(1){background:#ffa;animation-delay:0s}
    .slide li:nth-child(2){background:#faa;animation-delay:2s}
    .slide li:nth-child(3){background:#afa;animation-delay:4s}
    .slide li:nth-child(4){background:#aaf;animation-delay:6s}
     /* 100 / 8 = 12.5 */
    @keyframes fade {
      0% {opacity:0;}
      5% {opacity:1;}
      25% {opacity:1;}
      30% {opacity:0;}
      100% {opacity:0;}
    }
  </style>
</head>
<body>
  <div class="slide">
    <ul>
      <li></li>
      <li></li>
      <li></li>
      <li></li>
    </ul>
  </div>
</body>
</html>

여기서 핵심이 되는 내용은 다음과 같습니다.

  1. 모든 li는 똑같은 keyframe을 사용한다.
  2. animation-delay를 통하여, 똑같은 애니메이션이지만 실행 시점이 다르게 조정
  3. slide는 4 장면이 있으며, 1 장면단 진행 시간이 2초다. 따라서 전체 진행시간은 8초이며, 100%를 8로 나누면 12.5%가 된다. 12.5%가 1초동안 진행되는 것임





수동 가로 슬라이드

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    *{margin:0;padding:0;}
    ul,li{list-style:none;}
    .slide{height:300px;overflow:hidden;position:relative;}
    .slide ul{width:calc(100% * 4);display:flex;transition:1s;}
    .slide li{width:calc(100% / 4);height:300px;}
    .slide li:nth-child(1){background:#ffa;}
    .slide li:nth-child(2){background:#faa;}
    .slide li:nth-child(3){background:#afa;}
    .slide li:nth-child(4){background:#aaf;}
    .slide input{display:none;}
    .slide .bullet{position:absolute;bottom:20px;left:0;right:0;text-align:center;z-index:10;}
    .slide .bullet label{width:10px;height:10px;border-radius:10px;border:2px solid #666;display:inline-block;background:#fff;font-size:0;transition:0.5s;cursor:pointer;}

    /* 슬라이드 조작 */
    #pos1:checked ~ ul{margin-left:0;}
    #pos2:checked ~ ul{margin-left:-100%;}
    #pos3:checked ~ ul{margin-left:-200%;}
    #pos4:checked ~ ul{margin-left:-300%;}

    /* bullet 조작 */
    #pos1:checked ~ .bullet label:nth-child(1),
    #pos2:checked ~ .bullet label:nth-child(2),
    #pos3:checked ~ .bullet label:nth-child(3),
    #pos4:checked ~ .bullet label:nth-child(4){background:#666;}
  </style>
</head>
<body>
  <div class="slide">
    <input type="radio" name="pos" id="pos1" checked>
    <input type="radio" name="pos" id="pos2">
    <input type="radio" name="pos" id="pos3">
    <input type="radio" name="pos" id="pos4">
    <ul>
      <li></li>
      <li></li>
      <li></li>
      <li></li>
    </ul>
    <p class="bullet">
      <label for="pos1">1</label>
      <label for="pos2">2</label>
      <label for="pos3">3</label>
      <label for="pos4">4</label>
    </p>
  </div>
</body>
</html>

여기서 핵심이 되는 내용은 다음과 같습니다.

  1. display:flex로 li를 가로로 나열함
  2. ul width = slide width * li count
  3. li width = slide width = ul width / li count * 100%
  4. :checked 선택자로 input[type="radio"]의 선택 상태를 판별할 수 있다.
  5. ~ 선택자를 이용하여 뒤에 있는 태그를 선택하고 조작할 수 있다.
  6. label을 클릭하면, for과 일치하는 id 값을 가진 input에 focusing 된다.
  7. input은 display:none 상태에서도 작동한다.

4 ~ 7번은 뒤에 나올 두 종류의 슬라이드에도 적용되는 내용입니다.



수동 세로 슬라이드

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    *{margin:0;padding:0;}
    ul,li{list-style:none;}
    .slide{height:300px;overflow:hidden;position:relative;}
    .slide ul{height:calc(100% * 4);transition:1s;}
    .slide li{height:calc(100% / 4);}
    .slide li:nth-child(1){background:#ffa;}
    .slide li:nth-child(2){background:#faa;}
    .slide li:nth-child(3){background:#afa;}
    .slide li:nth-child(4){background:#aaf;}
    .slide input{display:none;}
    .slide .bullet{position:absolute;bottom:20px;left:0;right:0;text-align:center;z-index:10;}
    .slide .bullet label{width:10px;height:10px;border-radius:10px;border:2px solid #666;display:inline-block;background:#fff;font-size:0;transition:0.5s;cursor:pointer;}

    /* 슬라이드 조작 */
    #pos1:checked ~ ul{margin-top:0;}
    #pos2:checked ~ ul{margin-top:-300px;}
    #pos3:checked ~ ul{margin-top:-600px;}
    #pos4:checked ~ ul{margin-top:-900px;}

    /* bullet 조작 */
    #pos1:checked ~ .bullet label:nth-child(1),
    #pos2:checked ~ .bullet label:nth-child(2),
    #pos3:checked ~ .bullet label:nth-child(3),
    #pos4:checked ~ .bullet label:nth-child(4){background:#666;}
  </style>
</head>
<body>
  <div class="slide">
    <input type="radio" name="pos" id="pos1" checked>
    <input type="radio" name="pos" id="pos2">
    <input type="radio" name="pos" id="pos3">
    <input type="radio" name="pos" id="pos4">
    <ul>
      <li></li>
      <li></li>
      <li></li>
      <li></li>
    </ul>
    <p class="bullet">
      <label for="pos1">1</label>
      <label for="pos2">2</label>
      <label for="pos3">3</label>
      <label for="pos4">4</label>
    </p>
  </div>
</body>
</html>

자동 세로 슬라이드와 마찬가지로, margin-top에 퍼센트가 아닌 px로 수치를 기입했습니다. 그리고 직전에 한 "수동 가로 슬라이드"와 마찬가지로 :checked 선택자, ~ 선택자, label과 input을 이용했습니다.


수동 페이드 슬라이드

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    *{margin:0;padding:0;}
    ul,li{list-style:none;}
    .slide{height:300px;overflow:hidden;position:relative;}
    .slide li{position:absolute;left:0;right:0;top:0;bottom:0;opacity:0;transition:1s;}
    .slide li:nth-child(1){background:#ffa;}
    .slide li:nth-child(2){background:#faa;}
    .slide li:nth-child(3){background:#afa;}
    .slide li:nth-child(4){background:#aaf;}
    .slide input{display:none;}
    .slide .bullet{position:absolute;bottom:20px;left:0;right:0;text-align:center;z-index:10;}
    .slide .bullet label{width:10px;height:10px;border-radius:10px;border:2px solid #666;display:inline-block;background:#fff;font-size:0;transition:0.5s;cursor:pointer;}

    /* 슬라이드 조작 */
    #pos1:checked ~ ul li:nth-child(1),
    #pos2:checked ~ ul li:nth-child(2),
    #pos3:checked ~ ul li:nth-child(3),
    #pos4:checked ~ ul li:nth-child(4){opacity:1;}

    /* bullet 조작 */
    #pos1:checked ~ .bullet label:nth-child(1),
    #pos2:checked ~ .bullet label:nth-child(2),
    #pos3:checked ~ .bullet label:nth-child(3),
    #pos4:checked ~ .bullet label:nth-child(4){background:#666;}
  </style>
</head>
<body>
  <div class="slide">
    <input type="radio" name="pos" id="pos1" checked>
    <input type="radio" name="pos" id="pos2">
    <input type="radio" name="pos" id="pos3">
    <input type="radio" name="pos" id="pos4">
    <ul>
      <li></li>
      <li></li>
      <li></li>
      <li></li>
    </ul>
    <p class="bullet">
      <label for="pos1">1</label>
      <label for="pos2">2</label>
      <label for="pos3">3</label>
      <label for="pos4">4</label>
    </p>
  </div>
</body>
</html>

코드를 보면 알겠지만, 자동 페이드 슬라이드와 다르게 수동 페이드 슬라이드는 굉장히 쉬운편입니다. 자동으로 fade-in, fade-out 되는 것을 계산하지 않아도 되기 때문입니다. 또한 슬라이드가 진행될 때 opacity:1 이라는 공통되는 속성을 가지기 때문에 CSS를 작성하기가 더욱 수월합니다.