> All in One 586

Ads

Monday, February 23, 2026

Loading Smarter: SVG vs. Raster Loaders in Modern Web Design

I got this interesting question in an SVG workshop: “What is the performance difference between an SVG loader and simply rotating an image for a loader?”

The choice between Scalable Vector Graphics (SVG) and raster image loaders involves many factors like performance, aesthetics, and user experience. The short answer to that question is: there’s almost no difference at all if you are working on something very small and specific. But let’s get more nuanced in this article and discuss the capabilities of both formats so that you can make informed decisions in your own work.

Understanding the formats

SVGs are vector-based graphics, popular for their scalability and crispness. But let’s start by defining what raster images and vector graphics actually are.

Raster images are based on physical pixels. They contain explicit color information for every single pixel. What happens is that you send the entire pixel-by-pixel information, and the browser paints each pixel one by one, making the network work harder.

This means:

  • they have a fixed resolution (scaling can introduce blurriness),
  • the browser must decode and paint each frame, and
  • animation usually means frame-by-frame playback, like GIFs or video loops.

Vectors are mathematical instructions that tell the computer how to draw a graphic. As Chris Coyier said in this CSS Conf: “Why send pixels when you can send math?” So, instead of sending the pixels with all the information, SVG sends instructions for how to draw the thing. In other words, let the browser do more and the network do less.

Because of this, SVGs:

  • scale infinitely without losing quality,
  • can be styled and manipulated with CSS and JavaScript, and
  • can live directly in the DOM, eliminating that extra HTTP request.
Comparing two circular shapes, in SVG on the left, and raster on the right. The vector is clear and sharp while the raster is pixelated and does not support transparency.

The power of vectors: Why SVG wins

There are several reasons why it’s generally a good idea to go with SVG over raster images.

1. Transparency and visual quality

Most modern image formats support transparency, but not all transparency is equal. GIFs, for example, only support binary transparency , which means  pixels are either fully transparent or fully opaque.

This often results in jagged edges at larger scales, especially around curves or on opaque or transparent backgrounds. SVGs support true transparency and smooth edges, which makes a noticeable difference for loaders that sit on top of complex UI layers.

JPG GIF PNG SVG
Vector
Raster
Transparency
Animation
Compression Lossy Lossless Lossless Lossless

2. “Zero request” performance

From a raw performance perspective, rotating a small PNG and an SVG in CSS (or JavaScript for that matter) is similar. SVGs, however, win in practice because they are gzip-friendly and can be embedded inline.

<!-- Inline SVG: Heart -->
<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
  <title xmlns="">Heart</title>
  <path fill="currentColor" d="M8.4 5.25c-2.78 0-5.15 2.08-5.15 4.78c0 1.863.872 3.431 2.028 4.73c1.153 1.295 2.64 2.382 3.983 3.292l2.319 1.57a.75.75 0 0 0 .84 0l2.319-1.57c1.344-.91 2.83-1.997 3.982-3.292c1.157-1.299 2.029-2.867 2.029-4.73c0-2.7-2.37-4.78-5.15-4.78c-1.434 0-2.695.672-3.6 1.542c-.905-.87-2.167-1.542-3.6-1.542"/>
</svg>

<!-- Raster image -->
<img src="/img/heart.png" alt="Solid black heart">

By pasting the SVG code directly into your HTML, you eliminate an entire HTTP request. For something like a loader — a thing that’s supposed to show up while other things are loading — the fact that SVG code is already there and renders instantly is a huge win for performance.

More importantly, loaders affect perceived performance. A loader that adapts smoothly to its context and scales correctly can make wait times feel shorter, even if the actual load time is the same.

And even though the SVG code looks like it would be heavier than a single line of HTML, it’s the image’s file size that truly matters. And the fact that we’re measuring SVG in bytes that can be gzipped means it’s a lot less overhead in the end.

All that being said, it is still possible to import an SVG in an <img> just like a raster file (among a few other ways as well):

<img src="/img/heart.svg" alt="Solid black heart">

And, yes, that does count as a network request even though it respects the vector-ness of the file when it comes to crisp edges at any scale. That, and it eliminates other benefits, like the very next one.

3. Animation, control, and interactivity

Loaders formatted in SVG are DOM-based, not frame-based. That means you can:

You can manipulate your SVGs with CSS, JavaScript, or SMIL, creating a whole world of possibilities when it comes to interactivity that raster images are incapable of matching.

4. But do I need separate files for an animated SVG?

Again, SVG animations can live inline in the HTML or inside a single .svg file. This means you can ship one animated file, much like a GIF, but with far more control. By using <defs> and <use>, you can keep the code clean. Here is an example of an SMIL loader file:

<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100" overflow="visible" fill="#ff5463" stroke="none" role="img" aria-labelledby="loader-title">
  <title id="loader-title">Loading...</title>
  <defs>
    <circle id="loader" r="4" cx="50" cy="50" transform="translate(0 -30)"/>
  </defs>
  <use xlink:href="#loader" transform="rotate(45 50 50)">
    <animate attributeName="opacity" values="0;1;0" dur="1s" begin="0.13s" repeatCount="indefinite"></animate>
  </use>
  <use xlink:href="#loader" transform="rotate(90 50 50)">
    <animate attributeName="opacity" values="0;1;0" dur="1s" begin="0.25s" repeatCount="indefinite"></animate>
  </use>
</svg>

For more complex interactions, you can even include CSS and JavaScript inside your SVG file:

<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
<title id="titleId">Interactive Loading Spinner</title> <desc id="descId">A blue rotating circle. Clicking it toggles the rotation speed between fast and slow.</desc>
  <defs>
    <style>
      .loader {
        transform-origin: center;
        animation: spin 1s linear infinite;
        cursor: pointer;
      }
      @keyframes spin {
        to { transform: rotate(360deg); }
      }
    </style>
  </defs>
  
  <circle class="loader" id="loader" cx="50" cy="50" r="35" 
          fill="none" stroke="#3b82f6" stroke-width="6" 
          stroke-dasharray="150" stroke-dashoffset="50" 
          stroke-linecap="round" />
  
  <script type="text/javascript">
    const loader = document.getElementById('loader');
    loader.addEventListener('click', function() {
      this.style.animationDuration = this.style.animationDuration === '0.3s' ? '1s' : '0.3s';
    });
  </script>
</svg>

By embedding styles and scripts, you are essentially creating a standalone mini-application inside a single graphic. The primary advantage is encapsulation: the loader is completely portable, requires fewer HTTP requests, and its styles won’t “bleed” into your website. It’s the ultimate “drop-in” asset for different projects.

However, this power comes with a trade-off in functionality and security. Browsers treat SVGs as static images when loaded via <img> tags or CSS backgrounds, which disables all JavaScript for safety. To keep the interactivity alive, you must either inline the code directly or load the file using an <object> tag. Because of these limitations, the inline method (pasting the code directly into your HTML) remains the preferred choice for most modern web applications.

5. Creativity, brand, and user experience

This is where we move beyond performance and into storytelling.

Imagine a B2B site where a user creates an online store. It takes a few seconds to generate. Instead of a generic spinner, you could show an animation of products “arriving” at the store. You can even make this loader interactive.

An SVG animation like this can be less than 20kb. To do the same thing with a raster GIF, we would be talking about megabytes. SVG’s efficiency allows you to expand your brand voice and engage users during wait times without killing your performance.

When raster loaders still make sense

Raster loaders aren’t “wrong”  per se; they’re just limited in what they can do, especially when compared to SVG. That said, raster images do still make sense when:

  • the loader is photographic or uses complex, illustration-heavy textures,
  • you’re working within legacy systems that don’t allow SVG injection, or
  • you need a very quick, one-off drop-in asset with zero customization needed.

Summary

Feature Raster (GIF/PNG) SVG
Visual quality Might be blurry on retina screens Crisp and sharp at any scale
File size Typically larger (KB/MB) Very small (bytes)
Customization Requires re-exporting Modify directly with CSS/JavaScript
Network requests Typically one HTTP request Zero if inlined directly into HTML

Final thoughts

If you’re displaying a loading indicator that’s as simple as a rotating tiny dot, the performance difference between SVG and raster might be negligible. But once you consider scalability, transparency, accessibility, and the ability to tell a brand story, SVG loaders become about more than just performance ;  they’re about building loaders that actually belong to the modern web.

If you want to experiment with this, I invite you to try loaders.holasvg.com. It’s a free open-source generator I built that lets you customize parameters like animation, shape, and color, and then gives you the clean SVG code to use.


Loading Smarter: SVG vs. Raster Loaders in Modern Web Design originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



from CSS-Tricks https://ift.tt/upP2WUn
via IFTTT

Sunday, February 22, 2026

Mostly Clear today!



With a high of F and a low of 15F. Currently, it's 22F and Clear outside.

Current wind speeds: 8 from the Southeast

Pollen: 0

Sunrise: February 22, 2026 at 07:34PM

Sunset: February 23, 2026 at 06:36AM

UV index: 0

Humidity: 68%

via https://ift.tt/lb6udEG

February 23, 2026 at 10:02AM

Saturday, February 21, 2026

Mostly Clear today!



With a high of F and a low of 10F. Currently, it's 22F and Clear outside.

Current wind speeds: 5 from the Northeast

Pollen: 0

Sunrise: February 21, 2026 at 07:35PM

Sunset: February 22, 2026 at 06:35AM

UV index: 0

Humidity: 63%

via https://ift.tt/oL08fet

February 22, 2026 at 10:02AM

Friday, February 20, 2026

Clouds Early/Clearing Late today!



With a high of F and a low of 12F. Currently, it's 18F and Cloudy outside.

Current wind speeds: 9 from the Northeast

Pollen: 0

Sunrise: February 20, 2026 at 07:36PM

Sunset: February 21, 2026 at 06:34AM

UV index: 0

Humidity: 97%

via https://ift.tt/XwnVxJr

February 21, 2026 at 10:02AM

Potentially Coming to a Browser :near() You

Just before we wrapped up 2025, I saw this proposal for :near(), a pseudo-class that would match if the pointer were to go near the element. By how much? Well, that would depend on the value of the <length> argument provided. Thomas Walichiewicz, who proposed :near(), suggests that it works like this:

button:near(3rem) {
  /* Pointer is within 3rem of the button */
}

For those wondering, yes, we can use the Pythagorean theorem to measure the straight-line distance between two elements using JavaScript (“Euclidean distance” is the mathematical term), so I imagine that that’s what would be used behind the scenes here. I have some use cases to share with you, but the demos will only be simulating :near() since it’s obviously not supported in any web browser. Shall we dig in?

Visual effects

Without question, :near() could be used for a near-infinite (sorry) number of visual effects:

div {
  /* Div is wow */

  &:near(3rem) {
    /* Div be wowzer */
  }

  &:near(1rem) {
    /* Div be woahhhh */
  }
}

Dim elements until :near()

To reduce visual clutter, you might want to dim certain components until users are near them. :near() could be more effective than :hover in this scenario because users could have trouble interacting with the components if they have limited visibility, and so being able to trigger them “earlier” could compensate for that to some degree. However, we have to ensure accessible color contrast, so I’m not sure how useful :near() can be in this situation.

button:not(:near(3rem)) {
  opacity: 70%; /* Or...something */
}

Hide elements until :near()

In addition to dimming components, we could also hide components (as long as they’re not important, that is). This, I think, is a better use case for :near(), as we wouldn’t have to worry about color contrast, although it does come with a different accessibility challenge.

So, you know when you hover over an image and a share button appears? Makes sense, right? Because we don’t want the image to be obscured, so it’s hidden initially. It’s not optimal in terms of UX, but it’s nonetheless a pattern that people are familiar with, like on Pinterest for example.

And here’s how :near() can enhance it. People know or suspect that the button’s there, right? Probably in the bottom-right corner? They know roughly where to click, but don’t know exactly where, as they don’t know the size or offset of the button. Well, showing the button when :near() means that they don’t have to hover so accurately to make the button appear. This scenario is pretty similar to the one above, perhaps with different reasons for the reduced visibility.

However, we need this button to be accessible (hoverable, focusable, and find-in-pageable). For that to happen, we can’t use:

  • display: hidden (not hoverable, focusable, or find-in-pageable)
  • visibility: hidden (also not hoverable, focusable, or find-in-page-able)
  • opacity: 0 (there’s no way to show it once it’s been found by find-in-page)

That leaves us with content-visibility: hidden, but the problem with hiding content using content-visibility: hidden (or elements with display: none) is that they literally disappear, and you can’t be near what simply isn’t there. This means that we need to reserve space for it, even if we don’t know how much space.

Now, :near() isn’t supported in any web browser, so in the demo below, I’ve wrapped the button in a container with 3rem of padding, and while that container is being :hovered, the button is shown. This increases the size of the hoverable region (which I’ve made red, so that you can see it) instead of the actual button. It essentially simulates button:near(3rem).

But how do we hide something while reserving the space?

First, we declare contain-intrinsic-size: auto none on the hidden target. This ensures that it remains a specific size even as something changes (in this case, even as its content is hidden). You can specify a <length> for either value, but in this case auto means whatever the rendered size was. none, which is a required fallback value, can also be a <length>, but we don’t need that at all, hence “none.”

The problem is, the rendered size “was” nothing, because the button is content-visibility: hidden, remember? That means we need to render it if only for a single millisecond, and that’s what this animation does:

<div id="image">
  <div id="simulate-near">
    <button hidden="until-found">Share</button>
  </div>
</div>
@keyframes show-content {
  from {
    content-visibility: visible;
  }
}

button {
  /* Hide it by default */
  &:not([hidden="until-found"]) {
    content-visibility: hidden;
  }

  /* But make it visible for 1ms */
  animation: 1ms show-content;

  /* Save the size while visible */
  contain-intrinsic-size: auto none;
}

Note that if the button has the hidden=until-found attribute-value, which is what makes it focusable and find-in-page-able, content-visibility: hidden isn’t declared because hidden=until-found does that automatically. Either way, the animation declares content-visibility: visible for 1ms while contain-intrinsic-size: auto none captures its size and reserves the space, enabling us to hover it even when it’s not visible.

Now that you understand how it works, here’s the full code (again, simulated, because :near() isn’t supported yet):

<div id="image">
  <div id="simulate-near">
    <button hidden="until-found">Share</button>
  </div>
</div>
@keyframes show-content {
  from {
    content-visibility: visible;
  }
}

#simulate-near {
  /* Instead of :near(3rem) */
  padding: 3rem;

  button {
    /* Unset any styles */
    border: unset;
    background: unset;

    /* But include size-related styles */
    padding: 1rem;

    /* Hide it by default */
    &:not([hidden="until-found"]) {
      content-visibility: hidden;
    }

    /* But make it visible for 1ms */
    animation: 1ms show-content;

    /* Save the size while visible */
    contain-intrinsic-size: auto none;
  }

  &:where(:hover, :has(:focus-visible)) button {
    color: white;
    background: black;
    content-visibility: visible;
  }
}

If you’re wondering why we’re unsetting border and background, it’s because content-visibility: hidden only hides the content, not the element itself, but we’ve included padding here because that affects the size that we’re trying to render n’ remember. After that we simply apply those styles as well as content-visibility: visible to the button when the the wrapper is :hovered or :has(:focus-visible).

And here’s the same thing but with the unsupported :near():

<div id="image">
  <button hidden="until-found">Share</button>
</div>
@keyframes show-content {
  from {
    content-visibility: visible;
  }
}

button {
  /* Unset any styles */
  border: unset;
  background: unset;

  /* But include size-related styles */
  padding: 1rem;

  /* Hide it by default */
  &:not([hidden="until-found"]) {
    content-visibility: hidden;
  }

  /* But make it visible for 1ms */
  animation: 1ms show-content;

  /* Save the size while visible */
  contain-intrinsic-size: auto none;

  &:where(:near(3rem), :hover, :focus-visible) {
    color: white;
    background: black;
    content-visibility: visible;
  }
}

In short, :near() enables us to do what the simulated technique does but without the extra markup and creative selectors, and if there are any accessibility needs, we have that animation/contain-intrinsic-size trick.

Prefetch/prerender when near

I’m not suggesting that there’s a way to prefetch/prerender using :near() or even that the functionality of :near() should be extended, but rather that the Speculation Rules API could leverage its underlying functionality. The Speculation Rules API already uses mousedown, touchstart, pointer direction and velocity, viewport presence, and scroll pauses as signals to begin prefetching/prerendering the linked resource, so why not when near?

In fact, I think “near” as a concept could be utilized for a lot more than :near(), and should be considering that custom hit-testing using pointermove has a high performance cost and implementation complexity (as Thomas points out). Let’s look at another example.

Improve interest invoker interactions

When interacting with hover-triggered overlays, there’s risk of accidentally moving the pointer away from the trigger or target. The Interest Invoker API, which facilitates hover-triggered interactions, uses the interest-show-delay and interest-hide-delay CSS properties to prevent accidental activations and deactivations respectively, but from a user experience perspective, anything involving delays and time-sensitivity just isn’t fun.

A couple of examples:

  • The pointer falling into the gap between the interest trigger (e.g., a link or button) and interest target (e.g., a popover)
  • The pointer overshooting the bounds of the interest target when trying to interact with elements near the edge of it

Therefore, instead of (or in addition to) show and hide delays, the Interest Invoker API could leverage the concept of “near” to ensure that overlays don’t disappear due to mis-interaction. This could be configurable with a CSS property (e.g., near-radius: 3rem or just near: 3rem), which unlike :near() would invoke functionality (interest and loseinterest JavaScript events, in this case).

Another use-case, suggested by Thomas in his proposal: showing a “drag to reorder” hint while hovering near a draggable element. This is a terrific use-case because showing tooltips even just a few milliseconds earlier would likely reduce task time.

Unfortunately, you’d have a hard time (I think?) simulating these ones with valid HTML, mostly because <a>s and <button>s can only contain certain elements.

Downsides to :near()

A potential downside is that :near() could lead to a significant increase in developers lazily hiding things to reduce visual clutter in instances where better UI design would’ve been the right call, or increasing visual clutter (with unnecessary icons, for example) because it can be hidden more conditionally.

Other potential abuses include heatmapping, fingerprinting, and aggressive advertising patterns. It could also be used in ways that would negatively impact performance. Thomas’s proposal does a wonderful job of pointing out these abuses and the ways in which :near() could be implemented to thwart them.

:near() accessibility concerns

:near() shouldn’t imply :hover or :focus/:focus-visible. I think that much is obvious when you really think about it, but I can still see the lines getting crossed. A good question to ask before using :near() is: “Are we being preemptive or presumptive?” Preemptive can be good but presumptive would always be bad, as we never want users to think that they’re hovering or focusing on an interactive element when they’re not (or not yet). This is mentioned in various parts of the Web Content Accessibility Guidelines, but most notably in Success Criterion 2.4.7: Focus Visible (Level AA).

Similarly, Success Criterion 2.5.8: Target Size (Level AA) states that interactive elements smaller than 24x24px must have extra spacing around them, calculated as 24px - target width/24px - target height, but whether or not the value of :near() would factor into that is a bit ambiguous.

In conclusion

There’s lots to think about here, but ultimately I’d love to see this implemented as Thomas has proposed it. Having said that, the WCAG guidance must be rock-solid before any implementation begins, especially considering that we can already accomplish what :near() would do (albeit with more markup and maybe some CSS trickery).

And again, I think we should entertain the idea of “near” as a concept, where the underlying functionality could be leveraged by the Speculation Rules API and Interest Invoker API (the latter with a CSS property like near-radius).

Your thoughts, please!


Potentially Coming to a Browser :near() You originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



from CSS-Tricks https://ift.tt/IA7OgzC
via IFTTT

Thursday, February 19, 2026

Mostly Clear today!



With a high of F and a low of 8F. Currently, it's 15F and Fair outside.

Current wind speeds: 2 from the East

Pollen: 0

Sunrise: February 19, 2026 at 07:38PM

Sunset: February 20, 2026 at 06:32AM

UV index: 0

Humidity: 75%

via https://ift.tt/ckfR9Y2

February 20, 2026 at 10:02AM

Wednesday, February 18, 2026

Partly Cloudy/Wind today!



With a high of F and a low of 19F. Currently, it's 38F and Clear outside.

Current wind speeds: 11 from the Southwest

Pollen: 0

Sunrise: February 18, 2026 at 07:39PM

Sunset: February 19, 2026 at 06:31AM

UV index: 0

Humidity: 41%

via https://ift.tt/kz4MYWb

February 19, 2026 at 10:02AM

Loading Smarter: SVG vs. Raster Loaders in Modern Web Design

I got this interesting question in an SVG workshop: “What is the performance difference between an SVG loader and simply rotating an image f...