Juan Martín García Full-stack graphic and web designer, teacher, and self-taught code nerd.

5 things you can do with CSS instead of JavaScript

6 min read 1828

I’m not the first one to state that the lines between CSS and JavaScript are becoming blurry as both languages evolve.

From custom properties (a.k.a variables) to filters, animations, or math operations, CSS has taken a lot of what we used to do in JavaScript (or in popular CSS preprocessors) and made it available to us, natively.

Both languages serve different purposes. With each browser release, feature release, and increase in properties, CSS is becoming an incredibly powerful language, capable of handling functionality that we previously relied on JavaScript for.

In this post, we’ll learn about some CSS golden nuggets you might not have heard about, that will natively (and gracefully!) handle things like smooth scrolling, dark mode, form validation, and more features that previously required multiple lines of JS trickery to work.

Smooth scrolling

There was a time when we had to rely on JavaScript (or even jQuery) implementations to do this, with window.scrollY to replicate this behavior. Those days are gone now, thanks to the scroll-behavior property. We can now handle smooth scrolling on our website with, wait for it, one line of CSS code!

html {
  scroll-behavior: smooth;

Browser support is around 75%, and coming to Edge 76 soon. Check out how it works in the Codepen below:

See the Pen
CSS-Only Smooth Scrolling
by Juan Martín García (@imjuangarcia)
on CodePen.

Dark mode

Dark mode has been the hot trend lately after macOS released its dark mode functionality and Safari implemented the prefers-color-scheme media feature, which allows us to detect if the user has dark mode enabled by default.

You might think of dark mode as a complex feature to implement, involving CSS variables, different colors for each scheme, and some JavaScript to hook up the necessary click event to target the changes on the website. And while that’s partially true, and it’s currently the standard way to implement it (that’s how I do it on my website) it doesn’t need to be this complicated.

Wei Gao showed us on her blog a clever way to achieve a similar result (more of a reversed mode) using mix-blend-mode: difference, one of the blending modes supported on CSS. If you’ve ever played around with Photoshop Blending Modes, this is the same thing but directly on the browser.

Some of its advantages include not having to specify the inverted colors (the blend mode will do that for you), and you can isolate the elements you don’t want to change. Some of its limitations are that you don’t have a full range of colors, and performance can be a concern.

Currently, native browser support is at 77% plus 13% with prefixes (91% global), with Edge support coming on version 76.

For a more in-depth explanation of how this blending mode works, make sure you check Wei’s awesome article on it. For a fun experiment with it, check this Codepen:

See the Pen
Dark Mode with mix-blend-mode: difference
by Juan Martín García (@imjuangarcia)
on CodePen.

Truncate text

This is one of my personal favorites because it’s a common problem I run into when developing websites that rely on a CMS to populate content. Variable length on the copywriting might make your lovely-designed cards look inconsistent across different sizes or resolutions. Dave Rupert has a great article on that matter.

In the past, I’ve always reached out to JavaScript-based solutions without even thinking about it because most CSS techniques for achieving this result were quite “hacky”. But as I work on including a blog to my website, I discovered a couple of CSS properties that, coupled together, might be able to provide a native, easy-to-implement solution. Meet text-overflow and line-clamp!

You can check out the Codepen here:

See the Pen
CSS-Only Text Truncation
by Juan Martín García (@imjuangarcia)
on CodePen.


This is a widely adopted, fully supported native CSS-only solution to control how text behaves when it overflows its containing element. You can set its value to be ellipsis and that’ll give you the Unicode character. So far so good, but its main limitation is that you’ll always get one line of truncated text, regardless of your text’s length. So this might be a perfect fit for titles, but not so useful for excerpts, reviews or long passages of text. See below for an example:

That’s where line-clamp comes into play.


The line-clamp property isn’t new either. Dave DeSandro showed us this technique roughly a decade ago (hence the need for the old flexbox implementation with display: -webkit-box and -webkit-box-orient: vertical).

Then what’s new here? Firefox implemented it on version 68 and, wait for it… with the -webkit prefix! And now that Edge is Chromium-based, we can also use the -webkit prefix to boost browser support up to 92%.

That means we can now use a combination of three CSS lines to truncate multiple lines of text, like so. The only gotcha here is that the specification for line clamps is part of the CSS Overflow Module Level 3 which is currently in Editor’s Draft, which might imply there could be some changes to the spec. Another thing to consider is that you can’t control the number of characters to show, which might lead to some not so convenient (yet funny) truncation scenarios. But other than that, happy CSS clamping!

Scroll snapping

CSS scroll snapping is another handy functionality Chrome users have had for a while and we can now enjoy on Firefox with its latest 68 release. We will, also, get it on version 76 of Edge, bumping up overall browser support to all major browsers.

Have you ever noticed how some fancy websites will create fullscreen sections, and lock the viewport on specific locations as you scroll? Here’s an example of that behavior.

Getting this to work properly a while back was tricky, with lots of math calculations and JavaScript involved. But now, CSS is capable of creating interactions like this one natively.

It works similarly to Flexbox or CSS Grid in the sense that you need a container element on which you’ll set the scroll-snap-type and multiple children with scroll-snap-align set to them, like so:


<main class=”parent”>
  <section class=”child”></section>
  <section class=”child”></section>
  <section class=”child”></section>


.parent {
  scroll-snap-type: x mandatory;

.child {
  scroll-snap-align: start;

The scroll-snap-type accepts two different values: mandatory, which will force the snap to either the top or bottom of the element, or proximity, which will do the math for you and snap when the content is close enough to the snap point.

Another property we can set on the parent container is scroll-padding, which might be handy if you have fixed elements on the layout (like a fixed header or, why not, a cookie policy notification 😅) that might otherwise hide some of the content.

For the children, we only have scroll-snap-align for now, which will tell the container which points to snap to (top, center or bottom).

While it might feel tempting to go willy-nilly with adding scroll snapping on your entire website now that you know this technique can achieve that result with just a couple of CSS lines and no math involved, remember the one and only law of web design, according to Robin Rendle: Don’t mess with the scroll. This technique might be useful for things like sliders, image galleries or some specific sections on your page, but use it sparingly since it can affect performance and the user’s experience overall.

You can check out the Codepen here:

See the Pen
CSS-Only Horizontal Fullscreen Gallery with Scroll Snapping
by Juan Martín García (@imjuangarcia)
on CodePen.

Sticky navigation

Following up on features that previously required a lot of JavaScript math and were pretty expensive to implement performance-wise, we have sticky positioning. Where we previously needed offsetTop and window.scrollY we now have position: sticky to do all the wizardry for us! An element with sticky positioning will behave as a relatively-positioned element until a given point on the viewport is reached to then become a fixed-positioned element. Browser support is up to 92% with the -webkit prefix.

So, while it might sound as easy as doing something like:

header {
  position: sticky;
  top: 0;

To nicely set your header to be sticky, it’s important to know that the structure of your HTML matters! So for example, if your HTML structure looks like this:

    <h1>This is my sticky header!</h1>
  <section>This is my content</section>

The header will only be able to stick on the area that its parent (in this case, the <main> tag) covers. This “sticky parent” determines the scope on which the “sticky item” can act. This gotcha is better explained by Elad Shechter in this article, and here’s a fun little experiment using this technique.

You can check out the Codepen here:

See the Pen
CSS Race using Sticky Positioning
by Juan Martín García (@imjuangarcia)
on CodePen.

Whether it’s CSS or JS, it still needs to be monitored. Use LogRocket to ensure your frontend behaves like it should.

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.https://logrocket.com/signup/

LogRocket is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — .

Bonus to wrap up: @supports media-rule

Even though these CSS features are widely adopted and supported, as discussed above, you might still want to check if they are available on the browser before adding them. If that’s the case, you can use the @supports feature query, which is widely adopted by browsers and allows you to test if the browser supports a specific property: value pair before applying a set of styles. The syntax looks as follow:

@supports (initial-letter: 4) {
  p::first-letter {
    initial-letter: 4;

With this handy feature query, you can apply a set of styles just on those browsers that support them. The syntax might sound familiar since it’s exactly how we write media queries and is a great way to do what’s called progressive enhancement, using these top-notch features right now on browsers that have them, while preventing inconsistent behavior on browsers that don’t have them. Jen Simmons explains this better on her Resilient CSS videos.

So that’s it! Hopefully, these state-of-the-art CSS features will help you ship a smaller JavaScript bundle, while still creating interesting and compelling UIs. Also, feel free to check out these Codepens again as well.


Juan Martín García Full-stack graphic and web designer, teacher, and self-taught code nerd.

3 Replies to “5 things you can do with CSS instead of…”

  1. Nice. You can go even further and add css-only tooltips, modals, carousels, tab navigation and lots of other cool things as well.

Leave a Reply