Code Challenge: CSS Toggles with element.classList

5 minute read

Prerequisites

Research into the following areas may help with this exercise.

Objective

The goal for this exercise is to control CSS styles using the classList Javascript API. It will allow us to toggle (i.e. flip back-and-forth) a CSS class of our choosing on an element (or more) of our choosing. By the time we’re finished, you should have a page that looks similar to this demo:

See the Pen CSS Toggle with Element.classList.toggle() by Tony Grimes (@browsertherapy) on CodePen.

Sandbox environments: Codepen.io is a handy tool (one of many) that helps you code directly in the browser.

Planning it out

With this goal in mind, we will focus on the following objectives, starting with our HTML, then the CSS and finally the Javascript:

  1. Create and position a button and circle using Flexbox.
  2. Create button and circle Javascript element variables with element.querySelector().
  3. Add a click handler for our button using addEventListener().
  4. Toggle a CSS class with element.classList.toggle().

Objective 1: Create and position a button and circle using Flexbox

Objective 1a

As most things Web, we need some HTML content to play with. Eventually, the colour of the circle will change back-and-forth (i.e. toggle) each time the button is clicked.

<!-- HTML is for Content -->
<div class="circle"></div>
<button>Toggle</button>

Objective 1b

Our div element needs a little help being a circle. This will be the element that will flip back-and-forth when our button is clicked.

Don’t forget: By default, a block-level element is as wide as its parent and has no height if empty. We will explicitly set our width and height to whip our div into (an eventually circular) shape.

/* CSS is for Presentation */

.circle {
  /* make it square */
  width: 30vmin;
  height: 30vmin;

  /* make it visible */
  border: 1px solid grey;

  /* make it circular */
  border-radius: 50%;
}

Objective 1c

Position page elements in the center of the viewport. There are more elegant ways to do this but we’ve written this for clarity (hopefully). We’re using the body element as our Flex container to simplify our HTML.

Don’t forget: The body element is much like a normal block-level element: it will only be as tall as the content it contains. It needs to be as tall as the viewport in order for its items to be centered on the page so we explicitly set its height to 100vh (100% of the viewport, in theory).

body {
  /* Make the body the height of the viewport. This is needed to give Flexbox room to operate. */
  height: 100vh;
  
  /* Center the button in the middle of the viewport. */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

Getting fancy: Check out the Complete Guide to Flexbox for a handy, visual reference for everything Flexbox.

Objective 1d

One last bit of CSS: we need a class to toggle with Javascript! In the next steps will hook up our button so that it will toggle this class so that the circle will alternate colours (in this case, between rebeccapurple and the default: transparent)

/* Any element with a class of .fancy will have a (rebecca)purple background. */
.fancy {
  background: rebeccapurple;
}

Objective 2: Create button and circle JS element variables with element.querySelector()

document.querySelector() is a popular way to assign an HTML element to a JS variable. It accepts any valid CSS selector and will return the first DOM element it matches.

const circle = document.querySelector('.circle');
const button = document.querySelector('button');

Tool-time: From here on in, you’ll be relying on your browser’s Web Console to troubleshoot Javascript issues. How to open the Web Console on FireFox and Chrome.

Bug hunt: If you see an error like button is not defined or similar, chances are there’s a problem with the selector you’re passing to querySelector().

Objective 3: Add a click handler for our button using addEventListener()

Now that we have a button variable, let’s do something with it. Javascript is all about events like clicks/touches, mouse/finger movement, form submission, etc. We can tell the browser to run code when a particular event happens, like the click of our button. We use the addEventListener() method (all HTML elements have one) to attach a click handler to our button.

button.addEventListener('click', function(){
  
  // Objective 4 code here. It will be invoked every time the button is clicked.
  
});

Event reference: Bored of clicks? There’s a list of all available events in the MDN Event Reference.

Objective 4: Toggle a CSS class with element.classList.toggle()

When you add a list of classes to an HTML element (using the class attribute), the browser stores them in a list in memory. Normally, we add classes by typing some HTML but we can also use a useful Javascript API called classList. It allows us to add, remove, toggle and replace class names programmatically.

More about classList: The MDN documentation on element.classList is a little sparse but a quick skim of the example code will give you a good idea of what it does: it adds/removes/toggles/replaces the class names of HTML elements. Very handy!

button.addEventListener('click', function(){
  
  // Each time the button is clicked: if the `circle` element has a class of .fancy, remove it. If .fancy is already absent, add it.
  circle.classList.toggle('fancy');
  
});

What’s the point? If you’re looking for a real work application for a CSS toggle, look no further than the mighty hamburger menu!

Cleaning up our code: Making things pretty(ish)

Functionality isn’t everything. Browser default button styling suucks, so let’s make it more “buttony” (technical web development term).

button {
  /* Make the button bigger, and more... buttony */
  padding: .5rem 1rem;
  margin: 1rem;
  border-radius: 1rem;
  
  /* Try to make boring fonts look less boring. */
  font-size: 1.5rem;
  font-family: MS Sans Serif, Geneva, sans-serif;
  font-variant: small-caps;
  
  /* By default, buttons don't get the pointy hand when you hover. */
  cursor: pointer;
}

Fly high, Icarus

Now that you’ve got a basic understanding of how CSS toggles work, try adding two to the Tissue Contrast Illusion exercise: one to toggle .split-bg and another to hide/show the transparent image (hint: this might call for a new class named .hidden).

Good luck!