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.
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 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.
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!
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:
HTML:
<main class=”parent”> <section class=”child”></section> <section class=”child”></section> <section class=”child”></section> </main>
CSS:
.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.
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:
<main> <header> <h1>This is my sticky header!</h1> </header> <section>This is my content</section> </main>
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.
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 — Start monitoring for free.
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.
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowEfficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.
Design React Native UIs that look great on any device by using adaptive layouts, responsive scaling, and platform-specific tools.
Angular’s two-way data binding has evolved with signals, offering improved performance, simpler syntax, and better type inference.
Fix sticky positioning issues in CSS, from missing offsets to overflow conflicts in flex, grid, and container height constraints.
3 Replies to "5 things you can do with CSS instead of JavaScript"
Very useful, thanks!
Nice. You can go even further and add css-only tooltips, modals, carousels, tab navigation and lots of other cool things as well.
modaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaal