I often use a few CSS alternatives to common JavaScript interactions when I’m developing the front-end of a website (especially a prototype). There are some projects where downloading a plugin or creating a new file for a few lines of code seems like overkill. Here are some components I use created by using only CSS:
Tooltips
Tooltips are great for showing helpful information that isn’t necessary to a user’s experience. There are a few JavaScript plugins that give us this behavior, but if you don’t feel like adding that weight to your site, we can take care of it with plain ol’ CSS.
We can use pseudo-elements to pull in text and display it on :hover
. (You
could use the HTML title
attribute to effectively accomplish the same
solution, but you can’t style the tooltip to your liking.)
HTML:
<a href="#" class="tooltip-toggle" aria-label="Sample text for your tooltip!" tabindex="0">
Label for your tooltip
</a>
SCSS:
.tooltip-toggle {
cursor: pointer;
position: relative;
//Tooltip text container - above element
//You can adjust the position to make the container appear below or beside the element
&::before {
background-color: #000;
border-radius: 5px;
color: #fff;
content: attr(aria-label); //This pulls in the text from the element with the tooltip
left: -80px; //This centers the container above the element
padding: 1rem;
position: absolute;
text-transform: none;
top: -80px; //This places the container above the element that needs a tooltip
transition: all 0.5s ease;
width: 160px;
}
//Tooltip arrow
//You can adjust the position of this to align nicely with the element that
//needs a tooltip. You can also use `transform` to rotate it to make the
//tooltip work below or next to the element.
&::after {
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #000;
content: " ";
font-size: 0;
left: 9px; //This centers the arrow above the element with the tooltip
line-height: 0;
margin-left: -5px;
position: absolute;
top: -12px; //This positions the arrow at the bottom of the container
width: 0;
}
//Setting up the transition
&::before,
&::after {
opacity: 0;
pointer-events: none;
}
//Triggering the transition
&:focus::before,
&:focus::after,
&:hover::before,
&:hover::after {
opacity: 1;
transition: all 0.75s ease;
}
}
Dropdown menu
If you need to implement a simple dropdown menu, you can use CSS to easily
trigger the visibility of the menu on :hover
.
HTML:
<div class="nav-container">
<ul class="nav-items">
<!-- Navigation -->
<li class="nav-item"><a href="#">Home</a></li>
<li class="nav-item"><a href="#">About</a></li>
<li class="nav-item"><a href="#">Contact</a></li>
<!-- Dropdown menu -->
<li class="nav-item nav-item-dropdown">
<a class="dropdown-trigger" href="#">Settings</a>
<ul class="dropdown-menu">
<li class="dropdown-menu-item">
<a href="#">Dropdown Item 1</a>
</li>
<li class="dropdown-menu-item">
<a href="#">Dropdown Item 2</a>
</li>
<li class="dropdown-menu-item">
<a href="#">Dropdown Item 3</a>
</li>
</ul>
</li>
</ul>
</div>
SCSS:
//Nav bar styling
.nav-container {
background-color: #fff;
display: block;
margin: 0 auto;
max-width: 400px;
padding: 1em;
text-align: center;
}
ul,
li {
list-style: none;
-webkit-padding-start: 0;
}
//Navigation menu
.nav-item {
display: inline;
padding: 1em;
}
//Dropdown menu
.nav-item-dropdown {
position: relative;
&:hover > .dropdown-menu {
display: block;
opacity: 1;
}
}
.dropdown-trigger {
position: relative;
&:focus + .dropdown-menu {
display: block;
opacity: 1;
}
&::after {
color: #ED3E44;
content: "›";
font-size: 24px;
font-weight: bold;
position: absolute;
right: -15px;
top: -5px;
transform: rotate(90deg);
}
}
.dropdown-menu {
background-color: #fff;
display: inline-block;
display: none;
opacity: 0;
position: absolute;
right: -10px;
text-align: right;
top: 2.5rem;
transition: opacity 0.5s ease;
width: 160px;
}
.dropdown-menu-item {
cursor: pointer;
padding: 1em;
text-align: center;
&:hover {
background-color: #ccc;
}
}
Toggle Visibility
The most common reason I turn to JavaScript is to toggle the visibility of an
element. I recently learned that you can use the :checked
pseudo-class to
change the CSS of an element. (Thanks, Charlotte
Jackson!)
HTML:
<div class="toggle">
<!-- Checkbox toggle -->
<input type="checkbox" value="selected" id="beethoven-joke" class="toggle-input">
<label for="beethoven-joke" class="toggle-label">What was Beethoven's favorite fruit?</label>
<!-- Content to toggle -->
<div role="toggle" class="toggle-content">
BA-NA-NA-NA!
</div>
</div>
SCSS:
.toggle {
margin: 0 auto;
max-width: 400px;
}
//Style toggle
.toggle-label {
background: #fff;
cursor: pointer;
display: block;
font-size: 16px;
margin: 0 auto 1em;
padding: 1em;
&:after {
content: "+";
float: right;
}
}
//Style content
.toggle-content {
padding: 1em;
}
.toggle-input {
display: none; //Hide input element
&:not(checked) ~ .toggle-content {
display: none; //Hide content
}
}
//Display content when checkbox is "checked"
.toggle-input:checked {
~ .toggle-content {
display: block;
}
~ .toggle-label {
&:after {
content: "-"; //Change label's '+' to '-' when checked
}
}
}
In the end…
To recap, here’s a few reasons why using CSS over JavaScript can be beneficial to your project:
- Lightweight, no need to install a plugin or add another
.js
file - Clarity around what’s happening with styles and transitions
- Keep things simple and get things built quickly
And for good measure, here’s a few reasons to seek alternatives to these CSS-only methods:
- Accessibility concerns - a lot of these components need some JavaScript love to be more accessibility friendly. For more information about web accessibility, check out the WCAG Guidelines
- Support for touch devices -
:hover
can’t help you on a phone, so seek alternatives for accessing this content on a mobile device - JavaScript can help you accomplish a more well-rounded feature
Every project has different needs, so make sure you’re picking solutions that work best for your project’s goals. No single solution will work for all projects. In the meantime, it’s great to see what CSS can accomplish on its own.