Pseudo-element는 HTML 요소의 특정 부분만 선택해서 스타일을 줄 수 있는 CSS 선택자입니다. 콜론 2개(::)를 사용합니다.
/* 첫 번째 글자만 스타일링 */
.text::first-letter {
color: red;
font-size: 2em;
font-weight: bold;
}
/* 첫 번째 줄만 스타일링 */
.text::first-line {
color: blue;
text-transform: uppercase;
}
/* 요소 앞에 컨텐츠 추가 */
.text::before {
content: '📌 ';
color: red;
font-weight: bold;
}
/* 요소 뒤에 컨텐츠 추가 */
.text::after {
content: ' ✨';
color: gold;
}
/* 인용문 디자인 */
.quote::before {
content: '"';
font-size: 3em;
color: #ccc;
vertical-align: top;
}
.quote::after {
content: '"';
font-size: 3em;
color: #ccc;
}
/* 리스트 커스텀 마커 */
.custom-list li::before {
content: '→ ';
color: #007bff;
font-weight: bold;
}
/* float 해제용 가상 요소 */
.clearfix::after {
content: '';
display: block;
clear: both;
}
.tooltip {
position: relative;
cursor: help;
}
.tooltip::after {
content: attr(data-tooltip);
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
background: #333;
color: white;
padding: 5px 10px;
border-radius: 4px;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s;
}
.tooltip:hover::after {
opacity: 1;
}
<span class="tooltip" data-tooltip="도움말 텍스트">도움말</span>
.btn-hover {
position: relative;
overflow: hidden;
}
.btn-hover::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
transition: left 0.5s;
}
.btn-hover:hover::before {
left: 100%;
}
Shadow DOM은 브라우저가 복잡한 HTML 구조를 숨겨서 단순하게 보여주는 기술입니다. <input>, <progress>, <video> 등의 태그 내부에 숨겨진 HTML 요소들이 있습니다.
/* 크롬, 사파리, Edge */
input::-webkit-input-placeholder {
color: #ff6b6b;
font-style: italic;
opacity: 0.8;
}
/* 파이어폭스 */
input::-moz-placeholder {
color: #ff6b6b;
font-style: italic;
opacity: 0.8;
}
/* IE/Edge (구버전) */
input:-ms-input-placeholder {
color: #ff6b6b;
font-style: italic;
}
/* 파일 업로드 버튼 숨기기 */
input[type="file"] {
width: 0.1px;
height: 0.1px;
opacity: 0;
overflow: hidden;
position: absolute;
z-index: -1;
}
/* 커스텀 파일 업로드 버튼 */
input[type="file"] + label {
display: inline-block;
background: #007bff;
color: white;
padding: 10px 20px;
border-radius: 4px;
cursor: pointer;
transition: background 0.3s;
}
input[type="file"] + label:hover {
background: #0056b3;
}
/* 웹킷 기반 브라우저 (크롬, 사파리) */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
::-webkit-scrollbar-thumb {
background: #007bff;
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: #0056b3;
}
::selection {
background: #007bff;
color: white;
}
::-moz-selection {
background: #007bff;
color: white;
}
<progress value="0.7" max="1">70%</progress>
progress {
/* 기본 스타일 제거 */
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 100%;
height: 20px;
border: none;
border-radius: 10px;
background: #e9ecef;
/* IE10 호환성 */
color: #007bff;
}
/* 웹킷 기반 브라우저 (크롬, 사파리, Edge) */
progress::-webkit-progress-bar {
background: #e9ecef;
border-radius: 10px;
overflow: hidden;
}
progress::-webkit-progress-value {
background: linear-gradient(45deg, #007bff, #0056b3);
border-radius: 10px;
transition: width 0.3s ease;
}
/* 파이어폭스 */
progress::-moz-progress-bar {
background: linear-gradient(45deg, #007bff, #0056b3);
border-radius: 10px;
}
progress {
position: relative;
overflow: hidden;
}
progress::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(
90deg,
transparent,
rgba(255, 255, 255, 0.3),
transparent
);
animation: shine 2s infinite;
}
@keyframes shine {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
| 브라우저 | 접두사 | 예시 |
|---|---|---|
| 크롬, 사파리, Edge | -webkit- | -webkit-transform |
| 파이어폭스 | -moz- | -moz-transform |
| IE | -ms- | -ms-transform |
.element {
/* 표준 속성을 마지막에 */
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
-ms-transition: all 0.3s ease;
transition: all 0.3s ease;
}
.card {
position: relative;
overflow: hidden;
transition: transform 0.3s ease;
}
.card::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(
45deg,
transparent,
rgba(255, 255, 255, 0.1),
transparent
);
transform: rotate(45deg);
transition: all 0.6s;
opacity: 0;
}
.card:hover::before {
animation: shine 0.6s ease-in-out;
}
.card:hover {
transform: translateY(-5px);
}
@keyframes shine {
0% {
top: -50%;
left: -50%;
opacity: 0;
}
50% {
opacity: 1;
}
100% {
top: 50%;
left: 50%;
opacity: 0;
}
}
.ribbon {
position: relative;
background: #007bff;
color: white;
padding: 10px 20px;
margin: 20px 0;
}
.ribbon::before,
.ribbon::after {
content: '';
position: absolute;
top: 0;
width: 0;
height: 0;
border-style: solid;
}
.ribbon::before {
left: -20px;
border-width: 20px 20px 20px 0;
border-color: transparent #005cbf transparent transparent;
}
.ribbon::after {
right: -20px;
border-width: 20px 0 20px 20px;
border-color: transparent transparent transparent #005cbf;
}
/* 가상 요소 디버깅용 */
.debug::before,
.debug::after {
border: 1px solid red;
background: rgba(255, 0, 0, 0.1);
}
::before, ::after는 content 속성이 반드시 필요display: inline 요소에는 ::before, ::after 적용 불가<img>, <input> 등 대체 요소에는 적용 불가/* 좋은 예: transform 사용 */
.element::before {
transform: translateX(100px);
}
/* 나쁜 예: left 사용 */
.element::before {
left: 100px;
}
Pseudo-element와 Shadow DOM을 마스터하여 더욱 정교한 CSS 스타일링을 구현할 수 있습니다