Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 29, 2019 03:29 pm GMT

Creating a fold out navigation with CSS only

While using JavaScript to open a mobile navigation is a solid option, it's also possible to do it with CSS only. Even submenus don't necessarily need any JS to work, pseudo classes and sibling selectors are the answer!

How

Fold out navigations are usually triggered by what's been lovingly called the hamburger menu, referring to the three horizontal lines. This has been a much debated icon, but people have gotten used to it, so for now let's stick to it.

Opening and closing a fold out navigation

To create a CSS only navigation we need to use an <input /> element with type="checkbox", we will use the :checked pseudo class to see if it's selected. And we need a <label> that's linked to the input element with a for attribute.
This is the simplified version of what I usually create, for clarity's sake I've styled on elements rather than classes:

<nav>  <input type="checkbox" id="trigger" />  <label aria-label="open main navigation" for="trigger"><span></span></label>  <ul>    <li>      <a href="#">Link</a>    <li>    <li>      <a href="#">Link</a>    <li>    <li>      <a href="#">Link</a>    <li>  </ul></nav>

Note that I put the label element after the input element, this makes it possible to style the label by the input's state (:focus, :checked, etc).

Hiding the checkbox

The checkbox input needs to be entirely gone. I added position fixed because the rest of the navigation is fixed and standard behaviour of clicking on a checkbox label is scrolling to it, which would mean scrolling to the top.

input {  opacity: 0;  width: 0;  height: 0;  appearance: none;  position: fixed;}

Creating the trigger

You can just add a background image of a hamburger icon here or you can use before and after selectors to create them. This is the visible part of the trigger, this will be your "nav is closed!"-state.

You might have wondered about the 'unnecessary' span inside the label tags, I added it to make it styling it easier, you can leave the span out.

label {  position: fixed;  top: 0;  right: 0;  z-index: 10;  display: flex;  align-items: center;  width: 15px;  height: 10px;  margin: 40px;  color: hotpink;}label span {  display: block;  width: 100%;  height: 2px;  transition: transform 1s;}label span::before,label span::after {  content: "";  position: absolute;  left: 0;  right: 0;  display: block;  height: 2px;  background: hotpink;  transition: 0.4s}label span::before {  top: 0;}label span::after {  top: calc(100% - 2px); /* to make the transition easier :) */}

Hiding the navigation

While you could just add display: none here, and display: block when you want to show it, using a transform is a lot more fun.
I chose to translate the ul 100vw on the X axis to hide it from the screen until the user clicks on the trigger.

ul {  position: fixed;  top: 0;  left: 0;  right: 0;  bottom: 0;  transform: translateX(100vw);  transition: transform 0.2s;  background: white;}

Creating the 'open state'

I talked earlier about using the :checked pseudo class, a pseudo class is a keyword that's added to an element when it has a certain state.

Radio- and checkbox input types have a :checked state. Checkboxes can be checked and unchecked by clicking on them, in order to select another radiobutton there needs to be another button. Checkboxes are more suitable for our goals so we use them.

This is the place to add the css for the nav trigger's open state, a lot of websites don't style and animate this and it's a shame in my opinion.

The code may look intimidating if you're new to css but if you read it out loud it sometimes helps to understand it more clearly. The first line for example: select the inner element 'span' of the sibling 'label' of the checked 'input'.
Okay that still sounded a bit like gibberish, practice really does make perfect here.

input:checked + label span {  transform: rotate(45deg);}input:checked + label span::before, input:checked + label span::after {  top: calc(50% - 1px);  transition: 0.4s;}input:checked + label span::after {  transform: rotate(90deg);}

Showing the navigation

I used the general sibling selector here, this means "select any ul that is a sibling of a checked input", input:checked + label + ul would also have worked, but is more sensitive to errors (what if you add an element in between?).

input:checked ~ ul {  transform: none;  transition: transform 0.4s; }

The pretty SCSS version with beziers and all the fancy stuff:

But why?

Because we can!

This may seem a lot more complicated than just adding a class with JavaScript and you may be right. This is not only a great exercise if you want to get better at handling pseudo classes and sibling selectors, it's also very sturdy. Imagine your website has a small error in the JS, this would mean people couldn't use your navigation anymore. Let's leave JavaScript for the crazy animations and keep simple things like opening and closing a navigation as a CSS thing.

Accessibility

A good point to throw away this entire article is that using an input element to open and close a navigation is not semantic.

But really if you think about it, most people using screen readers (the group that might notice that you used an input element in stead of a more semantic button element) aren't exactly developers, you might really annoy the blind developers though, be ware.

The trigger is automatically accessible with the keyboard, if you also add a clear aria-label you've done more than most developers who use a button to open a fold out navigation.

I would really love some input from actual blind users or accessibility experts, let me know in the comments whether I'm completely clueless.


Original Link: https://dev.to/cydstumpel/creating-a-fold-out-navigation-with-css-only-4g9k

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To