CSS에서는 기본 선택자 외에도 특별한 상태나 위치를 지정할 수 있는 가상 요소와 가상 클래스를 제공한다.
가상 요소와 가상 클래스에 대해 알아보자.
가상 요소는 말 그대로 가상의 요소를 만드는 것이다.
선택한 요소의 특정 부분에 스타일을 적용할 수 있게 해주며, 이중 콜론(::)을 사용하여 표현한다.
::before
와 ::after
는 선택한 요소의 앞,뒤에 새로운 요소를 만들어 콘탠츠를 추가할 수 있도록 도와준다.
content 속성을 필수로 작성해야 한다.
p::before {
content: '『';
color: #3498db;
font-size: 1.2em;
margin-right: 5px;
}
p::after {
content: '』';
color: #3498db;
font-size: 1.2em;
margin-left: 5px;
}
주로 장식적인 요소를 추가하거나 기능적인 목적으로 사용되며, img, br, input에는 사용할 수 없다.
만약 이미지를 추가하고 싶다면 display값과 background, width, height 등의 속성을 함께 작성하여 원하는 위치에 배치할 수 있다.
::marker
는 리스트 아이템의 마커를 스타일링 할 수 있게 해주는 가상요소이다.
박스 모델의 속성인 background, border, padding은 적용되지 않는다.
ul li::marker {
content: '✦';
color: #e74c3c;
font-size: 1.2em;
}
::placeholder
는 input 태그나 textarea의 placeholder 텍스트에 스타일을 적용할 수 있게 해준다.
input::placeholder {
font-size: 14px;
}
textarea::placeholder {
font-size: 16px;
font-style: italic;
}
가상 클래스 선택자는 요소의 특정 상태를 선택할 수 있게 해주며 콜론(:)을 사용하여 표현한다.
사용자의 동작에 따라 변화하는 상태를 선택할 수 있다.
:link
는 아직 방문하지 않은 링크를 선택한다.
a:link {
color: blue;
text-decoration: none;
}
:visited
는 이미 방문한 링크를 선택한다.
a:visited {
color: red;
text-decoration: none;
}
:hover
는 마우스 포인터가 올라간 요소를 선택한다.
a:hover {
background-color: yellow;
}
:active
는 마우스로 클릭하고 있는 요소를 선택한다.
a:active {
background-color: green;
color: white;
}
:focus
는 현재 초점을 가진 요소를 선택한다.
a:focus {
border: 1px solid blue;
}
문서 구조 내에서 요소의 위치에 따라 선택할 수 있다.
:first-child
는 형제 요소 그룹 중 첫 번째 요소, :last-child
는 마지막 요소를 선택한다.
li:first-child {
color: red;
}
li:last-child {
color: blue;
}
body의 직계 자손의 경우
:first-child
선택자는 사용가능하지만,:last-child
선택자는 적용되지 않는다.<!-- index.html --> <body> <p>first-child</p> <p>last-child</p> </body>
/* style.css */ /* 적용 o */ body > :first-child { color: red; } /* 적용 x */ body > :last-child { color: red; }
부모 요소 내의 모든 자식 요소 중에서 지정된 순서에 있는 요소를 선택한다.
이 선택자는 요소의 타입과 관계없이 순서만 고려한다.
/* 두 번째 자식 요소 선택 */
div :nth-child(2) {
color: red;
}
:nth-child()
선택자는 괄호 안에 다양한 형태의 값을 사용할 수 있다.
부모 요소 내에서 같은 타입의 형제 요소 중 지정된 순서에 있는 요소를 선택한다.
:nth-child
와는 다르게 요소의 타입을 고려하여 순서를 계산한다.
<!-- index.html -->
<div>
<h2>첫 번째 제목</h2>
<p>첫 번째 문단</p>
<h2>두 번째 제목</h2>
<p>두 번째 문단</p>
</div>
/* style.css */
p:nth-of-type(2) {
color: green;
}
동일한 유형의 형제가 없는, 형제 요소 중 유일하게 사용된 태그를 선택한다.
<!-- index.html -->
<div>
<p>유일한 문단</p>
<h2>첫 번째 제목</h2>
<h2>두 번째 제목</h2>
</div>
/* style.css */
p:only-of-type {
color: blue;
}
/* h2는 유일하지 않아서 적용되지 않음. */
h2:only-of-type {
color: blue;
}
부정 선택자로, 특정 선택자를 제외한 요소를 선택한다.
<!-- index.html -->
<div>
<p>유일한 문단</p>
<h2>첫 번째 제목</h2>
<h2>두 번째 제목</h2>
</div>
/* style.css */
/* li 중 첫번째가 아닌 li */
li:not(:first-child) {
list-style-type: decimal;
}
여러 개의 선택자를 한꺼번에 지정할 수 있다.
:is()
는 여러 개의 선택자를 지정할 때 사용한다.
<!-- index.html -->
<h1><a>hello</a></h1>
<h2><a>hello</a></h2>
<h3><a>hello</a></h3>
<h4><a>hello</a></h4>
/* style.css */
:is(h1, h2, h3) a {
color: blue;
}
과거에는 위의 코드와 같이 선택하려면 그룹 선택자를 사용해야 했다.
/* 과거 코드 */
h1 a,
h2 a,
h3 a {
color: blue;
}
:where()
는 :is()
와 유사하지만, 우선순위가 낮다.
<!-- index.html -->
<h1><a>hello</a></h1>
<h2><a>hello</a></h2>
<h3><a>hello</a></h3>
<h4><a>hello</a></h4>
/* style.css */
:is(h1, h2) a {
color: blue;
}
:where(h1, h2, h3) a {
color: red;
}
이 우선순위가 낮다는 점은 장점이 되기도 한다.
스타일 재정의가 필요한 상황에서 매우 유용하게 사용할 수 있다.
예를 들어, 기본 스타일을 정의하면서도 필요한 경우 쉽게 재정의할 수 있도록 도와준다.
/* 기본 스타일 - 낮은 우선순위 */
:where(button, .btn, [type='submit']) {
padding: 0.5em 1em;
background-color: #e0e0e0;
border: 1px solid #ccc;
}
/* 특정 컨테이너의 버튼에 다른 스타일 적용 - 쉽게 재정의 가능 */
.form-container button {
background-color: #0066cc;
color: white;
}
위의 코드에서 만약 :is()
를 사용했다면, 두 번째 선택자를 더 구체적으로 만들어야 재정의가 가능하다.
:has()
는 2022년에 도입된 의사 클래스로, 특정 요소가 자식 요소를 포함하고 있는지를 검사할 수 있게 해준다.
다른 요소 안에 특정 요소가 포함되어 있는지 여부에 따라 스타일을 적용할 수 있어 매우 유용하다.
<!-- index.html -->
<div>
<p>lorem ipsum</p>
</div>
<div>
<a href="#">click me</a>
</div>
/* style.css */
div:has(a) {
background-color: lightblue;
}
위와 같이 특정 요소가 자식으로 링크를 포함하고 있는 경우에만 스타일을 적용하고 싶을 때 사용할 수 있다.
그 외에도 img 태그가 포함된 값만 다르게 설정한다거나(:has(img)
), 필수 키워드가 있는 라벨만 강조 하거나(:has(.required)
), :not()
가상 클래스를 함께 사용하여 빈 목록을 표시 방법을 설정하는 등(:not(:has(li))
)의 다양한 스타일링이 가능해졌다.
:focus
와 유사하다.
:focus
는 포커스된 요소에 항상 적용되고, :focus-visible
은 주로 키보드를 사용하여 페이지를 탐색할 때나 스크립트를 통해 포커스가 관리될 때 활성화된다.
일반적으로 마우스나 터치 인터페이스를 사용하여 요소에 물리적으로 포커스를 설정할 때는 사용자가 이미 자신이 어떤 요소를 선택했는지 알고 있기 때문에 :focus-visible
이 활성화되지 않는다.
/* Focus 스타일 */
.btn:focus {
outline: none;
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
}
/* Focus-visible 스타일 */
.btn:focus-visible {
outline: none;
border-color: dodgerblue;
box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.5);
}
일부 브라우저에서는 마우스 클릭으로도 :focus-visible
이 트리거될 수 있다.
요소 또는 그 자식 요소가 포커스를 받았을 때 적용된다.
div:focus-within {
background-color: lightblue;
border-color: cornflowerblue;
}
label {
display: block;
margin-bottom: 5px;
}
input {
padding: 5px;
border: 1px solid #ccc;
width: 100%;
}
활성화된 상태의 폼 요소를 선택한다.
input:enabled {
background-color: #fff;
}
비활성화된 상태의 폼 요소를 선택한다.
input:disabled {
background-color: lightgray;
cursor: not-allowed;
}
체크된 상태의 라디오 버튼이나 체크박스를 선택한다.
input[type='checkbox']:checked + label {
color: royalblue;
font-weight: bold;
}
input[type='radio']:checked + label {
color: royalblue;
font-weight: bold;
}