Why JavaScript sucks and CSS rules 😉

Ralf
REWRITE TECH by diconium
8 min readOct 25, 2023

Performance Boosting — Part 4 — CSS/HTML instead of JS

CSS instead of JavaScript

Actually, the JavaScript part of my performance boosting series should appear now, but I thought it was more important to first show how and when we can do without JavaScript by using plain HTML and CSS.

First let’s check some performance advantages we have by using CSS instead of JS:

  • When using JavaScript for DOM manipulations the layout needs to be re-rendered, whereas CSS is ready to go.
  • CSS is parsed and interpreted faster than JavaScript.
  • Less JavaScript code results in a better Total Blocking Time (TBT).
  • CSS does not block the critical rendering path.
  • By using CSS the browser doesn’t have to recalculate the layout every time the page is refreshed.

CSS also has other advantages compared to JS:

  • CSS has a high fault tolerance. A simple syntax error in JavaScript can cause the entire website or app to stop working. CSS is more forgiving ;)
  • Users can disable JavaScript in the browser settings, which can break the functionality and usability of your website. CSS can’t be disabled.

Conclusion: JavaScript must always be parsed and interpreted. These steps cause a delay in page loading. So let’s take a look at the places where JavaScript can be removed:

Dropdown navigation

Let’s start with a very simple example that has been around for a long time: the CSS dropdown menu.

On most websites, the navigation structure has several levels of hierarchy. A long time ago, scripting was used for this to enable additional navigation levels to be opened. Fortunately, that is now over…

The submenu is first hidden and then shown again by triggering the hover event of the parent container (in this case a <li>). The magic comes from these few lines of CSS alone:

.subnav {
display: none;
}

li:hover .subnav {
display: block;
}

You can see a complete basic example here:

calc() + vh

In the past, it was necessary to calculate measurements using JavaScript. Since the calc() function has been available, simple layout calculations can be implemented using stylesheets.

Let’s take the following example: here we have a navigation bar and a header teaser with a background image. We want the teaser to take up the entire height minus the height of the navigation. Using the combination of calc() and the measure 100vh (100% of the viewport height):

Animations and transitions

Before CSS provided the means to create smooth animations, you had to use JavaScript to perform memory-intensive calculations to get the desired result.

In this example, a box is created that changes its size and background color when the mouse hovers over it. The Transition property indicates that the width, height, and background color change in 1 second with a slight ease.

.box {
width: 100px;
height: 100px;
background-color: red;
transition: width 1s ease, height 1s ease, background-color 1s ease;
}

.box:hover {
width: 200px;
height: 200px;
background-color: blue;
}

Smooth scrolling

There was a time when smooth scrolling had to be implemented via JS. Fortunately, this time is over.

With one line of CSS code you can now move the user to your jump labels in a smooth animation:

html {
scroll-behavior: smooth;
}

Truncate text

A few years ago, if you still wanted to shorten text — especially multi-line text — and end it with three dots (…), you either had to deliver it from the server in the desired form or use JavaScript.

Check out examples for single-line and multi-line truncation:

Sticky navigation

One of my favorite CSS features of the last few years is the sticky positioning option. This relates to elements that are only in the flow of the page layout. As soon as you want to scroll past this container, it gets stuck at the top of the browser. Previously, you had to listen to the scroll event via JS and then the position of an element had to be switched to “fixed” — or even worse: a copy of the container to be glued was created and the DOM was further bloated.

header {
position: sticky;
top: 0;
}

CSS variables

The ability to use variables as values in CSS simplifies the creation of templates by server-side systems. If you wanted to serve custom CSS, you had to add server-side code to the CSS code where appropriate — which made readability worse, increased the amount of code and increased rendering time.

Here is an example using PHP to work with variables:

/* output each value by PHP */
.container {
height: <?php echo $height; ?>;
color: <?php echo $primaryColor; ?>;
}

h1 {
color: <?php echo $primaryColor; ?>;
}

/* using CSS variables */
:root {
--primary-color: <?php echo $primaryColor; ?>;
--height: <?php echo $height; ?>;
}

.container {
height: var(--height);
color: var(--primary-color);
}

h1 {
color: var(--primary-color);
}

You can even write default values for your variables and overwrite them later by adding rules like:

<div class="var">
Text
</div>

<div class="var var2">
Text 2
</div>
:root {
--textColor: red;
}

.var {
color: var(--textColor);
}

.var2 {
--textColor: blue;
}

Dark mode

In order to display dark mode in modern browsers, no template changes are required via JavaScript. It is very easy to use with Media Query:

@media (prefers-color-scheme: dark) {
body {
background-color: #222;
color: #eee;
}
}

Keep elements out of rendering path

If you wanted to keep HTML elements out of the render, then you had to use techniques like Shadow DOM, Hydration, etc. These techniques assume the use of JavaScript. There is a new CSS property that should greatly speed up page loading of websites by removing offscreen elements from the rendering. The feature is cited by Google developers as one of the most impactful CSS features for improving load time.

You can easily exclude elements from the rendering by adding the following rule:

.offscreen-element {
content-visibility: hidden;
}

<selectmenu>

Have you almost gone crazy trying to create a drop-down menu according to a designer’s ideas? Maybe you also used JavaScript to create a pseudo drop-down menu just to meet the visual requirements.

But don’t worry, the new <selectmenu> element is on the way and makes the design very easy and flexible by giving the individual interaction elements their own HTML containers.

<selectmenu>
<div slot="button">
<button behavior="button">Open</button>
<span class="label">Choose an option</span>
</div>
<option>Option 1</option>
<option>Option 2</option>
<option>Option 3</option>
</selectmenu>

Accordion

In order to implement a functioning accordion without using JavaScript, pure HTML is sufficient — without any CSS.

The <details> tag serves exactly this purpose. Within this tag, a <summary> tag serves as a toggle button. The other content that is in the <details> container is the content that is shown and hidden.

Check the Codepen below for an example:

Oldschool browser-safe accordion

If you want to continue to support old browsers, you won’t get very far by using <details>. However, there is another way to do this, which we can do without scripting languages. In contrast to <details>, this requires the use of CSS.

With radio buttons we have the opportunity to do the magic. First we hide the radio button itself as it has no place in our design :)

Also, we hide the paragraph which is our collapsible content. I put this in a <p> element.

If the radio button is checked by clicking on the <label>, then the <p> is displayed again via the pseudo status “:checked”. It’s really simple magic:

Custom Checkboxes and Radio Buttons

Custom checkboxes and radio buttons in CSS have become an essential part of modern web development, allowing developers to enhance the user experience and create visually appealing interfaces.

When it comes to customizing checkboxes and radio buttons, CSS provides a wide range of possibilities. By leveraging pseudo-elements such as ::before and ::after, we can create custom checkbox designs that align with the overall aesthetic of the website. Through careful manipulation of properties like background-color, border-radius, and transitions, we can transform the default checkboxes into eye-catching elements that seamlessly blend with the rest of the UI. Additionally, CSS animations can be applied to checkboxes to provide subtle feedback when they are checked or unchecked, enhancing the user’s understanding of their actions.

HTML code:

<label class="wrapper">
Checkbox Label Text

<input type="checkbox" class="checkbox">
<span class="checkmark"></span>
</label>

CSS code:

/* Hide default checkbox */
.checkbox {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}

/* Custom checkbox */
.checkmark {
position: absolute;
top: 0;
left: 0;
height: 25px;
width: 25px;
background-color: #ddd;
}

/* Checked appearance */
.checkbox:checked ~ .checkmark {
background-color: #000;
}

/* Checkmark */
.checkmark:after {
content: "";
position: absolute;
display: none;
left: 9px;
top: 5px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 3px 3px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}

/* Checkmark when checked */
.checkbox:checked ~ .checkmark:after {
display: block;
}

Prevent clicks

You want to prevent HTML elements from being clickable?
With JavaScript this has always been possible via “event.preventDefault();”. With a simple HTML attribute this will be possible in the future, without any JS code. The new attribute “inert” prevents clicking on HTML elements and their child nodes.

<div inert>
<button>Hi, I'm not clickable, because my parent told me not to be.</button>
</div>

CSS has also been offering the ability to make elements non-clickable for some time. The magic word is “pointer-events”:

.do-not-click-me {
pointer-events: none;
}

How it goes on with the website performance series

In order not to push this article into infinity, I have decided to separate the topic “CSS instead of JS” into at least two parts. In the next part you will learn how other components and functions can be implemented without using JavaScript.

In part 5 of my website performance boosting series I will show you how to build slideshows, dialog boxes, tooltips and much more without using JS. So keep your eyes peeled, we’ll read each other ;)

Useful links

Check the road to my current article

--

--