The CSS opacity property controls how transparent an element appears. It is commonly used for image effects, disabled states, overlays, fade animations, hover interactions, cards, modals, and UI layers. Opacity accepts a number between 0 and 1. A value of 1 means the element is fully visible, 0.5 means it is 50% transparent, and 0 means it is completely transparent.
Opacity is simple, but it has one very important rule: it affects the entire element. Text, borders, icons, images, pseudo-elements, and child elements all become transparent together. If you only want the background to be transparent while keeping text readable, use an alpha color such as rgba(), hsla(), or modern slash-alpha color syntax instead.
Opacity values are unitless numbers. You do not write 50% with the opacity property in normal CSS. Use decimals between 0 and 1.
| Value | Meaning | Common Use |
|---|---|---|
1 | Fully visible | Normal element state |
0.75 | Slightly transparent | Subtle hover or inactive image state |
0.5 | Half transparent | Overlays, disabled previews, background layers |
0.25 | Mostly transparent | Watermarks, ghost UI, decoration |
0 | Invisible but still present | Fade transitions, hidden overlay before animation |
.visible {
opacity: 1;
}
.soft {
opacity: 0.75;
}
.half {
opacity: 0.5;
}
.faint {
opacity: 0.25;
}
.invisible {
opacity: 0;
}
When opacity is applied to a parent element, the browser renders the whole element group as one transparent layer. This means child text cannot become fully opaque again by setting opacity: 1 on the child. The child is still inside the faded parent layer.
.card {
opacity: 0.5;
background: #2563eb;
color: white;
padding: 20px;
}
.card h3 {
opacity: 1; /* The text is still faded by the parent */
}
If the goal is a transparent tl-card background with readable text, keep the parent fully opaque and use an alpha background color instead.
.card {
background: rgba(37, 99, 235, 0.18);
color: #0f172a;
border: 1px solid rgba(37, 99, 235, 0.35);
padding: 20px;
}
.card h3 {
color: #1d4ed8; /* Text remains fully readable */
}
Both opacity and alpha colors create transparency, but they solve different problems. Use opacity when the entire element should fade. Use alpha colors when only a color layer should be transparent.
| Technique | Example | What Becomes Transparent? | Best For |
|---|---|---|---|
opacity | opacity: 0.6; | Entire element and children | Images, hover states, fade animations |
rgba() | rgba(0, 0, 0, 0.5) | Only that color | Background overlays, readable cards |
hsla() | hsla(220, 80%, 50%, 0.4) | Only that color | Theme colors with transparency |
| Slash alpha | rgb(0 0 0 / 50%) | Only that color | Modern CSS color syntax |
/* Everything inside this tl-card becomes faded */
.faded-card {
opacity: 0.6;
background: #0f172a;
color: white;
}
/* Only the background is transparent */
.transparent-bg-card {
background: rgba(15, 23, 42, 0.6);
color: white;
}
Opacity is excellent for simple image interactions. A common pattern is to make an image slightly transparent by default and restore full opacity when the user hovers over it. Add transition so the change feels smooth instead of sudden.
.gallery-img {
opacity: 0.72;
transition: opacity 0.25s ease;
}
.gallery-img:hover,
.gallery-img:focus {
opacity: 1;
}
Overlays are often used on hero images, banners, cards, and thumbnails. Instead of applying opacity to the whole image container, place a pseudo-element over the image and give that pseudo-element a semi-transparent background. This keeps the content above the overlay clear and readable.
.hero {
position: relative;
min-height: 360px;
background: url("banner.jpg") center / cover no-repeat;
color: white;
}
.hero::before {
content: "";
position: absolute;
inset: 0;
background: rgba(0, 0, 0, 0.55);
}
.hero-content {
position: relative;
z-index: 1;
}
Developers often confuse opacity: 0, visibility: hidden, and display: none. All can hide something visually, but they affect layout and interaction differently.
| CSS | Visible? | Takes Layout Space? | Can Be Clicked? |
|---|---|---|---|
opacity: 0; | No | Yes | Yes, unless pointer events are disabled |
visibility: hidden; | No | Yes | No |
display: none; | No | No | No |
.tooltip {
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: opacity 0.2s ease, visibility 0.2s ease;
}
.button:hover .tooltip,
.button:focus-within .tooltip {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
Opacity is often used to show disabled controls. However, opacity alone only changes appearance. It does not actually prevent clicks, keyboard focus, form submission, or screen reader announcement. For real buttons and form controls, use the proper disabled attribute. For custom controls, combine visual styling with interaction and accessibility attributes.
button:disabled {
opacity: 0.45;
cursor: not-allowed;
}
.custom-button[aria-disabled="true"] {
opacity: 0.45;
pointer-events: none;
cursor: not-allowed;
}
Opacity is one of the safest CSS properties to animate because it does not force layout recalculation. It is commonly paired with transform to create smooth entrance and exit animations.
.fade-in {
opacity: 0;
transform: translateY(12px);
animation: fadeIn 0.35s ease forwards;
}
@keyframes fadeIn {
to {
opacity: 1;
transform: translateY(0);
}
}
Transparent text can quickly become hard to read. Keep enough contrast between text and background, especially for body copy, buttons, alerts, and navigation. Avoid using very low opacity for important labels. If you reduce opacity for a disabled state, make sure the state is also communicated through markup or text, not only color or transparency.
.panel {
transition: opacity 0.25s ease, transform 0.25s ease;
}
@media (prefers-reduced-motion: reduce) {
.panel {
transition: none;
}
}
.card { opacity: 0.5; }
.card { background: rgba(255, 255, 255, 0.5); }
.hidden { opacity: 0; }
.hidden { opacity: 0; visibility: hidden; pointer-events: none; }
.disabled { opacity: 0.4; }
<button disabled>Submit</button>
Explore 500+ free tutorials across 20+ languages and frameworks.