CSS :playing Pseudo-Class
The CSS :playing pseudo-class selects media elements, such as <video> and <audio>, while they are in a playing state. It allows developers to change the appearance of media players automatically when playback starts, pauses, or resumes.
:playing Syntax
selector:playing {
property: value;
}
The :playing pseudo-class matches supported media elements while they are in a playing state.
Basic Example
video:playing {
border: 3px solid #2e7d32;
}
Adds a green border around a video while it is playing.
Audio Example
audio:playing {
opacity: 1;
}
Applies full opacity to an audio element while it is playing.
Class Selector
.tutorial-video:playing {
outline: 2px solid #2e7d32;
}
Matches a media element with the tutorial-video class while it is in a playing state.
No Parentheses
The :playing pseudo-class does not accept arguments and is written without parentheses.
How :playing Works
The browser determines whether a media element is in a playing state. The :playing pseudo-class matches when the media is playing, even if playback temporarily stops to wait for data.
HTML Example
<video controls width="300">
<source src="video/sample.mp4" type="video/mp4">
Your browser does not support the video element.
</video>
CSS Example
video {
border: 3px solid #ccc;
}
video:playing {
border-color: #2e7d32;
}
The video receives a green border when playback begins. Pausing the video removes the playing-state styling.
Automatic State Changes
The browser updates selector matching as the media's playback state changes. JavaScript does not need to add or remove a class for basic playing-state styling.
Playing Is Not the Same as Audible
A muted video can still match :playing. The selector describes playback activity, not whether sound can be heard.
Playing Is Not a CSS Animation State
The :playing pseudo-class does not select ordinary elements because their CSS animations are running.
Playing <video> Elements
Video elements can be styled according to whether they are playing or paused.
HTML Example
<video class="tutorial-video" controls width="300" preload="metadata">
<source src="video/sample.mp4" type="video/mp4">
Your browser does not support the video element.
</video>
CSS Example
.tutorial-video {
border: 3px solid #ccc;
}
.tutorial-video:playing {
border-color: #2e7d32;
box-shadow: 0 0 8px rgb(46 125 50 / 20%);
}
The video receives a green border and shadow while it is playing.
Paused Video Styling
.tutorial-video:paused {
border-color: #006699;
}
Provides a different border color when the video is paused.
Native Controls
The controls attribute displays the browser's native media controls. Playing and pausing through those controls updates the matching state automatically.
Autoplay
A video with the autoplay attribute can match :playing when playback begins. Browser autoplay policies may prevent playback from starting, especially when sound is enabled.
Playing <audio> Elements
Audio elements also support media playback states and can be styled with :playing.
HTML Example
<audio class="tutorial-audio" controls>
<source src="audio/sample.mp3" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
CSS Example
.tutorial-audio {
opacity: 0.7;
}
.tutorial-audio:playing {
opacity: 1;
}
The audio element becomes fully opaque when playback begins.
Playing and Paused Colors
audio:playing {
outline: 2px solid #2e7d32;
}
audio:paused {
outline: 2px solid #006699;
}
Applies different outlines according to the audio element's playback state.
Muted Audio
An audio element can remain in a playing state while muted. The :playing selector does not require audible output.
Native Control Differences
Audio controls vary across browsers. Styling the audio element itself is generally more predictable than styling individual browser-provided controls.
Playback States
Media elements can move between playing and paused states as users interact with their controls or as scripts change playback.
Playback State Comparison
| State | Description |
|---|---|
| Playing | The media is in a playing state, including temporary interruptions while waiting for data. |
| Paused | Playback is paused or has not started. |
| Seeking | The playback position is being changed. |
| Buffering | The media is waiting for additional data during playback. |
| Ended | Playback has reached the end of the media. |
Playing and Paused Selectors
video:playing {
border-color: #2e7d32;
}
video:paused {
border-color: #006699;
}
These rules distinguish playing and paused media elements.
Initial State
A media element that has not started playback generally matches :paused, not :playing.
After Playback Ends
When non-looping playback reaches the end, the media stops being in the playing state.
Looping Playback
A media element with the loop attribute can restart automatically when it reaches the end and continue matching :playing.
Buffering and Seeking
The :playing pseudo-class can continue matching during certain temporary interruptions in playback.
Buffering
When media is playing but temporarily waits for additional data, it can continue matching :playing while also matching :buffering.
video:playing {
border-color: #2e7d32;
}
video:buffering {
outline: 2px dashed #cc8800;
}
Seeking
Seeking changes the playback position. A media element can be seeking while it remains in a playing state.
video:seeking {
outline: 2px dashed #cc8800;
}
Paused While Seeking
A user can also seek through media while it is paused. Seeking does not necessarily mean that playback is active.
Playback State vs. Data Availability
The :playing selector describes the media's playback state rather than guaranteeing that video frames or audio samples are advancing at every instant.
JavaScript and Playback
JavaScript can start, pause, and monitor media playback using the HTML media element API. CSS automatically responds to supported playback states.
Starting Playback
const video = document.querySelector("video");
video.play().catch((error) => {
console.log("Playback could not start:", error);
});
The play() method requests playback and returns a promise. The promise can reject if the browser prevents playback.
Pausing Playback
video.pause();
Calling pause() changes the media to its paused state.
Playback Events
video.addEventListener("playing", () => {
console.log("Playback is active");
});
video.addEventListener("pause", () => {
console.log("Playback paused");
});
The playing and pause events allow scripts to respond to changes in media playback.
Checking the Paused Property
console.log(video.paused);
The paused property reports whether the media element is paused. It does not necessarily indicate whether playback is temporarily waiting for data.
CSS Does Not Require Event Listeners
For visual state changes alone, :playing and :paused can remove the need to manage custom CSS classes with JavaScript.
Styling Media Containers
The :playing pseudo-class matches the media element itself. The :has() pseudo-class can style a parent container based on the media's playback state.
HTML Example
<div class="video-container">
<video controls width="300">
<source src="video/sample.mp4" type="video/mp4">
</video>
<p class="playing-message">Video is playing.</p>
</div>
CSS Example
.playing-message {
display: none;
}
.video-container:has(video:playing) .playing-message {
display: block;
color: #2e7d32;
}
Displays a status message when the video inside the container is playing.
Container Background
.video-container:has(video:playing) {
background-color: #eaf7ed;
}
Changes the container background while its video is playing.
Multiple Media Elements
When a container includes several media elements, :has(video:playing) matches if at least one descendant video is in a playing state.
Related Pseudo-Classes
Media-state pseudo-classes identify different conditions involving playback, data availability, and audio output.
Comparison
| Pseudo-Class | Matching Behavior |
|---|---|
:playing | Matches supported media elements in a playing state. |
:paused | Matches supported media elements in a paused state. |
:buffering | Matches supported media elements while buffering. |
:seeking | Matches supported media elements while seeking. |
:stalled | Matches supported media elements whose playback has stalled. |
:muted | Matches supported media elements while muted. |
:volume-locked | Matches supported media elements whose volume is locked. |
:picture-in-picture | Matches a video displayed in Picture-in-Picture mode. |
Playing vs. Paused
video:playing {
border-color: #2e7d32;
}
video:paused {
border-color: #006699;
}
These selectors provide different styles for the two playback states.
Playing vs. Muted
A video can be playing and muted at the same time. The two pseudo-classes describe separate conditions.
Playing vs. Picture-in-Picture
A video can continue playing in Picture-in-Picture mode. The floating-window state does not determine whether playback is active.
:playing Specificity
The :playing pseudo-class contributes a specificity of 0-1-0, like other standard pseudo-classes.
Specificity Examples
| Selector | Specificity |
|---|---|
:playing | 0-1-0 |
video:playing | 0-1-1 |
.media-player:playing | 0-2-0 |
.video-container video:playing | 0-2-1 |
video:playing:muted | 0-2-1 |
#main-video:playing | 1-1-0 |
Specificity Example
video {
border: 3px solid #ccc;
}
video:playing {
border-color: #2e7d32;
}
When both rules match and other cascade factors are equal, the :playing rule takes precedence because it has greater specificity.
Combined Pseudo-Classes
video:playing:muted {
opacity: 0.8;
}
This selector matches a video that is both playing and muted.
Practical Uses
The :playing pseudo-class can provide immediate visual feedback when media playback is active.
Playing Video Border
video:playing {
border: 3px solid #2e7d32;
}
Highlights a video while it is playing.
Playing Video Shadow
video:playing {
box-shadow: 0 0 10px rgb(46 125 50 / 25%);
}
Adds a subtle shadow around a playing video.
Audio Player Appearance
audio:playing {
opacity: 1;
}
Displays an audio player at full opacity while it is playing.
Playback Status Message
.media-container:has(video:playing) .status-message {
display: block;
}
Displays a status message when the container includes a playing video.
Playing Indicator
.media-container:has(video:playing) .playing-indicator {
color: #2e7d32;
font-weight: bold;
}
Changes the appearance of a separate indicator based on the video's playing state.
Limitations
The :playing pseudo-class applies to supported media playback states and has several limitations.
Media Elements Only
Ordinary HTML elements do not match :playing simply because they contain moving content or animations.
Not a CSS Animation Selector
The pseudo-class does not identify elements with running CSS animations. Use animation-related CSS properties and JavaScript when controlling animation playback.
Not an Audio Output Test
Muted media can still match :playing.
Temporary Playback Interruptions
The selector can continue matching while media temporarily waits for data. It does not guarantee that playback is advancing at every instant.
Native Media Controls
The pseudo-class styles the media element, not necessarily the individual buttons inside the browser's native control interface.
Browser Support
Older browsers may not support the pseudo-class. Test the selector in the browsers required by your project.
Not a Playback Command
The selector does not start or stop playback. It only matches the media's current state.
Best Practices
- Use
:playingto style supported audio and video elements during playback. - Combine it with
videooraudioto target the intended media type. - Use
:pausedwhen different styling is needed while playback is paused. - Remember that buffering can occur while the media remains in a playing state.
- Do not confuse playback activity with muted audio or Picture-in-Picture mode.
- Preserve accessible playback controls and keyboard interaction.
- Use clear visual indicators instead of relying only on color.
- Use
:has()when styling a container based on its media element's state. - Test playback, pause, seeking, buffering, and end-of-media behavior.
- Use JavaScript media events when application behavior must change in addition to CSS styling.
:playing Example
This example uses a video element with native playback controls. The video receives a green border while playing and a blue border while paused. The browser updates the styling automatically when the playback state changes.
HTML
<div class="playing-demo">
<video controls width="280" preload="metadata">
<source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
Your browser does not support the video element.
</video>
<p>Use the video controls to play or pause.</p>
</div>
CSS
.playing-demo video {
display: block;
max-width: 100%;
box-sizing: border-box;
border: 3px solid #ccc;
}
.playing-demo video:playing {
border-color: #2e7d32;
box-shadow: 0 0 8px rgb(46 125 50 / 20%);
}
.playing-demo video:paused {
border-color: #006699;
box-shadow: 0 0 8px rgb(0 102 153 / 20%);
}
.playing-demo p {
margin-top: 10px;
font-size: 0.875rem;
}
Browser Result
Note: The video initially displays a blue border because it is paused. Press Play to change the border to green. Pause the video to restore the blue border. The external video file must be accessible for playback.
Browser Support
Baseline: Newly available. The :playing pseudo-class is supported in recent versions of major browsers. Older browser versions may not recognize it, so compatibility should be checked before relying on it for essential interface feedback.
For current compatibility information, visit Can I Use? and search for :playing.
Compatibility Alternative
For older browsers, JavaScript can listen for media playback events and apply classes such as .is-playing and .is-paused to provide similar visual feedback.
Specifications
The :playing pseudo-class is defined in CSS Selectors Level 4 as a media-state pseudo-class. It represents media elements that are in a playing state.
