IT일상

CSS로 별점 기능 만들기

  • 프론트엔드
Profile picture

Written by solo5star

2023. 3. 27. 16:47

JavaScript를 사용하지 않고 별점 기능을 만들어보려고 합니다.

<body>
  <div class="star-rating">
    <input type="radio" class="star" value="1">
    <input type="radio" class="star" value="2">
    <input type="radio" class="star" value="3">
    <input type="radio" class="star" value="4">
    <input type="radio" class="star" value="5">
  </div>
</body>
.star-rating {
  display: flex;
}

.star {
  appearance: none;
  padding: 1px;
}

.star::after {
  content: '☆';
  color: hsl(60, 80%, 45%);
  font-size: 20px;
}

별점 기능을 만들기 위해 별 모양을 표현하는 HTML과 CSS를 만들어줍니다.

평점은 1 ~ 5 사이의 값을 하나 가지기 때문에 input[type="radio"]를 사용하였습니다.

appearance: none 은 기존의 라디오 모양을 표시하지 않도록 합니다. 대신에, ::after 를 사용하여 원하는 모양을 표현할 수 있습니다.

1

별 다섯개가 표시될 것입니다. 간단하게 하기 위해 ☆ 특수기호를 사용하였습니다.

:hover

 .star-rating {
   display: flex;
 }
 
 .star {
   appearance: none;
   padding: 1px;
 }
 
 .star::after {
   content: '☆';
   color: hsl(60, 80%, 45%);
   font-size: 20px;
 }

+.star:hover::after {
+  content: '★';
+}

마우스를 올릴 때 :hover pseudo class가 활성화되면서 ★ 모양이 표시될 것입니다.

:has(~ :hover)

갑자기 어려운 쿼리가 나타났습니다. 하나씩 해석해보자면,

:has() 는 괄호 안의 선택자에 해당되는 엘리먼트를 가지고 있을 때 활성화될 것입니다. 기본적으로 자식 요소를 찾습니다.

하지만 괄호 안에서 물결표(~)로 시작한다면, 자신의 뒤에 있는 요소를 찾습니다.

.star:has(~ .star:hover) 는, 자신(.star)의 뒤의 요소에 :hover.star가 있다면 활성화됩니다.

 .star-rating {
   display: flex;
 }
 
 .star {
   appearance: none;
   padding: 1px;
 }
 
 .star::after {
   content: '☆';
   color: hsl(60, 80%, 45%);
   font-size: 20px;
 }

 .star:hover::after {
   content: '★';
 }

+.star:has(~ .star:hover)::after {
+  content: '★';
+}

클릭 시 별이 고정되도록 하기

라디오 버튼의 특성을 활용하여 클릭하였을 때 별이 고정되도록 할 수 있습니다.

 .star-rating {
   display: flex;
 }
 
 .star {
   appearance: none;
   padding: 1px;
 }
 
 .star::after {
   content: '☆';
   color: hsl(60, 80%, 45%);
   font-size: 20px;
 }

 .star:hover::after {
   content: '★';
 }

 .star:has(~ .star:hover)::after {
   content: '★';
 }
 
+.star:checked::after,
+.star:has(~ .star:checked)::after {
+  content: '★';
+}

라디오의 :checked 를 사용하면 체크되어 있는 라디오 버튼을 대상으로 할 수 있습니다.

체크되어 있는 자신과 이전 요소들이 ★ 모양으로 변경되도록 CSS를 추가해줍니다.

호버 중일 때 뒤의 별들은 모두 끄기

위의 실행결과 보고 어색하다고 느꼈을 겁니다. :hover:hover.star를 기준으로 뒤의 .star들이 모두 꺼져야 하기 때문입니다.

이 또한 CSS로 간단하게 처리할 수 있습니다.

 .star-rating {
   display: flex;
 }
 
 .star {
   appearance: none;
   padding: 1px;
 }
 
 .star::after {
   content: '☆';
   color: hsl(60, 80%, 45%);
   font-size: 20px;
 }
 
 .star:hover::after {
   content: '★';
 }
 
 .star:has(~ .star:hover)::after {
   content: '★';
 }
 
 .star:checked::after,
 .star:has(~ .star:checked)::after {
   content: '★';
 }

+.star:hover ~ .star::after {
+  content: '☆';
+}

물결표(A ~ B) 선택자는 A 뒤에 있는 B를 선택합니다. 즉 .star:hover ~ .star 는, :hover되어있는 .star 뒤의 .star가 선택됩니다.

CSS 축약하기

 .star-rating {
   display: flex;
 }
 
 .star {
   appearance: none;
   padding: 1px;
 }
 
 .star::after {
   content: '☆';
   color: hsl(60, 80%, 45%);
   font-size: 20px;
 }
 
-.star:hover::after {
-  content: '★';
-}
-
-.star:has(~ .star:hover)::after {
-  content: '★';
-}
-
-.star:checked::after,
-.star:has(~ .star:checked)::after {
-  content: '★';
-}
+.star:hover::after,
+.star:has(~ .star:hover)::after,
+.star:checked::after,
+.star:has(~ .star:checked)::after {
+  content: '★';
+}

 .star:hover ~ .star::after {
   content: '☆';
 }

동일한 스타일을 표현하는 선택자들은 콤마(,)로 묶을 수 있습니다.

전체 소스코드

<!DOCTYPE html>
<html lang="ko">

<head>
  <style>
    .star-rating {
      display: flex;
    }

    .star {
      appearance: none;
      padding: 1px;
    }

    .star::after {
      content: '☆';
      color: hsl(60, 80%, 45%);
      font-size: 20px;
    }

    .star:hover::after,
    .star:has(~ .star:hover)::after,
    .star:checked::after,
    .star:has(~ .star:checked)::after {
      content: '★';
    }

    .star:hover ~ .star::after {
      content: '☆';
    }
  </style>
</head>

<body>
  <div class="star-rating">
    <input type="radio" class="star" value="1">
    <input type="radio" class="star" value="2">
    <input type="radio" class="star" value="3">
    <input type="radio" class="star" value="4">
    <input type="radio" class="star" value="5">
  </div>
</body>

</html>

Profile picture

Written by solo5star

안녕하세요 👋 개발과 IT에 관심이 많은 solo5star입니다

  • GitHub
  • Baekjoon
  • solved.ac
  • about
© 2023, Built with Gatsby