Written by Rob O'Leary??
The HTML elements, collectively referred to as a disclosure widget, are not easy to style. People often make their own version with a custom component because of the limitations. However, as CSS has evolved, these elements have gotten easier to customize. In this article, I will cover how you can customize the appearance and behavior of a disclosure widget.
How do and work together?
work together?
When the user clicks on the widget or focuses on it and presses the space bar, it opens and reveals additional information. The triangle marker points down to indicate that it is in an open state:
The disclosure widget has a label that is always shown and is provided by the
You can also provide multiple elements after the
<details> <summary>Do you want to know more?</summary> <h3>Additional info</h3> <p>The average human head weighs around 10 to 11 pounds (approximately 4.5 to 5 kg).</p> </details>
Styling and
There are a few interoperability issues that should be considered when styling the elements. Let's cover the basics before we get into some common use cases.
The
The disclosure widget has two pseudo-elements to style its constituent parts:
- The ::marker pseudo-element: Represents the triangular marker that sits at the beginning of
. The styling story for this is a bit complicated. We are limited to a small set of CSS properties. Browser support is good for ::marker, but Safari doesn’t currently support the complete set of properties. I will discuss this in more detail in the “Styling the summary marker” section of this article - The ::details-content pseudo-element: Represents the “additional information” of . This is a recent addition, so browser support is currently limited to Chrome
In the following sections, I will demonstrate some of the newer, lesser-known ways to customize a disclosure widget.
Animating the open and close actions
When you open a disclosure widget, it snaps open instantly. Blink, and you will miss it!
It is preferable to transition from one state to another in a more gradual way to show the user the impact of their action. Can we add a transition animation to the opening and closing actions of a disclosure widget? In short, yes!
To animate this, we want the height of the hidden content to transition from zero to its final height. The default value of the height property is auto, which leaves it to the browser to calculate the height based on the content. Animating to a value of auto was not possible in CSS until the addition of the [interpolate-size](https://nerdy.dev/interpolate-size) property. While browser support is a bit limited for the newer CSS features we need to use — chiefly interpolate-size and ::details-content — this is a great example of a progressive enhancement. It will currently work in Chrome!
Here's a CodePen example of the animation.
How does the disclosure animation work?
First, we add interpolate-size so we can transition to a height of auto:
<details> <summary>Do you want to know more?</summary> <h3>Additional info</h3> <p>The average human head weighs around 10 to 11 pounds (approximately 4.5 to 5 kg).</p> </details>
Next, we want to describe the closed style. We want the “additional info” content to have a height of zero and ensure that no content is visible, i.e., we want to prevent overflow.
We use the ::details-content pseudo-element to target the hidden content. I use the block-size property rather than height because it's a good habit to use logical properties. We need to include content-visibility in the transition because the browser sets content-visibility: hidden on the content when it is in a closed state — the closing animation will not work without including it:
<details> <summary>Do you want to know more?</summary> <h3>Additional info</h3> <p>The average human head weighs around 10 to 11 pounds (approximately 4.5 to 5 kg).</p> </details>
The animation still won’t work as expected because the content-visibility property is a discrete animated property. This means that there is no interpolation; the browser will flip between the two values so that the transitioned content is shown for the entire animation duration. We don't want this.
If we include transition-behavior: allow-discrete;, the value flips at the very end of the animation, so we get our gradual transition.
Also, we get content overflow by setting the block-size to 0 when the disclosure widget is in an intermediate state. We show most of the content as it opens. To prevent this from happening, we add overflow: hidden.
Lastly, we add the style for the open state. We want the final state to have a size of auto:
details { interpolate-size: allow-keywords; }
Those are the broad strokes. If you would prefer a more detailed video explanation, check out Kevin Powell's walkthrough for how to animate .
Are there any other considerations when animating a disclosure widget?
The disclosure widget may grow horizontally if the “additional information” content is wider than the
Like any animation, you should consider users who are sensitive to motion. You can use the prefers-reduced-motion media query to cater to that scenario:
/* closed state */ details::details-content { block-size: 0; transition: content-visibility, block-size; transition-duration: 750ms; transition-behavior: allow-discrete; overflow: hidden; }
Implementing an exclusive group (exclusive accordion)
A common UI pattern is an accordion component. It consists of a stack of disclosure widgets that can be expanded to reveal their content. To implement this pattern, you just need multiple consecutive
/* open state */ details[open]::details-content { block-size: auto; }
The default style is fairly simple:
Each
A variation of this pattern is to make the accordion exclusive so that only one of the disclosure widgets can be opened at a time. As soon as one is opened, the browser will close the other. You can create exclusive groups through the name attribute of
<details> <summary>Do you want to know more?</summary> <h3>Additional info</h3> <p>The average human head weighs around 10 to 11 pounds (approximately 4.5 to 5 kg).</p> </details>
Before using exclusive accordions, consider if it is helpful to users. If users are likely to want to consume more of the information, this will require them to open items often, which can be frustrating.
This feature is currently supported in all modern browsers so you can use it right away.
Styling the summary marker
A disclosure widget is typically presented with a small triangular marker beside it. In this section, we'll cover the process of styling this marker.
The marker is associated with the
- All of the font properties
- color
- white-space
- text-combine-upright, [unicode-bidi](https://developer.mozilla.org/en-US/docs/Web/CSS/unicode-bidi), and direction properties
- content
- All animation and transition properties
As mentioned earlier,
Before jumping into examples, a quick word on browser support. At the time of writing, Safari is the only major browser that doesn’t fully support styling the marker:
- Safari support is currently limited to styling the color and font-size properties of the ::marker pseudo-element. Safari supports the non-standard pseudo-element ::-webkit-details-marker
- Safari doesn’t support styling the list-style properties at all. See CanIUse for reference
Changing the color and size of a marker
Say we wanted to change the color of the triangular marker to red and make it 50% larger. We can do the following:
details { interpolate-size: allow-keywords; }
This should work across all browsers. Here’s the CodePen example.
Adjusting the spacing of the marker
By default, the marker is to the side of the text content of
If we set list-style-position to outside, the marker sits outside of the
<details> <summary>Do you want to know more?</summary> <h3>Additional info</h3> <p>The average human head weighs around 10 to 11 pounds (approximately 4.5 to 5 kg).</p> </details>
You can see this in the second instance in the screenshot above.
Here is a CodePen of this example:
Changing the marker text/image
If you want to change the content of the marker, you can use the content property of the ::marker pseudo-element. Based on your preferences, you can set it to text. For my example, I used the zipper mouth emoji for the closed state and the open mouth emoji for the open state:
details { interpolate-size: allow-keywords; }
To use an image for the marker, you can use the content property of the ::marker pseudo-element, or the list-style-image property of
/* closed state */ details::details-content { block-size: 0; transition: content-visibility, block-size; transition-duration: 750ms; transition-behavior: allow-discrete; overflow: hidden; }
In the following example, we are using two arrow icons from Material Symbols for the marker. The right-facing arrow is for the closed state, and the down-facing arrow is for the open state:
These examples will work as expected in Chrome and Firefox, but Safari will ignore the styles. You can approach this as a progressive enhancement and call it a day. But if you want the same appearance across all browsers, you can hide the marker and then add your own image as a stand-in. This gives you more freedom:
/* open state */ details[open]::details-content { block-size: auto; }
You can visually indicate the state using a new marker icon, such as an inline image or via pseudo-elements. The
<details> <summary>Do you want to know more?</summary> <h3>Additional info</h3> <p>The average human head weighs around 10 to 11 pounds (approximately 4.5 to 5 kg).</p> </details>
You can choose to position the marker at the end of
details { interpolate-size: allow-keywords; }
However, it is important to note that hiding the marker causes accessibility issues with screen readers. Firefox, VoiceOver, JAWS, and NVDA all have an issue with consistently announcing the toggled state of the disclosure widget if the marker is removed. Unfortunately, the style is tied to the state. It is preferable to avoid doing this.
Styling the "additional information" section of
You may want to style the "additional information" section of the disclosure widget without leaking styles to the
/* closed state */ details::details-content { block-size: 0; transition: content-visibility, block-size; transition-duration: 750ms; transition-behavior: allow-discrete; overflow: hidden; }
My go-to is to exclude the
/* open state */ details[open]::details-content { block-size: auto; }
Alternatively, you can use the ::details-content pseudo-element, which targets the entire section. This is why you want to use this for animating the opening and closing state transitions:
>@media (prefers-reduced-motion) { /* styles to apply if a user's device settings are set to reduced motion */ details::details-content { transition-duration: 0.8s; /* slower speed */ } }
Notice the difference? There is only one margin at the start of the section. The
and
Common mistakes when styling disclosure widgets
- Historically, it wasn't possible to change the display type of the element. This restriction has been relaxed in Chrome
- Be careful changing the display type of
. The default is display: list-item;; if you change it to display: block;, it may result in the marker being hidden in some browsers. This was an issue in Firefox:
<details> <summary>Payment Options</summary> <p>...</p> </details> <details> <summary>Personalise your PIN</summary> <p>...</p> </details> <details> <summary>How can I add an additional cardholder to my Platinum Mastercard</summary> <p>...</p> </details>
- You cannot nest
-
Because the
element has a default ARIA role of button, it strips all roles from child elements. Therefore, if you want to have a heading like a in a
, assistive technologies such as screen readers won’t recognize it as a heading. Try to avoid this pattern:
<details> <summary>Do you want to know more?</summary> <h3>Additional info</h3> <p>The average human head weighs around 10 to 11 pounds (approximately 4.5 to 5 kg).</p> </details>
Hiding the marker causes accessibility issues with some screen readers. Firefox, VoiceOver, JAWS, and NVDA all have an issue with consistently announcing the toggled state of the disclosure widget if the marker is removed
Are there more changes to come?
Recently, there was a big proposal to help make
- Remove CSS display property restrictions so you can use other display types like flex and grid
- Specify the structure of the shadow tree more clearly. This should help with interoperability with Flexbox and CSS Grid
- Add a ::details-content pseudo-element to address the second slot so that a container for the "additional information" in the element can be styled
The exciting news is items 1 and 3 in the list above have shipped in Chrome 131 (as of November 2024). The next phase should be tackling improving the styling of the marker. Additionally, there is a set of related changes that will help improve the ability to animate these elements.
Conclusion
The
The Achilles’ heel of
Is your frontend hogging your users' CPU?
As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording everything that happens in your web app, mobile app, or website. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.
Modernize how you debug web and mobile apps — start monitoring for free.
The above is the detailed content of Styling HTML and with modern CSS. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

CSS blocks page rendering because browsers view inline and external CSS as key resources by default, especially with imported stylesheets, header large amounts of inline CSS, and unoptimized media query styles. 1. Extract critical CSS and embed it into HTML; 2. Delay loading non-critical CSS through JavaScript; 3. Use media attributes to optimize loading such as print styles; 4. Compress and merge CSS to reduce requests. It is recommended to use tools to extract key CSS, combine rel="preload" asynchronous loading, and use media delayed loading reasonably to avoid excessive splitting and complex script control.

ThebestapproachforCSSdependsontheproject'sspecificneeds.Forlargerprojects,externalCSSisbetterduetomaintainabilityandreusability;forsmallerprojectsorsingle-pageapplications,internalCSSmightbemoresuitable.It'scrucialtobalanceprojectsize,performanceneed

Autoprefixer is a tool that automatically adds vendor prefixes to CSS attributes based on the target browser scope. 1. It solves the problem of manually maintaining prefixes with errors; 2. Work through the PostCSS plug-in form, parse CSS, analyze attributes that need to be prefixed, and generate code according to configuration; 3. The usage steps include installing plug-ins, setting browserslist, and enabling them in the build process; 4. Notes include not manually adding prefixes, keeping configuration updates, prefixes not all attributes, and it is recommended to use them with the preprocessor.

CSSismostlycase-insensitive,butURLsandfontfamilynamesarecase-sensitive.1)Propertiesandvalueslikecolor:red;arenotcase-sensitive.2)URLsmustmatchtheserver'scase,e.g.,/images/Logo.png.3)Fontfamilynameslike'OpenSans'mustbeexact.

Theconic-gradient()functioninCSScreatescirculargradientsthatrotatecolorstopsaroundacentralpoint.1.Itisidealforpiecharts,progressindicators,colorwheels,anddecorativebackgrounds.2.Itworksbydefiningcolorstopsatspecificangles,optionallystartingfromadefin

TocreatestickyheadersandfooterswithCSS,useposition:stickyforheaderswithtopvalueandz-index,ensuringparentcontainersdon’trestrictit.1.Forstickyheaders:setposition:sticky,top:0,z-index,andbackgroundcolor.2.Forstickyfooters,betteruseposition:fixedwithbot

The scope of CSS custom properties depends on the context of their declaration, global variables are usually defined in :root, while local variables are defined within a specific selector for componentization and isolation of styles. For example, variables defined in the .card class are only available for elements that match the class and their children. Best practices include: 1. Use: root to define global variables such as topic color; 2. Define local variables inside the component to implement encapsulation; 3. Avoid repeatedly declaring the same variable; 4. Pay attention to the coverage problems that may be caused by selector specificity. Additionally, CSS variables are case sensitive and should be defined before use to avoid errors. If the variable is undefined or the reference fails, the fallback value or default value initial will be used. Debug can be done through the browser developer

CSSanimationsenhancewebpagesbyimprovinguserexperienceandsitefunctionality.1)Usetransitionsforsmoothstylechanges,asinthebuttoncolorexample.2)Employkeyframesfordetailedanimations,likethebouncingball.3)Ensureperformancebykeepinganimationssimpleandusingt
