Show/Hide Script-Free (Which Means CSS Only)
There are many ways to hide and show content with a click (or tap or poke or key-press or …). Many of them have JavaScript under the hood and nearly all of them have dependencies on third-party libraries and/or CDNs. This may be fine when you already have to load a pile of script on a page. This may also lead to poor development practices.
You can mitigate that JavaScript failure with a little CSS-only progressive enhancement. If you lean on the :target
selector you only need two lines of CSS for the most basic show/hide feature:
.expando { display: none; } .expando:target { display: block; }
I made a sample to show it in action:
See the Pen Show/Hide Script-Free by Adrian Roselli (@aardrian) on CodePen.
Supporting older browsers that don’t know what to do with :target
can be as simple as wrapping the CSS in media queries or using conditional comments (for old Internet Explorer).
From here you can layer all your nifty JavaScript animated effects, key bindings, and so on.
What Prompted This Post?
I was at the W3C looking for all the accessibility-related specs. I saw the list of groups of specs, saw the blue text that implied I could click (underlines are inconsistently applied, so they aren’t a consistent clue) and something would happen, but was unable to get anywhere.
A quick view-source showed me that those weren’t links nor buttons (no a href
and no button
to be seen). Checking the console I saw the following error: Uncaught TypeError: Cannot read property 'substring' of undefined
The script was failing and since the a href
is added after the page is served, the error prevented any controls from being added, leaving the content I wanted unavailable. The raw HTML looks like this:
<div class="trviewcat expand_block closed"> <h3 id="tr_Accessibility__All_"> <span class="expand_section">Accessibility (All)</span> </h3>
I grabbed a screen shot that shows (what I think) are all the relevant bits:
The page is set up to show all the content expanded if there is no JavaScript support. That’s a good practice to support users who cannot get the script (bad connections, firewalls, etc.).
The script then comes around and collapses all the content and adds a href
s to make it all work. Unfortunately, if the script breaks after it collapses the content but before the links are added then users are left in a bad spot. Adding the a href
s server-side could mitigate that, reducing the scenarios where the page breaks.
I want to be fair to the folks at the W3C who built this. Nobody can reproduce this issue. I can’t reproduce it on any other browser (so far) besides Chrome, and it works properly if I visit the page in incognito mode. If I turn off all my Chrome extensions, however, the page still breaks. I just haven’t figured out what part of my configuration breaks it yet.
More on Progressive Enhancement
- Understanding Progressive Enhancement
- Progressive Enhancement: Past, Present, and Future
- Progressive Enhancement is not about JavaScript availability
12 Comments
Nice! but there an option to add a function to remove the last option chosen like a combo select?
Thanks
In response to .Carlos, no there is not — at least not without another anchor link. When the URL no longer has an anchor referenced (via #foo), then nothing will be the target and the CSS selector won’t apply. This is really just a very basic example to show the capability.
and it is possible to join this example with yours?
http://codepen.io/vkjgr/pen/VYMeXp
Thanks for your help Adrian
In response to .Sort of. Those are
select
menus, so they aren’t related to my example at all. You could use the select menu to load the page at a specific anchor, but then you are using a form for navigation and that’s generally frowned upon. You could also re-style my example to look like those menus, but that’s also suggesting to users that functionally they will behave like the form element (such as support for arrow keys).
This is pretty nifty and simple. Targeting an ID scrolls the page to that element, is there anyway to avoid the scroll? I have a lengthy Q&A where you answer each question with yes or no (some nested questions too), and once clicked your answer shows, then you manually scroll to the next question.
I would like to avoid the page scrolling to the answer (your choice) when it is chosen. Any thoughts on this? I see another solution using input checkboxes that I might try too, but it’s not as elegantly simple as this.
Thanks.
In response to .I cannot think of an option off the top of my head that does not involve some scripting. However, since I consider the scrolling effect to be a feature and one which I would not want to disable, then this may not be best option for you.
You may want to just use a
<button>
element with a simple function that toggles aclass
. Then use an adjacent sibling selector for any buttons with that class and display the content.FWIW, I am still not a fan of hiding content until a user interacts with it when it is already on the page, but I do not know your application.
Is there a way to re-hide? I’m using this to open up more text (descriptive) once read I would like the user to be able to shut it.
In response to .Nope. Not without navigating to a different anchor or clearing the anchor from the URL. This approach is not nearly as robust as
<details>
/<summary>
, which will require a polyfill for IE and Edge.
In response to .This seems to work for re-hide:
<a href="#Expando1" rel="nofollow ugc">Show</a> My content<a href="" rel="nofollow ugc">Hide</a>
Am I missing anything?
In response to .Well, the validator does not balk. So maybe yeah? It is seemingly no worse than what I propose in this post!
In response to .Here’s what I was trying to show:
https://codepen.io/j8j8/pen/rNOoMbR
CodePen gets a little fussy with the empty href attribute, but the empty href is valid in HTML5 and this seems to work otherwise.
Hi JJ, add a hash to your Codepen
<a href="#" rel="nofollow ugc">Hide my content</a>
and it’ll work
Leave a Comment or Response