Opacity in CSS controls how transparent an element is. A value of 1 means fully visible, 0 means fully transparent, and values between them create partial transparency. Opacity is used for overlays, disabled states, fade effects, modals, tooltips, image hover states, and subtle interface layers.
Opacity looks simple, but it has important behavior. It affects the entire element, including text, children, borders, backgrounds, and pseudo elements. It can also create a stacking context, which changes how z-index behaves.
Basic Opacity Syntax
The opacity property accepts a number from 0 to 1 or a percentage.
.muted {
opacity: 0.6;
}
.hidden {
opacity: 0;
}
The muted element is partially transparent. The hidden element is visually invisible, but it still exists in layout and may still receive pointer or keyboard interaction depending on the element.
Opacity Affects Children
Opacity applies to the whole rendered element as a group. If a parent has opacity 0.5, all children also appear 50 percent transparent.
.card {
opacity: 0.5;
}
This is different from using a transparent background color. If you only want the background to be transparent, use an alpha color instead.
Opacity vs Alpha Color
Use opacity when the entire element should become transparent. Use alpha colors when only a color layer should be transparent.
.bad-overlay {
opacity: 0.5;
}
.good-overlay {
background: rgb(0 0 0 / 0.5);
}
The first example makes all child content transparent too. The second example creates a semi-transparent background while text inside can remain fully visible.
Opacity and visibility
An element with opacity: 0 is invisible but still takes up layout space. The visibility property can hide it from painting while keeping layout space.
.tooltip {
opacity: 0;
visibility: hidden;
}
.trigger:hover .tooltip {
opacity: 1;
visibility: visible;
}
This pattern is common for tooltips and menus because visibility prevents the hidden element from being seen while opacity can still transition.
Opacity and display
The display property removes an element from layout when set to none. It does not transition smoothly like opacity.
.modal {
opacity: 0;
pointer-events: none;
transition: opacity 180ms ease;
}
.modal.is-open {
opacity: 1;
pointer-events: auto;
}
Opacity is good for fade effects. Display is good for removing layout entirely. Many UI patterns combine opacity with visibility, pointer events, or JavaScript state.
pointer-events with Opacity
An invisible element can still block clicks if it remains above other content. Use pointer-events: none when a hidden overlay should not capture mouse or touch input.
.overlay {
opacity: 0;
pointer-events: none;
}
.overlay.is-active {
opacity: 1;
pointer-events: auto;
}
This keeps hidden overlays from interfering with the page.
Opacity and Stacking Context
An element with opacity less than 1 creates a new stacking context. This means its children are stacked inside that context and may not escape above unrelated elements with z-index.
.panel {
opacity: 0.98;
}
Even a value like 0.98 can affect stacking behavior. If z-index seems strange, check ancestors for opacity, transform, filter, isolation, and other stacking-context triggers.
Fade Transitions
Opacity is one of the safest properties to animate. It is commonly paired with transform for entrance and exit effects.
.toast {
opacity: 0;
transform: translateY(8px);
transition: opacity 180ms ease, transform 180ms ease;
}
.toast.is-visible {
opacity: 1;
transform: translateY(0);
}
This creates a smooth fade and slide without changing layout flow.
Disabled States
Opacity is often used for disabled states, but it should not be the only signal. Disabled controls should also use semantic HTML attributes and clear cursor or color treatment when appropriate.
button:disabled {
opacity: 0.55;
cursor: not-allowed;
}
Use the real disabled attribute for disabled buttons. CSS opacity alone does not stop interaction or communicate state to assistive technology.
Image Overlays
Opacity can be used for image overlays, but alpha background colors are usually better when text is involved.
.image-card::before {
content: "";
position: absolute;
inset: 0;
background: rgb(0 0 0 / 0.45);
}
This darkens the image while keeping text fully opaque. It is usually better than applying opacity to the whole card.
Accessibility and Contrast
Low opacity text can fail contrast requirements quickly. Be careful with muted labels, disabled text, placeholders, and overlay content. If text needs to be readable, choose a color with enough contrast instead of simply lowering opacity.
Opacity is visual. It does not change semantics. Use proper HTML states such as disabled, hidden, aria-expanded, or aria-hidden when interaction and accessibility require them.
Opacity with CSS Variables
Opacity often works better when alpha values are part of a color system. Modern CSS color syntax makes this readable.
:root {
--brand-rgb: 37 99 235;
}
.brand-overlay {
background: rgb(var(--brand-rgb) / 0.18);
}
This creates a transparent brand color without making child content transparent. It is usually better than applying opacity to the whole component.
Opacity and aria-hidden
Visual hiding and accessibility hiding are different. An element with opacity: 0 can still be present to assistive technology. If hidden content should not be read, use the correct HTML or ARIA state along with CSS.
<div class="modal" aria-hidden="true">
...
</div>
When the modal opens, JavaScript can update both the class and the ARIA state. CSS handles the fade, while HTML attributes describe the interaction state.
Opacity in Image Cards
Image cards often use opacity for hover overlays. The overlay fades in, but the text remains fully opaque.
.image-card::before {
content: "";
position: absolute;
inset: 0;
background: rgb(0 0 0 / 0.45);
opacity: 0;
transition: opacity 180ms ease;
}
.image-card:hover::before {
opacity: 1;
}
This is a good use of opacity because it affects only the overlay pseudo element, not the entire card.
Opacity and Animation
Opacity is commonly animated because it does not require layout recalculation. It pairs well with transform for modals, toasts, tooltips, and dropdowns.
Still, an invisible element may remain focusable if the underlying HTML state is not handled. For menus and dialogs, coordinate opacity with visibility, pointer events, focus management, and ARIA state.
Opacity Checklist
- Use opacity for whole-element transparency.
- Use alpha colors for transparent backgrounds.
- Use pointer-events when invisible overlays should not block clicks.
- Use semantic states for disabled or hidden UI.
- Check contrast when text uses low opacity.
- Remember opacity below 1 creates a stacking context.
Opacity with Pseudo Elements
Pseudo elements are often the best place to use opacity because the transparency can be isolated to one visual layer.
.banner {
position: relative;
}
.banner::after {
content: "";
position: absolute;
inset: 0;
background: #000;
opacity: 0.45;
}
The overlay becomes transparent, but the banner content can remain fully opaque by placing it above the pseudo element with stacking rules.
Opacity and Hidden Content
Opacity is not a complete hiding strategy. If a panel is visually hidden with opacity but still focusable, keyboard users may tab into invisible controls. This creates a broken experience.
For interactive UI, pair opacity with proper state handling. Hidden dialogs, dropdowns, and menus need focus management and accessibility states, not just transparent pixels.
Opacity in Loading States
Opacity can show that content is temporarily inactive while loading. Use this carefully so the user still understands what is happening.
.form.is-loading {
opacity: 0.65;
pointer-events: none;
}
This visually dims the form and prevents interaction. A loading message or spinner should also explain the state.
Opacity vs color-mix
For text and borders, using a deliberately mixed color can be better than lowering opacity. It avoids unexpected transparency over complex backgrounds.
.muted-text {
color: color-mix(in srgb, currentColor 65%, transparent);
}
Support should be checked for advanced color functions, but the idea is important: muted color and transparent elements are not always the same design choice.
Opacity and Stacking Bugs
Opacity can create confusing stacking bugs because any value below 1 creates a stacking context. A child with a high z-index may still be trapped inside the parent context.
.wrapper {
opacity: 0.99;
}
.wrapper .dropdown {
position: absolute;
z-index: 9999;
}
The dropdown may still appear below another element outside the wrapper if that outside element belongs to a higher stacking context. The fix is not always a bigger z-index. Sometimes the opacity should be moved to a child layer, or the dropdown should be placed outside the stacked parent.
Opacity in Design Systems
Design systems often define opacity values for overlays, disabled states, hover layers, and pressed states. This keeps transparency consistent across components.
:root {
--overlay-strong: 0.72;
--overlay-soft: 0.28;
--disabled-opacity: 0.55;
}
Named opacity values make intent clearer than random decimals. A teammate can understand why a value exists instead of guessing whether 0.47 was chosen carefully or accidentally.
When Not to Use Opacity
Avoid opacity when only one color should change, when text contrast becomes weak, or when the element still needs normal stacking behavior. In those cases, use alpha colors, color tokens, visibility rules, or real state management instead.
Opacity is strongest when it controls a deliberate visual layer, not when it is used as a shortcut for every muted style.
Use it with clear intent.
Avoid accidental transparency.
Predictable transparency keeps layered interfaces easier to debug.
Common Opacity Mistakes
- Using opacity on a parent and accidentally fading all children.
- Using opacity 0 and forgetting the element can still block clicks.
- Relying on opacity alone for disabled state.
- Making text too low contrast.
- Forgetting opacity less than 1 creates a stacking context.
- Trying to transition display instead of opacity.
Opacity in CSS FAQ
What does opacity do in CSS?
Opacity controls how transparent an element is, from fully transparent at 0 to fully visible at 1.
Does opacity affect child elements?
Yes. Opacity affects the whole rendered element, including children.
Is opacity 0 the same as display none?
No. Opacity 0 is invisible but still occupies layout space, while display none removes the element from layout.
Does opacity create a stacking context?
Yes. Any opacity value below 1 creates a stacking context.
Continue learning CSS in order
Follow the topic sequence with the previous and next lesson.