Tag: Without

GIFs Without the .gif: The Most Performant Image and Video Options Right Now

So you want an auto-playing looping video without sound? In popular vernacular this is the very meaning of the word GIF. The word has stuck around but the image format itself is ancient and obsolete. Twitter, for example, has a “GIF” button that actually inserts a <video> element with an MP4 file into your tweet — no .gif in sight. There are a beguiling amount of ways to achieve the same outcome but one thing is clear: there’s really no good reason to use the bulky .gif file format anymore.

Use a HTML <video> element

It’s easy to recreate the behavior of a GIF using the HTML video element.

<video autoplay loop muted playsinline src="cats.mp4"></video>

With this code the video will play automatically in a continuous loop with no audio. playsinline means that mobile browsers will play the video where it is on the page rather than opening in fullscreen.

While the HTML video element itself has been supported for many years, the same can’t be said for the wide variety of video formats.

Videos are made up of two parts: the container and the video codec. (If your video contains audio then it is made up of three parts, the third being the audio codec.) Containers can store video, audio, subtitles and meta information. The two most common containers for video on the web are MP4 and WebM. The container is the same as the file type — if a file ends with a .mp4 extension, that means it’s using an MP4 container. The file extension doesn’t tell you the codec though. Examples of video codecs commonly used on the web include VP8, VP9, H.264 and HEVC (H.265). For your video to play online, the browser needs to support both the video container and the codec.

Browser support for video is a labyrinthine mess, which is part of the reason YouTube embeds are ubiquitous, but that doesn’t work for our use case. Let’s look at the video formats that are worth considering.


  • MP4 was originally released in 2001. It is supported by all web browsers and has been for quite some time.
  • WebM was released in 2010. It works in all browsers except for iOS Safari.


  • The H.264 codec works in all browsers.
  • HEVC/H.265, the successor of H.264, is supported by Safari, Edge, and Chrome (as of version 105).
  • VP9 is the successor to the VP8 codec. VP9 is supported by all the browsers that support WebM.
  • The AV1 codec has been supported in Chrome since 2018 and Firefox since 2019. It has not yet shipped in Edge or Safari.

An MP4 file using the H.264 codec will work everywhere, but it doesn’t deliver the best quality or the smallest file size.

AV1 doesn’t have cross-browser support yet but, released in 2018, it’s the most modern codec around. It’s already being used, at least for some videos and platforms, by Netflix, YouTube and Vimeo. AV1 is a royalty-free video codec designed specifically for the internet. AV1 was created by the Alliance for Open Media (AOM), a group founded by Google, Mozilla, Cisco, Microsoft, Netflix, Amazon, and Intel. Apple is now also a member, so it’s safe to assume all browsers will support AV1 eventually. Edge is “still evaluating options to support AVIF and AV1.”

The recently redesigned website from development consultancy Evil Martians is a testament to the file-size reduction that AV1 is capable of.

If you want to use newer video formats with fallbacks for older browsers, you can use multiple <source> elements. The order of the source elements matter. Specify the ideal source at the top, and the fallback after.

<video autoplay loop muted playsinline>   <source src="cats.webm" type="video/webm"> <!-- ideal -->   <source src="cats.mp4" type="video/mp4"> <!-- fallhack --> </video>

Given the above code, cats.webm will be used unless the browser does not support that format, in which case the MP4 will be displayed instead.

What if you want to include multiple MP4 files, but with each using a different codec? When specifying the type you can include a codecs parameter. The syntax is horrifically complicated for anybody who isn’t some kind of hardcore codec nerd, but it looks something like this:

<video autoplay loop muted playsinline>   <source src="cats.mp4" type="video/mp4; codecs=av01.0.05M.08" >   <source src="cats.mp4" type="video/mp4" > </video>

Using the above code the browser will select AV1 if it can play that format and fallback to the universally-supported H.264 if not. For AV1, the codecs parameter always starts with av01. The next number is either 0 (for main profile), 1 (for high profile) or 2 (for professional profile). Next comes a two-digit level number. This is followed either by the letter M (for main tier) or H (for high tier). It’s difficult to understand what any those things mean, so you could provide your AV1 video in a WebM container and avoid specifying the codec entirely.

Most video editing software does not allow you to export as AV1, or even as WebM. If you want to use one of those formats you’ll need to export your video as something else, like a .mov, and then convert it using the command-line tool FFmpeg:

ffmpeg -i yourSourceFile.mov -map_metadata -1 -c:a libopus -c:v librav1e -qp 80 -tile-columns 2 -tile-rows 2 -pix_fmt yuv420p -movflags +faststart -vf &quot;scale=trunc(iw/2)*2:trunc(ih/2)*2&quot; videoTitle.mp4

You should use the most high-resolution source file you can. Obviously, once image quality is lost you can’t improve it through conversion to a superior format. Using a .gif as a source file isn’t ideal because the visual quality of .gif isn’t great, but you’ll still get the benefit of a large reduction in file size:

ffmpeg -i cats.gif -map_metadata -1 -an opus -c:v librav1e -qp 80 -tile-columns 2 -tile-rows 2 -pix_fmt yuv420p -movflags +faststart -vf &quot;scale=trunc(iw/2)*2:trunc(ih/2)*2&quot; cats.mp4

On Mac, you can download FFmpeg using Homebrew:

brew install ffmpeg

Here’s a nice example of video in web design on the masterfully designed Oxide website:

If you want to use the video as a background and place other elements on top of it, working with <video> is slightly more challenging than a CSS background-image, and requires code that goes something like this:

.video-parent {   position: relative;   width: 100vw;   height: 100vh; }   .video-parent video {   object-fit: cover;   position: absolute;   inset: 0;   z-index: -1;   width: 100%;   height: 100%; }

The <video> element is a perfectly okay option for replacing GIFs but it does have one unfortunate side-effect: it prevents a user’s screen from going to sleep, as explained in this post from an ex- product manager on the Microsoft Edge browser.

The benefits of using an image

Whether it’s an animated WebP or animated AVIF file, using images rather than video comes with some benefits.

I’m not sure how many people actually want to art-direct their GIFs, but using the <picture> element does open up some possibilities that couldn’t easily be achieved with <video>. You could specify different animations for light and dark mode, for example:

<picture>   <source srcset="dark-animation.avifs" media="(prefers-color-scheme: dark)">   <img src="light-animation.avif" alt=""> </picture>

We might want a video on mobile to be a different aspect ratio than on desktop. We could just crop parts of the image with CSS, but that seems like a waste of bytes and somewhat haphazard. Using a media query we can display a different animated image file based on the screen size or orientation:

<picture>   <source type="image/avif" srcset="typeloop-landscape.avifs" media="(orientation: landscape)"">   <img src="typeloop-portrait.avif" alt=""> </picture>

All of this is possible with video — you can use matchMedia to do any media queries in JavaScript and programmatically change the src of a <video> element:

const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); if (mediaQuery.matches) {   document.querySelector("video").src = "dark-animation.mp4"; }

I believe that whenever there’s a way to do something with markup it should be preferred over doing it JavaScript.

You can use raster images inside of an SVG using the <image> element. This includes animated image formats. There’s not much you can do with an image inside an SVG that you couldn’t already do with CSS, but if you group an image with vector elements inside an SVG, then you do get the benefit that the different elements move and scale together.

The <img> element has the benefit of native lazy-loading:

<img loading="lazy" src="cats.avif" alt="cats">

If you want a background video that takes up the entire screen, it’s slightly easier to position a background-image than a HTML <video> element:

.background-video {   background-image: url("coolbackground.webp");   background-repeat: no-repeat;   background-size: cover;   height: 100vh;   width: 100vh; } 

If you want to support older browsers you could use the <picture> element with a fallback of either an animated WebP or, just for Safari, an img with a video src, or if you care about ancient browsers, maybe an APNG (animated PNG) or a GIF. Using multiple image formats this way might be impractical if you’re optimizing images manually; but it is relatively trivial if you’re using a service like Cloudinary.

<picture>   <source type="image/avif" srcset="cats.avif">   <img src="cats.webp"> </picture>

There’s still no well-supported way to specify fallback images for CSS backgrounds. image-set is an equivalent of the <picture> element, [but for background-image. Unfortunately, only Firefox currently supports the type attribute of image-set.

.box {   background-image: image-set(     url("cats.avif") type("image/avif"),     url("cats.webp") type("image/webp")); }

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.


Chrome Firefox IE Edge Safari
108* 89 No 105* TP

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
105* 104 105* 16.1

Use animated WebP

The WebP image format was introduced by Google in 2010. WebP, including animated WebP, has broad browser support.

A cat flying through space leaving a rainbow trail
<img src="nyancat.webp" alt="A cat flying through space leaving a rainbow trail">

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.


Chrome Firefox IE Edge Safari
32 65 No 18 16.0

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari
105 104 4.2-4.3 14.0-14.4

Use animated AVIF

WebP is now twelve years old. The more modern AV1 Image File Format (AVIF), released in 2019, is the best image format for most use cases on the web. Converting a .gif file to AVIF can reduce bytes by over 90%.

<img src="nyancat.avif" alt="A cat flying through space leaving a rainbow trail">

As its name suggests, AVIF is based on the the AV1 video codec. Like WebP, AVIF can be used for both still images and animation. There’s not much difference between an animated AVIF file and an AV1 video in an MP4 container.

You can put a shadow on AVIF animation, e.g.:

filter: drop-shadow(2px 4px 6px black);

AVIF is already supported by Safari, Firefox, Samsung Internet, and Chrome. Firefox only shipped support for still images, not animated AVIF. Safari supports animation as of version 16.1. Unfortunately, because Firefox does support AVIF, just not animated AVIF, it’s impossible to successfully use the <picture> element to display AVIF only to browsers that support animation. Given the following code, Firefox would display the AVIF, but as a static image, rather than showing the animated WebP version:

<picture>   <source srcset="https://fonts.gstatic.com/s/e/notoemoji/latest/1f4a9/512.avif" type="image/avif">   <img src="https://fonts.gstatic.com/s/e/notoemoji/latest/1f4a9/512.webp" alt="💩" width="32" height="32"> </picture>

Tooling for AVIF is still improving. Video editing software does not enable you to export footage as animated AVIF or animated WebP. You’ll need to export it in some other format and then convert it. On the website ezgif.com you can upload a video file or a .gif and convert it to AVIF or WebP. You could also use FFmpeg. Using Cloudinary you can upload a video file or an old .gif and convert it to pretty much any format you want — including animated WebP and animated AVIF. As of time of writing, Squoosh, an image conversion app, doesn’t support animated AVIF.

Adoption remains lacking in design software. When viewing a prototype, Figma will play any animated GIFs included in the design. For AVIF, by contrast, you can’t even import or export a still image.

An error in Figma that says files failed to import.

Use a video with an <img> element

In 2018, Safari 11.1 gave developers the ability to use a video file as the source of the HTML <img> element. This works in Safari:

<img src="cat.mp4" alt="A Siamese cat walking in a circle">

All the same codecs that Safari supports for <video> are supported by <img>. This means you can use MP4, H.264, and HEVC.

In Safari, video files will also work anyplace in CSS where you could use an image, like background-image or border-image:

.video-border {     border: 40px solid transparent;   border-image: url(abstract_bg_animation.mp4) 100 round; }

One strange consequence of this feature in Safari is that the poster image of a <video> element can also be a video. The poster will autoplay even if you have blocked video’s from auto-playing. Safari claimed this feature came with performance benefits, not just over using .gif files but also over using the <video> element. According to Apple:

By placing your videos in <img> elements, the content loads faster, uses less battery power, and gets better performance.

Colin Bendell, co-author of O‘Reilly’s High Performance Images, wrote about the shortcomings of the <video> tag for our use case:

Unlike <img> tags, browsers do not preload <video> content. Generally preloaders only preload JavaScript, CSS, and image resources because they are critical for the page layout. Since <video> content can be any length – from micro-form to long-form – <video> tags are skipped until the main thread is ready to parse its content. This delays the loading of <video> content by many hundreds of milliseconds.


Worse yet, many browsers assume that <video> tags contain long-form content. Instead of downloading the whole video file at once, which would waste your cell data plan in cases where you do not end up watching the whole video, the browser will first perform a 1-byte request to test if the server supports HTTP Range Requests. Then it will follow with multiple range requests in various chunk sizes to ensure that the video is adequately (but not over-) buffered. The consequence is multiple TCP round trips before the browser can even start to decode the content and significant delays before the user sees anything. On high-latency cellular connections, these round trips can set video loads back by hundreds or thousands of milliseconds.

Chrome has marked this as “WontFix” — meaning they don’t intend to ever support this feature, for various reasons. There is, however, an open issue on GitHub to add it to the HTML spec, which would force Google’s hand.

Respecting user preferences

Video has the benefit of automatically respecting a users preferences. Firefox and Safari allow users to block videos from automatically playing, even if they don’t have any audio. Here are the settings in Firefox, for example:

firefox autoplay settings open in a modal.

The user can still decide to watch a certain video by right-clicking and pressing play in the menu, or enable autoplay for all videos on a specific website.

Contextual menu for a video.

For users who haven’t disabled autoplay, it’s nice to have the option to pause an animation if you happen to find it annoying or distracting (a user can still right-click to bring up the pause option in a menu when video controls aren’t shown). Success Criterion 2.2.2 Pause, Stop, Hide of the WCAG accessibility guidelines states:

For any moving, blinking or scrolling information that (1) starts automatically, (2) lasts more than five seconds, and (3) is presented in parallel with other content, there is a mechanism for the user to pause, stop, or hide it unless the movement, blinking, or scrolling is part of an activity where it is essential.

With the <video> element, you’ll achieve that criterion without any additional development.

There’s also a “reduce motion” user setting that developers can respect by reducing or removing CSS and JavaScript web animations.

macOS settings window for display accessibility with rediced motion checked.

You can also use it to display a still image instead of an animation. This takes extra code to implement — and you need to host a still image in additional to your animated image.

<picture>   <source     srcset="nyancat.avifs"     type="image/avif"     media="(prefers-reduced-motion: no-preference)"   />   <img src="nyancat.png" alt="Nyan cat" width="250" height="250" /> </picture>

There’s another downside. When using the <picture> element in this way if the user has checked “reduce motion”there’s no way for them to see the animation. Just because a user prefers less animation, doesn’t mean they never want any — they might still want to be able to opt-in and watch one every now and then. Unlike the <video> element, displaying a still image takes away that choice.

Checking for progressive enhancement

If you want to check that your <picture> code is properly working and fallback images are being displayed, you can use the Rendering tab in Chrome DevTools to turn off support for AVIF and WebP image formats. Seeing as all browsers now support WebP, this is a pretty handy feature.

Chrome DevTools with Rendering panel open optons for disabling AVIF and WebP images.

While it’s usually the best option to create animations with CSS, JavaScript, DOM elements, canvas and SVG, as new image and video formats offer smaller files than what was previously possible, they become a useful option for UI animation (rather than just nyancat loops). For one-off animations, an AVIF file is probably going to be more performant than importing an entire animation library.

Circular badge that reads Match Accepted with an animated blue progress highlight going around it.
Here’s a fun example of using video for UI from all the way back in 2017 for the League of Legends website.


After Effects is a popular animation tool from Adobe. Using an extension called Bodymovin, you can export animation data from After Effects as a JSON file.

Then there’s Lottie, an open-source animation library from Airbnb that can take that JSON file and render it as an animation on different platforms. The library is available for native iOS, Android, and React Native applications, as well as for the web. You can see examples from Google Home, Target, and Walgreens, among others.

Once you’ve included the dependency you need to write a small amount of JavaScript code to get the animation to run:

<div id="lottie"></div>
const animation = bodymovin.loadAnimation({   container: document.getElementById('lottie'),   path: 'myAnimation.json',   renderer: 'svg',   loop: true,   autoplay: true, })

You can optionally change those settings to only play after an event:

const lottieContainer = document.getElementById('lottie'); const animation = bodymovin.loadAnimation({   container: lottieContainer,    path: 'myAnimation.json',   renderer: 'svg',   loop: true,   autoplay: false,   }) // Play the animation on hover lottieContainer.addEventListener('mouseover', () => {   animation.play(); }); // Stop the animation after playing once animation.addEventListener('loopComplete', function() {   animation.stop(); });

Here’s a cute example of a cat typing on a keyboard I took from Lottiefiles.com (the website is a useful website for previewing your own Lottie JSON file animations, rather than needing to install After Effects, as well finding animations from other creatives):

You can also programmatically play an animation backwards and change the playback rate.

If you do choose to use Lottie, there’s a Figma plugin for Lottie but all it does is convert JSON files to .gif so that they can be previewed in prototyping mode.

Abd what about Lottie’s performance? There’s size of the library — 254.6KB (63.8 gzipped) — and the size of the JSON file to consider. There’s also the amount of DOM elements that get created for the SVG parts. If you run into this issue, Lottie has the option to render to a HTML <canvas>, but you’ll need to use a different version of the JavaScript library.

const animation = bodymovin.loadAnimation({   container: document.getElementById('lottie'),    path: 'myAnimation.json',   renderer: 'canvas', })

Lottie isn’t a full replacement for gifs. While After Effects itself is often used with video clips, and Lottie can render to a HTML <canvas>, and a canvas can play video clips, you wouldn’t use a Lottie file for that purpose. Lottie is for advanced 2D animations, not so much for video. There are other tools for creating complex web animations with a GUI like SVGator and Rive, but I haven’t tried them myself. 🤷‍♂️

I wish there was a TL;DR for this article. For now, at least, there’s no clear winner…

GIFs Without the .gif: The Most Performant Image and Video Options Right Now originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.


, , , , , , , ,

What is Chromium Without Chrome on Top?

Raw Chromium, perhaps?

So, Chrome is based on Chromium which is open-source. Chrome is Chromium with Google’s extra stuff on top of it. What extra stuff? Kinda lots! A few years ago, The Verge published “Microsoft reveals all the Google things it removed in its Chromium Edge browser” with this image from Microsoft listing out all the stuff:

A long list of features Microsoft has removed from Chromium split into four columns.

So, not all Chromium features are from Chrome

I guess that implies all this stuff is actually in Chromium, but not added to Chrome in some build step. That means if you wanna build your own Chromium fork and de-couple yourself from Google, you’ve got some work to do.

Several big players have done that work. Clearly, Microsoft has done it with Edge. Vivaldi and Brave are other big Chromium-based browsers with presumably similar de-Googleification.

Dan Abramov was asking around about this the other day:

Sounds like Dan (and by extension: me) learned through this thread that Chromium isn’t actually just the core browser stuff where Chrome then adds stuff on top of it. It’s that if you want to base another browser on Chromium, you have to yank stuff out of Chromium.

Seems a smidge weird to me, but hey, it’s open-source, so if you don’t like it, fork it. And obviously many have. Perhaps most notable is ungoogled-chromium. It lists this as the philosophy:

  1. Remove all remaining background requests to any web services while building and running the browser
  2. Remove all code specific to Google web services
  3. Remove all uses of pre-made binaries from the source code, and replace them with user-provided alternatives when possible.
  4. Disable features that inhibit control and transparency, and add or modify features that promote them (these changes will almost always require manual activation or enabling).

I have zero doubt that the browser world is converging on Chromium. You can imagine Apple hanging onto their own thing with WebKit forever, but things don’t seem to be going terribly well at Mozilla, and they haven’t for a while. Mozilla’s money seems to come from Google anyway so it’s tough to imagine Mozilla’s browser engines hanging on for that much longer. Y’all can call me an ignorant asshole in January 2032 if Mozilla still has a competitive browser engine.

The health of the browser ecosystem would benefit from a cleaner, company-agnostic version of Chromium (and maybe call it something else). If most browsers are based on it, so be it, but let the innovation happen from a level playing field.

What is Chromium Without Chrome on Top? originally published on CSS-Tricks. You should get the newsletter and become a supporter.


, ,

Think Without Boxes

What’s the one thing people can do to make their website better? Now that is a good question. One with many right answers, like improving performance, taking care of accessibility, and upgrading user experience as prime examples. These are all great tips, and there’s more like them, but how do you choose just one? And, should you choose just one?

If we knew what “better” meant, then maybe it would be easier. Does it mean faster? Prettier? The answer isn’t clear. A developer who maintains a legacy codebase will tell you that a “better website” is one with clean and readable code (and they’d be right).

Better, then, is a subjective term. I started looking at this question from my own subjective point of view. I’ve built a lot of sites in my time, and I know enough do’s and don’ts, but I’m not really an “expert” in anything.

But what I do know—what I’m sure about—is that websites nowadays have to stop being patterned, themed, and framed. Not that patterns, themes, and frames aren’t good, but when we heavily rely on them, we wind up with the same site over and over again, only with (slightly) different content.

🎵 Little boxes on the hillside / Little boxes made of ticky tacky / Little boxes all the same.

So if I have to recommend only one thing you can do to make your site better, it is…

Get creative

Whether it’s a portfolio website, a blog, or an eCommerce site, you want to stand out. You want people to remember you, to be excited about your product, and interact with your content. You can’t just give them the same experience they’ve already had thousands of times before.

So be unique, be original, be impressive.

Your website is you—it’s your product, your company, your livelihood. You don’t have to accept the generic conventions, and shouldn’t stick your dream website into a box that someone else built.

Start clean, build up, and don’t be afraid to test weird features. Play around with layouts, colors, and fonts, but also try to change the copy—like using different tones, adding humor, perhaps some sarcasm—whatever fits you. Try new things, listen to your gut feeling, and then take a deep breath and disregard criticism.

And of course, your website should still be accessible with good performance and everything else. I’m not saying that one is more important that the other (at least it shouldn’t be!), but if you get creative, it would also represent the most important thing: You.

And just a little tip to finish with:

Get excited!

When you love what you do, and are excited to do it, it shows. It will be reflected in the content, and your audience will love it and get excited along with you.


, ,

Jetpack Backup: Roll Back Your WooCommerce Site Without Losing Orders

Here’s a dilemma: what happens if your WooCommerce site has a problem and the quickest and best way to fix it is to roll back to a previous version? The dilemma is, if you roll back the database, you would lose literal customer orders that are stored in the database. That’s not acceptable for an eCommerce store.

Good news: Jetpack Backup won’t do you wrong like that. You can still restore to a prior point, but you won’t lose any customer order or product data.

Do you lose all the orders that came in since that last backup? Nope.

Will the inventory get all screwed up? Nope.

What about the new products that were added after the restore point? Still there.

All that data is treated as immutable. The way that it plays out is that the database is restored to that point (along with everything else) and that all the new product and order data that has changed since then is replayed on top of the database after the restore.

With Jetpack Backup, there’s absolutely no guesswork. Its real-time snapshots feature has a unique feature that protects WooCommerce customer and product data when rolling back things back so you get the best-case scenario: readily available backups that preserves customer orders and product information.

That’s just one of the magical benefits you get from such a deep integration between Jetpack and WooCommerce. There are others, of course! But you can imagine just what a big deal this specific integration for any WooCommerce-powered store.

And, hey, Jetpack Backup is sold à la carte. So, if backups are all you want from Jetpack, then you can get just that and that alone.

The post Jetpack Backup: Roll Back Your WooCommerce Site Without Losing Orders appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , , , , , ,

React Without Build Tools

Jim Nielsen:

I think you’ll find it quite refreshing to use React A) with a JSX-like syntax, and B) without any kind of build tooling.

Refreshing indeed:

It’s not really the React that’s the hard part to pull off without build tools (although I do wonder what we lose from not tree shaking), it’s the JSX. I’m so used to JSX I think it would be hard for me to work on a front-end JavaScript project without it. But I know some people literally prefer a render function instead. If that’s the case, you could use React.createComponent directly and skip the JSX, or in the case of Preact, use h:

I work on a project that uses Mithril for the JavaScript templating which is a bit like that, and it’s not my favorite syntax, but you totally get used to it (and it’s fast):

Direct Link to ArticlePermalink

The post React Without Build Tools appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , ,

How to Create a Shrinking Header on Scroll Without JavaScript

Imagine a header of a website that is nice and thick, with plenty of padding on top and bottom of the content. As you scroll down, it shrinks up on itself, reducing some of that padding, making more screen real estate for other content.

Normally you would have to use some JavaScript to add a shrinking effect like that, but there’s a way to do this using only CSS since the introduction of position: sticky.

Let me just get this out there: I’m generally not a fan of sticky headers. I think they take up too much of the screen’s real estate. Whether or not you should use sticky headers on your own site, however, is a different question. It really depends on your content and whether an ever-present navigation adds value to it. If you do use it, take extra care to avoid inadvertently covering or obscuring content or functionality with the sticky areas — that amounts to data loss.

Either way, here’s how to do it without JavaScript, starting with the markup. Nothing complicated here — a <header> with one descendant <div> which, intern, contains the logo and navigation.

<header class="header-outer">   <div class="header-inner">     <div class="header-logo">...</div>     <nav class="header-navigation">...</nav>   </div> </header>

As far as styling, we’ll declare a height for the parent <header> (120px) and set it up as a flexible container that aligns its descendant in the center. Then, we’ll make it sticky.

.header-outer {   display: flex;   align-items: center;   position: sticky;   height: 120px; }

The inner container contains all the header elements, such as the logo and the navigation. The inner container is in a way the actual header, while the only function of the parent <header> element is to make the header taller so there’s something to shrink from.

We’ll give that inner container, .header-inner, a height of 70px and make it sticky as well.

.header-inner {   height: 70px;   position: sticky;   top: 0;  }

That top: 0? It’s there to make sure that the container mounts itself at the very top when it becomes sticky.

Now for the trick! For the inner container to actually stick to the “ceiling” of the page we need to give the parent <header> a negative top value equal to the height difference between the two containers, making it stick “above” the viewport. That’s 70px minus 120px, leaving with with — drumroll, please — -50px. Let’s add that.

.header-outer {   display: flex;   align-items: center;   position: sticky;   top: -50px; /* Equal to the height difference between header-outer and header-inner */   height: 120px; }

Let’s bring it all together now. The <header> slides out of frame, while the inner container places itself neatly at the top of the viewport.

We can extend this to other elements! How about a persistent alert?

While it’s pretty awesome we can do this in CSS, it does have limitations. For example, the inner and outer containers use fixed heights. This makes them vulnerable to change, like if the navigation elements wrap because the number of menu items exceeds the amount of space.

Another limitation? The logo can’t shrink. This is perhaps the biggest drawback, since logos are often the biggest culprit of eating up space. Perhaps one day we’ll be able to apply styles based on the stickiness of an element…

The post How to Create a Shrinking Header on Scroll Without JavaScript appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , , ,

Creating CSS APIs without JavaScript With the datasette-css-properties plugin

Simon Willison has a project called Datasette, an open source multi-tool for exploring and publishing data. I’m not sure I’m qualified to explain it, but it’s like a tool to make handling data easier and doing more — through the web — with data you have. Like making that data queryable and giving it an API.

I would think, typically, you’d get the results of an API call against your data in something useful, like JSON. But Simon made a plugin that outputs the results as CSS custom properties instead, and blogged it:

It’s very, very weird—it adds a .css output extension to Datasette which outputs the result of a SQL query using CSS custom property format. This means you can display the results of database queries using pure CSS and HTML, no JavaScript required!

Here’s what I said just recently in “Custom Properties as State”:

This makes me think that a CDN-hosted CSS file like this could have other useful stuff, like today’s date for usage in pseudo content, or other special time-sensitive stuff. Maybe the phase of the moon? Sports scores?! Soup of the day?!

And Simon is like, how about roadside attractions?

My brain automatically worries about the accessibility of that, but… aren’t pseudo-elements fairly and reliably read in screen readers these days? You still can’t select the text though, or find-on-page, which are both usability and accessibility issues, so don’t consider this like a real thing that you really do for production work with unknown users.

His blog post demonstrates a slightly more dynamic example where the time of day outputs a different color. That makes me think of @property and declaring types for custom properties. I think this gets a smidge more useful when you can use the values that come back as specific syntaxes.

The post Creating CSS APIs without JavaScript With the datasette-css-properties plugin appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , , ,

Bold on Hover… Without the Layout Shift

When you change the font-weight of a font, the text will typically cause a bit of a layout shift. That’s because bold text is often larger and takes up more space. Sometimes that doesn’t matter, like a vertical stack of links where the wider/bolder text doesn’t push anything anyway. Sometimes it does matter, like a horizontal row where the wider/bolder text pushes other elements away a smidge.

Ryan Mulligan demonstrates:

Ryan’s technique is very clever. Each item in the list has a pseudo-element on it with the exact text in the link. That pseudo-element is visually hidden, but pre-bolded and still occupies width. So when the actual link text is bolded, it won’t take up any additional width.

It also sorta depends on how you’re doing the layout. Here, if I force four columns with CSS grid and text that doesn’t really challenge the width, the bolding doesn’t affect the layout either:

But if I were to, say, let those links flow into automatic columns, we would have the shifting problem.

The post Bold on Hover… Without the Layout Shift appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.


, , , ,

Constrained CSS grids without `max-width`

Ain’t nothing wrong with max-width, but Ethan makes a point in the last sentence:

Rather than simply defaulting to max-width as a constraint, I can use the empty space around my design, and treat it as a layout tool.

If the space “around” your grid is actually part of the grid, it’s easier to use. Maybe you’d decide to scootch some author information up there after all, or show an ad, or who knows what. It will be more robust if you do it within the established grid.

Direct Link to ArticlePermalink

The post Constrained CSS grids without `max-width` appeared first on CSS-Tricks.


, , ,

Animating CSS Width and Height Without the Squish Effect

The first rule of animating on the web: don’t animate width and height. It forces the browser to recalculate a bunch of stuff and it’s slow (or “expensive” as they say). If you can get away with it, animating any transform property is faster (and “cheaper”).

Butttt, transform can be tricky. Check out how complex this menu open/close animation becomes in order to make it really performant. Rik Schennink blogs about another tricky situation: border-radius. When you animate the scale of an element in one direction, you get a squishy effect where the corners don’t maintain their nice radius. The solution? 9-slice scaling:

This method allows you to scale the element and stretch image 2, 4, 6, and 8, while linking 1, 3, 7, and 9 to their respective corners using absolute positioning. This results in corners that aren’t stretched when scaled. 

It’s like the 2020 version of sliding doors.

Direct Link to ArticlePermalink

The post Animating CSS Width and Height Without the Squish Effect appeared first on CSS-Tricks.


, , , , ,