Recently I’ve been building a few web sites without JavaScript where possible, relying instead on modern browser support for CSS.
Here are some things I’ve figured out, including toggling the NavBar burger dropdown, smooth scrolling, showing and hiding modal dialogs with transitions!
Smooth Scrolling
In a previous post, Single Page Bulma template with Smooth Scroll and Scroll Spy JavaScript, I used JavaScript to override the on-click behaviour simply to use smooth scrolling. Something like these two methods:
<a id="top" href="#" data-target="about">Top</a>
<a id="jump" href="#element" data-target="element">Jump</a>
<section id="element"></section>
<script>
document.getElementById("top").addEventListener("click", e => {
e.preventDefault();
window.scroll({ behavior: "smooth", left: 0, top: 0 });
});
document.getElementById("jump").addEventListener("click", e => {
e.preventDefault();
window.scroll({
behavior: "smooth",
left: 0,
top: document.getElementById(e.target.dataset.target).getBoundingClientRect().top + window.scrollY
});
};
</script>
With CSS, most browsers support scroll-behaviour
), so all I need is this style (not on the body
element mind):
html {
scroll-behavior: smooth;
}
Notable exceptions being all versions to-the of IE and Safari... in which case, the JavaScript method above would not do anything either!
Navigation Burger Drop Down
A really interesting trick with a checkbox, a label and CSS (which everybody knows except me, apparently):
- The trick is to link a checkbox control to a label,
- Such that, when the label is clicked (in my example below, a NavBar burger),
- It will trigger CSS on the checkbox
:checked
selector state to hide or show something (in my example below, a NavBar drop down menu)
The minimum code to do this for a Bulma NavBar is:
- Use the
label
element for the classnavbar-burger
instead ofa
. - Add an
input
element of typecheckbox
, giving it a unique ID, e.g.id="navbar-toggle"
, and making it hidden. - On the
label
element, add the attributefor="navbar-toggle"
to refer to the checkbox above. - Finally, add CSS to trigger on
:checked
to display thenavbar-menu
.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>NavBar Test</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css">
<style>
#navbar-toggle:checked + .navbar-menu { display:block; }
</style>
</head>
<body>
<nav id="navbar" class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item">Logo</a>
<label class="navbar-burger burger" for="navbar-toggle" role="button" aria-label="menu" aria-expanded="false">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</label>
</div>
<input id="navbar-toggle" type="checkbox" class="is-hidden"/>
<div class="navbar-menu">
<div class="navbar-end">
<a class="navbar-item">About</a>
<a class="navbar-item">Help</a>
<a class="navbar-item">Contact</a>
</div>
</div>
</nav>
<section class="section">
<div class="container">
<h1 class="title">Hello world!</h1>
</div>
</section>
</body>
</html>
Note that by not using the class is-active
like in the standard Bulma example, you may have styles go unapplied!
Modal Dialog Opening
Continuing with Bulma, we now address modal overlay dialogs, forwhich I’ll use the modal card boilerplate, with simple JavaScript to activate (show) the modal, and deactive (hide) it.
<a id="launch-modal" class="button">Launch modal</a>
<div class="modal">
<div class="modal-background"></div>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Modal title</p>
<a class="delete" aria-label="close"></a>
</header>
<section class="modal-card-body">
<h1 class="title">Hiya!</h1>
</section>
<footer class="modal-card-foot"></footer>
</div>
</div>
<script>
document.getElementById("launch-modal").addEventListener("click", () => {
document.getElementById("modal").classList.add("is-active");
});
document.getElementById("close-modal").addEventListener("click", () => {
document.getElementById("modal").classList.remove("is-active");
});
</script>
And without JavaScript, the trick is in using a CSS to check for #
anchors in the address using the :target
selector. It’s quite straightforward and even a standard example at w3schools CSS :target Selector... in fact even gives an example for a tabbed interface which would work with Bulma too!
All you need is:
- To show the modal, to click on a link with
href
pointing to the modal’s ID. This will trigger the CSS#modal:target
which sets the modaldisplay
style. - And to hide it, to click on a close button with
href
pointing anywhere else. Unfortunately, usinghref="#"
will scroll to the top of the page, which is not ideal! So, I just use a non-existent link. See CSS-Tricks On :target Fighting the Jump for options. - Similarly, clicking on the background would do the same.
<style>
#modal:target {
display: flex;
}
</style>
<a id="launch-modal" class="button" href="#modal">Launch modal</a>
<div class="modal">
<a class="modal-background" href="#x"></a>
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Modal title</p>
<a class="delete" aria-label="close" href="#x"></a>
</header>
<section class="modal-card-body">
<h1 class="title">Hiya!</h1>
</section>
<footer class="modal-card-foot"></footer>
</div>
</div>
Ah, again this won’t set the is-active
class, so beware!
Modal Dialog Animation
Posta.re shared code on GitHub to apply various transition animations when showing a modal dialog, e.g. slide in, fade in, zoom in, 3d flip, etc.
Studying the styles for the slideTop effect, the minimum CSS required is as below. I’m using .modal
with a .modal-card
rather than .modal-content
but either will do. Also, I’m not even bothering to apply any style (i.e. modal-fx-slideTop
), but rather, overriding relevant modal
styles directly.
.modal {
display:flex;
visibility:hidden;
}
.modal.is-active {
visibility:visible
}
.modal .modal-card {
transform:translateY(-20%);
opacity:0;
transition:all .3s
}
.modal.is-active .modal-card {
transform:translateY(0);
opacity:1;
}
Merging the last :target
hack, and given that you know is-active
is never applied (instead, use #modal:target
), then the CSS I land up with is:
.modal {
display:flex;
visibility:hidden;
}
#modal:target {
display: flex;
visibility: visible;
}
.modal-card {
transform:translateY(-20%);
opacity:0;
transition:all 0.4s
}
#modal:target .modal-card {
transform:translateY(0);
opacity:1;
transition:all 0.4s
}
Conclusion
Putting it all together:
Voila! No JavaScript!