> All in One 586: February 2026

Ads

Saturday, February 28, 2026

Mostly Cloudy today!



With a high of F and a low of 28F. Currently, it's 45F and Fair outside.

Current wind speeds: 12 from the Southeast

Pollen: 0

Sunrise: February 28, 2026 at 07:25PM

Sunset: March 1, 2026 at 06:42AM

UV index: 0

Humidity: 33%

via https://ift.tt/rI8WclH

March 1, 2026 at 10:02AM

Friday, February 27, 2026

Clear today!



With a high of F and a low of 32F. Currently, it's 44F and Partly Cloudy outside.

Current wind speeds: 3 from the Southeast

Pollen: 0

Sunrise: February 27, 2026 at 07:27PM

Sunset: February 28, 2026 at 06:41AM

UV index: 0

Humidity: 21%

via https://ift.tt/YyI0nge

February 28, 2026 at 10:02AM

What’s !important #6: :heading, border-shape, Truncating Text From the Middle, and More

Despite what’s been a sleepy couple of weeks for new Web Platform Features, we have an issue of What’s !important that’s prrrretty jam-packed. The web community had a lot to say, it seems, so fasten your seatbelts!

@keyframes animations can be strings

Peter Kröner shared an interesting fact about @keyframes animations — that they can be strings:

@keyframes "@animation" {
  /* ... */
}

#animate-this {
  animation: "@animation";
}

Yo dawg, time for a #CSS fun fact: keyframe names can be strings. Why? Well, in case you want your keyframes to be named “@keyframes,” obviously! #webdev

[image or embed]

— Peter Kröner (@sirpepe.bsky.social) Feb 18, 2026 at 10:33

I don’t know why you’d want to do that, but it’s certainly an interesting thing to learn about @keyframes after 11 years of cross-browser support!

: vs. = in style queries

Another hidden trick, this one from Temani Afif, has revealed that we can replace the colon in a style query with an equals symbol. Temani does a great job at explaining the difference, but here’s a quick code snippet to sum it up:

.Jay-Z {
  --Problems: calc(98 + 1);

  /* Evaluates as calc(98 + 1), color is blueivy */
  color: if(style(--Problems: 99): red; else: blueivy);

  /* Evaluates as 99, color is red */
  color: if(style(--Problems = 99): red; else: blueivy);
}

In short, = evaluates --Problems differently to :, even though Jay-Z undoubtably has 99 of them (he said so himself).

Declarative <dialog>s (and an updated .visually-hidden)

David Bushell demonstrated how to create <dialog>s declaratively using invoker commands, a useful feature that allows us to skip some J’Script in favor of HTML, and works in all web browsers as of recently.

Also, thanks to an inquisitive question from Ana Tudor, the article spawned a spin-off about the minimum number of styles needed for a visually-hidden utility class. Is it still seven?

Maybe not…

How to truncate text from the middle

Wes Bos shared a clever trick for truncating text from the middle using only CSS:

Someone on reddit posted a demo where CSS truncates text from the middle. They didn't post the code, so here is my shot at it with Flexbox

[image or embed]

— Wes Bos (@wesbos.com) Feb 9, 2026 at 17:31

Donnie D’Amato attempted a more-native solution using ::highlight(), but ::highlight() has some limitations, unfortunately. As Henry Wilkinson mentioned, Hazel Bachrach’s 2019 call for a native solution is still an open ticket, so fingers crossed!

How to manage color variables with relative color syntax

Theo Soti demonstrated how to manage color variables with relative color syntax. While not a new feature or concept, it’s frankly the best and most comprehensive walkthrough I’ve ever read that addresses these complexities.

How to customize lists (the modern way)

In a similar article for Piccalilli, Richard Rutter comprehensively showed us how to customize lists, although this one has some nuggets of what I can only assume is modern CSS. What’s symbols()? What’s @counter-style and extends? Richard walks you through everything.

A table with headings titled CSS and USE CASE detailing HTML list customizations. It lists the property list-style for basic bullet styles; the pseudo-element li::marker for coloring numbering; the function symbols() for Firefox-specific styles; the at-rule @counter-style for custom numbering systems; the descriptor extends for modifying existing systems; and the pseudo-element li::before for advanced marker positioning.
Source: Piccalilli.

Can’t get enough on counters? Juan Diego put together a comprehensive guide right here on CSS-Tricks.

How to create typescales using :heading

Safari Technology Preview 237 recently began trialing :heading/:heading(), as Stuart Robson explains. The follow-up is even better though, as it shows us how pow() can be used to write cleaner typescale logic, although I ultimately settled on the old-school <h1><h6> elements with a simpler implementation of :heading and no sibling-index():

:root {
  --font-size-base: 16px;
  --font-size-scale: 1.5;
}

:heading {
  /* Other heading styles */
}

/* Assuming only base/h3/h2/h1 */

body {
  font-size: var(--font-size-base);
}

h3 {
  font-size: calc(var(--font-size-base) * var(--font-size-scale));
}

h2 {
  font-size: calc(var(--font-size-base) * pow(var(--font-size-scale), 2));
}

h1 {
  font-size: calc(var(--font-size-base) * pow(var(--font-size-scale), 3));
}

Una Kravets introduced border-shape

Speaking of new features, border-shape came as a surprise to me considering that we already have — or will have — corner-shape. However, border-shape is different, as Una explains. It addresses the issues with borders (because it is the border), allows for more shapes and even the shape() function, and overall it works differently behind the scenes.

Source: Una Kravets.

modern.css wants you to stop writing CSS like it’s 2015

It’s time to start using all of that modern CSS, and that’s exactly what modern.css wants to help you do. All of those awesome features that weren’t supported when you first read about them, that you forgot about? Or the ones that you missed or skipped completely? Well, modern.css has 75 code snippets and counting, and all you have to do is copy ‘em.

Screenshot of a website titled modern.css showing browser compatibility filters and six code snippets, labeled with their category (e.g., SELECTORS or LAYOUT), difficulty level, topic, an example of outdated code to avoid, a browser support percentage, and a link to view the modern solution.

Kevin Powell also has some CSS snippets for you

And the commenters? They have some too!

Honestly, Kevin is the only web dev talker that I actually follow on YouTube, and he’s so close to a million followers right now, so make sure to hit ‘ol K-Po’s “Subscribe” button.

In case you missed it

Actually, you didn’t miss that much! Firefox 148 released the shape() function, which was being held captive by a flag, but is now a baseline feature. Safari Technology Preview 237 became the first to trial :heading. Those are all we’ve seen from our beloved browsers in the last couple of weeks (not counting the usual flurry of smaller updates, of course).

That being said, Chrome, Safari, and Firefox announced their targets for Interop 2026, revealing which Web Platform Features they intend to make consistent across all web browsers this year, which more than makes up for the lack of shiny features this week.

Also coming up (but testable in Chrome Canary now, just like border-shape) is the scrolled keyword for scroll-state container queries. Bramus talks about scrolled scroll-state queries here.

Remember, if you don’t want to miss anything, you can catch these Quick Hits as the news breaks in the sidebar of css-tricks.com.

See you in a fortnight!


What’s !important #6: :heading, border-shape, Truncating Text From the Middle, and More originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Yet Another Way to Center an (Absolute) Element

TL;DR: We can center absolute-positioned elements in three lines of CSS. And it works on all browsers!

.element {
  position: absolute;
  place-self: center; 
  inset: 0;
}

Why? Well, that needs a longer answer.

In recent years, CSS has brought a lot of new features that don’t necessarily allow us to do new stuff, but certainly make them easier and simpler. For example, we don’t have to hardcode indexes anymore:

<ul style="--t: 8">
  <li style="--i: 1"></li>
  <li style="--i: 2"></li>
  <!--  ...  -->
  <li style="--i: 8"></li>
</ul>

Instead, all this is condensed into the sibling-index() and sibling-count() functions. There are lots of recent examples like this.

Still, there is one little task that feels like we’ve doing the same for decades: centering an absolutely positioned element, which we usually achieve like this:

.element {
  position: absolute;
  top: 50%;
  left: 50%;
  
  translate: -50% -50%;
}

We move the element’s top-left corner to the center, then translate it back by 50% so it’s centered.

There is nothing wrong with this way — we’ve been doing it for decades. But still it feels like the old way. Is it the only way? Well, there is another not-so-known cross-browser way to not only center, but also easily place any absolutely-positioned element. And what’s best, it reuses the familiar align-self and justify-self properties.

Turns out that these properties (along with their place-self shorthand) now work on absolutely-positioned elements. However, if we try to use them as is, we’ll notice our element doesn’t even flinch.

/* Doesn't work!! */
.element {
  position: absolute;
  place-self: center; 
}

So, how do align-self and justify-self work for absolute elements? It may be obvious to say they should align the element, and that’s true, but specifically, they align it within its Inset-Modified Containing Block (IMCB). Okay… But what’s the IMCB?

Imagine we set our absolute element width and height to 100%. Even if the element’s position is absolute, it certainly doesn’t grow infinitely, but rather it’s enclosed by what’s known as the containing block.

The containing block is the closest ancestor with a new stacking context. By default, it is the html element.

We can modify that containing block using inset properties (specifically top, right, bottom, and left). I used to think that inset properties fixed the element’s corners (I even said it a couple of seconds ago), but under the hood, we are actually fixing the IMCB borders.

Diagram showing the CSS for an absolutely-positioning element with inset properties and how those values map to an element.

By default, the IMCB is the same size as the element’s dimensions. So before, align-self and justify-self were trying to center the element within itself, resulting in nothing. Then, our last step is to set the IMCB so that it is the same as the containing block.

.element {
  position: absolute;
  place-self: center; 
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

Or, using their inset shorthand:

.element {
  position: absolute;
  place-self: center; 
  inset: 0;
}

Only three lines! A win for CSS nerds. Admittedly, I might be cheating since, in the old way, we could also use the inset property and reduce it to three lines, but… let’s ignore that fact for now.

We aren’t limited to just centering elements, since all the other align-self and justify-self positions work just fine. This offers a more idiomatic way to position absolute elements.

Pro tip: If we want to leave a space between the absolutely-positioned element and its containing block, we could either add a margin to the element or set the container’s inset to the desired spacing.

What’s best, I checked Caniuse, and while initially Safari didn’t seem to support it, upon testing, it seems to work on all browsers!


Yet Another Way to Center an (Absolute) Element originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Thursday, February 26, 2026

Clear today!



With a high of F and a low of 30F. Currently, it's 39F and Clear outside.

Current wind speeds: 3 from the West

Pollen: 0

Sunrise: February 26, 2026 at 07:28PM

Sunset: February 27, 2026 at 06:40AM

UV index: 0

Humidity: 27%

via https://ift.tt/4khcW86

February 27, 2026 at 10:02AM

Wednesday, February 25, 2026

Light Rain/Wind Early today!



With a high of F and a low of 30F. Currently, it's 38F and Showers in the Vicinity outside.

Current wind speeds: 12 from the North

Pollen: 0

Sunrise: February 25, 2026 at 07:30PM

Sunset: February 26, 2026 at 06:39AM

UV index: 0

Humidity: 71%

via https://ift.tt/cEWauIs

February 26, 2026 at 10:02AM

An Exploit … in CSS?!

Ok, take a deep breath.

We’ll have some fun understanding this vulnerability once you make sure your browser isn’t affected, using the table below.

Chromium-based browser Am I safe?
Google Chrome Ensure you’re running version 145.7632.75 or later. Go to Settings > About Chrome and check for updates.
Microsoft Edge Ensure you’re running on version 145.0.3800.58 or later. Click on the three dots (…) on the very right-hand side of the window. Click on Help and Feedback > About Microsoft Edge.
Vivaldi Ensure you’re running on version 7.8 or later. Click the V icon (menu) in the top-left corner, select Help > About.
Brave Ensure you’re running on version v1.87.188 or later. Click the hamburger menu on the top right, select Help > About Brave.

So, you updated your browser and said a prayer. When you’re able to string whole sentences together again, your first question is: Has CSS really had the dubious honor of being the cause of the first zero-day exploit in Chromium-based browsers for 2026?

I mean, the Chrome update channel says they fixed a high-severity vulnerability described as “[u]ser after free in CSS” … on Friday the 13th no less! If you can’t trust a release with a description and date like that, what can you trust? Google credits security researcher Shaheen Fazim with reporting the exploit to Google. The dude’s LinkedIn says he’s a professional bug hunter, and I’d say he deserves the highest possible bug bounty for finding something that a government agency is saying “in CSS in Google Chrome before 145.0.7632.75 allowed a remote attacker to execute arbitrary code inside a sandbox via a crafted HTML page.”

Is this really a CSS exploit?

Something doesn’t add up. Even this security researcher swears by using CSS instead of JavaScript, so her security-minded readers don’t need to enable JavaScript when they read her blog. She trusts the security of CSS, even though she understands it enough to create a pure CSS x86 emulator (sidenote: woah). So far, most of us have taken for granted that the possible security issues in CSS are relatively tame. Surely we don’t suddenly live in a world where CSS can hijack someone’s OS, right?

Well, in my opinion, the headlines describing the bug as a CSS exploit in Chrome are a bit clickbait-y, because they make it sound like a pure CSS exploit, as though malicious CSS and HTML would be enough to perform it. If I’m being honest, when I first skimmed those articles in the morning before rushing out to catch the train to work, the way the articles were worded made me imagine malicious CSS like:

.malicious-class {
  vulnerable-property: 'rm -rf *';
}

In the fictional, nightmare version of the bug that my malinformed imagination had conjured, some such CSS could be “crafted” to inject that shell command somewhere it would run on the victim’s machine. Even re-reading the reports more carefully, they feel intentionally misleading, and it wasn’t just me. My security-minded friend’s first question to me was, “But… isn’t CSS, like, super validatable?” And then I dug deeper and found out the CSS in the proof of concept for the exploit isn’t the malicious bit, which is why CSS validation wouldn’t have helped!

It doesn’t help the misunderstanding when the SitePoint article about CVE-2026-2441 bizarrely lies to its readers about what this exploit is, instead describing a different medium-severity bug that allows sending the rendered value of an input field to a malicious server by loading images in CSS. That is not what this vulnerability is.

It’s not really a CSS exploit in the sense that JavaScript is the part that exploits the bug. I’ll concede that the line of code that creates the condition necessary for a malicious script to perform this attack was in Google Chrome’s Blink CSS engine component, but the CSS involved isn’t the malicious part.

So, how did the exploit work?

The CSS involvement in the exploit lies in the way Chrome’s rendering engine turns certain CSS into a CSS object model. Consider the CSS below:

@font-feature-values VulnTestFont {
  @styleset {
    entry_a: 1;
    entry_b: 2;
    entry_c: 3;
    entry_d: 4;
    entry_e: 5;
    entry_f: 6;
    entry_g: 7;
    entry_h: 8;
  }
}

When this CSS is parsed, a CSSFontFeaturesValueMap is added to the collection of CSSRule objects in the document.styleSheets[0].cssRules. There was a bug in the way Chrome managed the memory for the HashMap data structure underlying the JavaScript representation of the CSSFontFeaturesValueMap, which inadvertently allowed a malicious script to access memory it shouldn’t be able to. This by itself isn’t sufficient to cause harm other than crashing the browser, but it can form the basis for a Use After Free (UAF) exploit.

Chrome’s description of the patch mentions that “Google is aware that an exploit for CVE-2026-2441 exists in the wild,” although for obvious reasons, they are coy about the details for a full end-to-end exploit. Worryingly, @font-feature-values isn’t new — it’s been available since early 2023 — but the discovery of an end-to-end UAF exploit may be recent. It would make sense if the code that created the possibility of this exploit is old, but someone only pulled off a working exploit recently. If you look at this detailed explanation of a 2020 Use After Free vulnerability in Chrome within the WebAudio API, you get the sense that accessing freed memory is only one piece of the puzzle to get a UAF exploit working. Modern operating systems create hoops that attackers have to go through, which can make this kind of attack quite hard.

Real-world examples of this kind of vulnerability get complex, especially in a Chrome vulnerability where you can only trigger low-level statements indirectly. But if you know C and want to understand the basic principles with a simplified example, you can try this coding challenge. Another way to help understand the ideas is this medium post about the recent Chrome CSSFontFeaturesValueMap exploit, which includes a cute analogy in which the pointer to the object is like a leash you are still holding even after you freed your dog — but an attacker hooks the leash to a cat instead (known as type confusion), so when you command your “dog” to bark, the attacker taught his cat to think that “bark” command means to do something malicious instead.

The world is safe again, but for how long?

The one-line fix I mentioned Chrome made was to change the Blink code to work with a deep copy of the HashMap that underlies the CSSFontFeaturesValueMap rather than a pointer to it, so there is no possibility of referencing freed memory. By contrast, it seems Firefox rewrote its CSS renderer in Rust and therefore tends to handle memory management automatically. Chromium started to support the use of Rust since 2023. One of the motivations mentioned was “safer (less complex C++ overall, no memory safety bugs in a sandbox either)” and to “improve the security (increasing the number of lines of code without memory safety bugs, decreasing the bug density of code) of Chrome.” Since it seems the UAF class of exploit has recurred in Chromium over the years, and these vulnerabilities tend to be high-severity when discovered, a more holistic approach to defending against such vulnerabilities might be needed, so I don’t have to freak you out with another article like this.


An Exploit … in CSS?! originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

A Complete Guide to Bookmarklets

You’re surely no stranger to bookmarks. The ability to favorite, save, or “bookmark” web pages has been a staple browser feature for decades. Browsers don’t just let you bookmark web pages, though. You can also bookmark JavaScript, allowing you to do so much more than merely save pages.

A JavaScript script saved as a bookmark is called a “bookmarklet,” although some people also use the term “favelet” or “favlet.” Bookmarklets have been around since the late 90s. The site that coined them, bookmarklets.com, even remains around today. They’re simple and versatile, a fact evidenced by most of the bookmarklets listed on the aforementioned site are still working today despite being untouched for over two decades.

While bookmarklets have fallen a bit to the wayside in more recent years as browsers have grown more capable and dev tools have matured, they’re still a valuable tool in any web developer’s arsenal. They’re simple but capable, and no additional software is needed to create or use them. If you watch any good machinist or engineer at work, they’re constantly building tools and utilities, even one-off contraptions, to address problems or come to a more graceful solution as they work. As developers, we should endeavor to do the same, and bookmarklets are a perfect way to facilitate such a thing.

Making a Bookmarklet

Bookmarklets are extremely easy to make. You write a script in exactly the same manner you would if writing it for the browser console. You then save it as a bookmark, prefixing it with javascript: which designates it for use in the browser URL bar.

Let’s work through making a super basic bookmarklet, one that sends a simple alert. We’ll take the below code, which triggers a message using the alert() method, and bookmarklet-ify it.

alert("Hello, World!");

Next, we will turn it into an Immediately Invoked Function Expression (IIFE), which has a few benefits. Firstly, it creates a new scope to avoid polluting the global namespace and prevents our bookmarklet from interfering with JavaScript already on the page, or vice versa. Secondly, it will cause the bookmarklet to trigger upon click.

We’ll achieve this by enclosing it within an anonymous function (lambda) (e.g., (() => {})) and suffixing it with ();, which will execute our function.

(() => {
  alert("Hello, World!");
})();

For reliability across browsers, it is to our benefit to URL-encode our bookmarklet to escape special characters. Without doing so, browsers can go awry and misinterpret our code. Even if it isn’t entirely necessary with a simple bookmarklet like this, it can prevent a lot of trouble that may arise with more complexity. You can encode your bookmarklet yourself using JavaScript’s encodeURIComponent() function, or you can use one of a number of existing tools. We’ll also reduce it to a single line.

(()%3D%3E%7Balert(%22Hello%2C%20World!%22)%3B%7D)()%3B

We must prefix javascript: so that our browser knows this is not a standard URL to a webpage but instead a JavaScript bookmarklet.

javascript:(()%3D%3E%7Balert(%22Hello%2C%20World!%22)%3B%7D)()%3B

Installing a Bookmarklet

Finally, we must add it to our browser as a bookmarklet. As you might expect, this is extremely dependent on the browser you’re using.

In Safari on macOS, the easiest way is to bookmark a webpage and then edit that bookmark into a bookmarklet:

Safari window with the Favorites tab opened and a context menu open for an item highlighting the Edit Address option.

In Firefox on desktop, the easiest way is to secondary click on the bookmark toolbar and then “Add Bookmark…”:

Firefox window showing the Add Bookmark option.

In Chrome on desktop, the easiest way is to secondary click on the bookmark toolbar and then “Add page…”:

Chrome window showing the Add page option.

Many mobile browsers also allow the creation and usage of bookmarks. This can be especially valuable, as browser dev tools are often unavailable on mobile.

CSS Bookmarklets

You’ve no doubt been looking at the word “JavaScript” above with a look of disdain. This is CSS-Tricks after all. Fear not, because we can make bookmarklets that apply CSS to our page in a plethora of ways.

My personal favorite method from an authoring perspective is to create a <style> element with my chosen content:

javascript: (() => {
  var style = document.createElement("style");
  style.innerHTML = "body{background:#000;color:rebeccapurple}";
  document.head.appendChild(style);
})();

The much more graceful approach is to use the CSSStyleSheet interface. This approach allows for incremental updates and lets you directly access the CSS Object Model (CSSOM) to read selectors, modify existing properties, remove or reorder rules, and inspect computed structure. The browser also validates values input this way, which helps prevent you from inputting broken CSS. It is more complex but also gives you greater control.

javascript: (() => {
  const sheet = new CSSStyleSheet();
  document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
  sheet.insertRule("body { border: 5px solid rebeccapurple !important; }", 0);
  sheet.insertRule("img { filter: contrast(10); }", 1);
})();

As we’re writing CSS for general usage across whatever page we wish to use our bookmarklet on, it is important to remain aware that we may run into issues with specificity or conflicts with the page’s existing stylesheets. Using !important is usually considered a bad code smell, but in the context of overriding unknown existing styles, it is a reasonable way to address our needs.

Limitations

Unfortunately, there are a few roadblocks that can hinder our usage of bookmarklets. The most pervasive are Content Security Policies (CSP). A CSP is a security feature that attempts to prevent malicious actions, such as cross-site scripting attacks, by allowing websites to regulate what can be loaded. You wouldn’t want to allow scripts to run on your bank’s website, for instance. A bookmarklet that relies on cross-origin requests (requests from outside the current website) is very frequently blocked. For this reason, a bookmarklet should ideally be self-contained, rather than reliant on anything external. If you’re suspicious a bookmarklet is being blocked by a website’s security policies, you can check the console in your browser’s developer tools for an error.

Firefox blocking a bookmarklet from running due to inline scripts being disallowed.

As bookmarklets are just URLs, there isn’t any strict limit to the length specified. In usage, browsers do impose limits, though they’re higher than you’ll encounter in most cases. In my own testing (which may vary by version and platform), here are the upper limits I found: The largest bookmarklet I could create in both Firefox and Safari was 65536 bytes. Firefox wouldn’t let me create a bookmarklet of any greater length, and Safari would let me create a bookmarklet, but it would do nothing when triggered. The largest bookmarklet I could create in Chrome was 9999999 characters long, and I started having issues interacting with the textbox after that point. If you need something longer, you might consider loading a script from an external location, keeping in mind the aforementioned CSP limitations:

javascript:(() => {
  var script=document.createElement('script');
  script.src='https://example.com/bookmarklet-script.js';
  document.body.appendChild(script);
})();

Otherwise, you might consider a userscript tool like TamperMonkey, or, for something more advanced, creating your own browser extension. Another option is creating a snippet in your browser developer tools. Bookmarklets are best for small snippets.

Cool Bookmarklets

Now that you’ve got a gauge on what bookmarklets are and, to an extent, what they’re capable of, we can take a look at some useful ones. However, before we do, I wish to stress that you should be careful running bookmarklets you find online. Bookmarklets you find online are code written by someone else. As always, you should be wary, cautious, and discerning. People can and have written malicious bookmarklets that steal account credentials or worse.

For this reason, if you paste code starting with javascript: into the address bar, browsers automatically strip the javascript: prefix to prevent people from unwittingly triggering bookmarklets. You’ll need to reintroduce the prefix. To get around the javascript: stripping, bookmarklets are often distributed as links on a page, which you’re expected to drag and drop into your bookmarks.

Specific bookmarklets have been talked about on CSS-Tricks before. Given the evolution of browsers and the web platform, much has been obsoleted now, but some more contemporary articles include:

Be sure to check out the comments of those posts, for they’re packed with countless great bookmarklets from the community. Speaking of bookmarklets from the community:

If you’ve got any golden bookmarklets that you find valuable, be sure to share them in the comments.


A Complete Guide to Bookmarklets originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Tuesday, February 24, 2026

Partly Cloudy today!



With a high of F and a low of 37F. Currently, it's 47F and Partly Cloudy outside.

Current wind speeds: 4 from the Northeast

Pollen: 0

Sunrise: February 24, 2026 at 07:31PM

Sunset: February 25, 2026 at 06:38AM

UV index: 0

Humidity: 32%

via https://ift.tt/FLS37qN

February 25, 2026 at 10:02AM

Monday, February 23, 2026

Partly Cloudy today!



With a high of F and a low of 34F. Currently, it's 39F and Clear outside.

Current wind speeds: 10 from the Southwest

Pollen: 0

Sunrise: February 23, 2026 at 07:32PM

Sunset: February 24, 2026 at 06:37AM

UV index: 0

Humidity: 35%

via https://ift.tt/gFpS0ri

February 24, 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 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

Distinguishing “Components” and “Utilities” in Tailwind

Here’s a really quick tip. You can think of Tailwind utilities as components — because you can literally make a card “component” out of Tailwind utilities.

@utility card {
  border: 1px solid black;
  padding: 1rlh;
}
<div class="card"> ... </div>
A plain white rectangular box with a black border.

This blurs the line between “Components” and “Utilities” so we need to better define those terms.

The Great Divide — and The Great Unification

CSS developers often define Components and Utilities like this:

  1. Component = A group of styles
  2. Utility = A single rule

This collective thinking has emerged from the terminologies we have gathered over many years. Unfortunately, they’re not really the right terminologies.

So, let’s take a step back and consider the actual meaning behind these words.

Component means: A thing that’s a part of a larger whole.

1640s, "constituent part or element" (earlier "one of a group of persons," 1560s), from Latin componentem (nominative componens), present participle of componere to put together, to collect a whole from several parts, from com with, together (see com-) + ponere to place (see position (n.)). Related: Componential. Meaning mechanical part of a bicycle, automobile, etc. is from 1896. As an adjective, constituent, entering into the composition of, from 1660s.

Utility means: It’s useful.

late 14th century., utilite, 'fact or character of being useful,' from Old French utilite 'usefulness' (13th century, Modern French utilite), earlier utilitet (12th century.), from Latin utilitatem (nominative utilitas) 'usefulness, serviceableness, profit,' from utilis 'usable,' from uti 'make use of, profit by, take advantage of.'

So…

  • Utilities are Components because they’re still part of a larger whole.
  • Components are Utilities because they’re useful.

The division between Components and Utilities is really more of a marketing effort designed to sell those utility frameworks — nothing more than that.

It. Really. Doesn’t. Matter.

The meaningful divide?

Perhaps the only meaningful divide between Components and Utilities (in the way they’re commonly defined so far) is that we often want to overwrite component styles.

It kinda maps this way:

  • Components: Groups of styles
  • Utilities: Styles used to overwrite component styles.

Personally, I think that’s a very narrow way to define something that actually means “useful.”

Just overwrite the dang style

Tailwind provides us with an incredible feature that allows us to overwrite component styles. To use this feature, you would have to:

  • Write your component styles in a components layer.
  • Overwrite the styles via a Tailwind utility.
@layer components {
  .card {
    border: 1px solid black;
    padding: 1rlh;
  }
}
<div class="card border-blue-500"> ... </div>
A simple rectangular box with a blue border.

But this is a tedious way of doing things. Imagine writing @layer components in all of your component files. There are two problems with that:

  1. You lose the ability to use Tailwind utilities as components
  2. You gotta litter your files with many @layer component declarations — which is one extra indentation and makes the whole CSS a little more difficult to read.

There’s a better way of doing this — we can switch up the way we use CSS layers by writing utilities as components.

@utility card {
  padding: 1rlh; 
  border: 1px solid black;
}

Then, we can overwrite styles with another utility using Tailwind’s !important modifier directly in the HTML:

<div class="card !border-blue-500"> ... </div>

I put together an example over at the Tailwind Playground.

Unorthodox Tailwind

This article comes straight from my course, Unorthodox Tailwind, where you’ll learn to use CSS and Tailwind in a synergistic way. If you liked this, there’s a lot more inside: practical ways to think about and use Tailwind + CSS that you won’t find in tutorials or docs.


Distinguishing “Components” and “Utilities” in Tailwind originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Clear today!

With a high of F and a low of 43F. Currently, it's 50F and Clear outside. Current wind speeds: 9 from the West Pollen: 0 Sunrise...