One way to enhance your website without relying on Javascript is by utilizing a pure CSS approach that incorporates the :target
pseudo-class.
By structuring your content within the document and utilizing navigation links with fragment identifiers as their href
attributes, you can maintain the core functionality of your page even in the absence of Javascript or CSS.
Check out this Codepen demo for reference
Markup Structure
<nav role="complementary">
<ul role="tablist">
<li role="tab" aria-controls="cnt1" id="tab1" aria-selected="true">
<a href="#cnt1">Content 1</a></li>
<li role="tab" aria-controls="cnt2" id="tab2" aria-selected="false">
<a href="#cnt2">Content 2</a></li>
<li role="tab" aria-controls="cnt3" id="tab3" aria-selected="false">
<a href="#cnt3">Content 3</a></li>
<li role="tab" aria-controls="cnt4" id="tab4" aria-selected="false">
<a href="#cnt4">Content 4</a></li>
</ul>
</nav>
<main>
<section id="cnt1" aria-hidden="false" role="tabpanel" aria-labelledby="tab1">
<h2>Content 1</h2>
<p>This is a lorem ipsum text.</p>
</section>
<section id="cnt2" aria-hidden="true" role="tabpanel" aria-labelledby="tab2">
<h2>Content 2</h2>
<p>I am the content of link #2</p>
</section>
<section id="cnt3" aria-hidden="true" role="tabpanel" aria-labelledby="tab3">
<h2>Content 3</h2>
<p>Here's another piece of content.</p>
</section>
<section id="cnt4" aria-hidden="true" role="tabpanel" aria-labelledby="tab4">
<h2>Content 4</h2>
<p>And that wraps it up!</p>
</section>
</main>
CSS Styling (relevant part)
body { display: flex; }
main {
flex: 1;
align-self: stretch;
position: relative; }
ul { list-style: none; }
nav { align-self: flex-start; }
[role="tabpanel"] {
position: absolute;
transition: .25s opacity;
background: #fff;
padding: 0 20px;
left: 0; right: 0; top: 0; bottom: 0;
opacity: 0; }
[role="tabpanel"]:first-of-type { opacity: .99; }
[role="tabpanel"]:target { opacity: 1; }
Through a straightforward CSS transition, you can seamlessly alter the appearance of your content.
It's worth noting the inclusion of role
and aria-*
attributes, making this type of navigation closely resemble a tab/tabpanels widget.
Despite the absence of Javascript in this scenario, its implementation could significantly improve the accessibility of your content. For instance, using a transitionend
event to detect visible sections based on opacity values and adjusting relevant aria-*
attributes can greatly benefit users relying on assistive technology.
Javascript Functionality
(purely for enhancing accessibility)
var _gcs = window.getComputedStyle;
var _sections = document.querySelectorAll('[role="tabpanel"]');
var _tabs = document.querySelectorAll('[role="tab"]');
var _setARIAAttributes = () => {
var currentHash;
/* Update aria-hidden attribute for panels */
[..._sections].forEach( ( s ) => {
var hidden = +( _gcs( s ).getPropertyValue( 'opacity' ) ) < 1;
s.setAttribute( 'aria-hidden', hidden);
if (!hidden) currentHash = s.id;
});
/* Update aria-controls attribute for tabs */
[..._tabs].forEach( ( t ) => {
var selected = t.getAttribute( 'aria-controls' ) === currentHash;
t.setAttribute( 'aria-selected', selected );
});
}
if (!!location.hash) { _setARIAAttributes() }
window.addEventListener('transitionend', () => { _setARIAAttributes(); });