> All in One 586

Ads

Tuesday, April 7, 2026

Alternatives to the !important Keyword

Every now and then, I stumble onto an old project of mine, or worse, someone else’s, and I’m reminded just how chaotic CSS can get over time. In most of these cases, the !important keyword seems to be involved in one way or another. And it’s easy to understand why developers rely on it. It provides an immediate fix and forces a rule to take precedence in the cascade.

That’s not to say !important doesn’t have its place. The problem is that once you start using it, you’re no longer working with the cascade; you’re bypassing it. This can quickly get out of hand in larger projects with multiple people working on them, where each new override makes the next one harder.

Cascade layers, specificity tricks, smarter ordering, and even some clever selector hacks can often replace !important with something cleaner, more predictable, and far less embarrassing to explain to your future self.

Let’s talk about those alternatives.

Specificity and !important

Selector specificity is a deep rabbit hole, and not the goal of this discussion. That said, to understand why !important exists, we need to look at how CSS decides which rules apply in the first place. I wrote a brief overview on specificity that serves as a good starting point. Chris also has a concise piece on it. And if you really want to go deep into all the edge cases, Frontend Masters has a thorough breakdown.

In short, CSS gives each selector a kind of “weight.” When two rules target the same element, the rule with higher specificity wins. If the specificity is equal, the rule declared later in the stylesheet takes precedence.

  • Inline styles (style="...") are the heaviest.
  • ID selectors (#header) are stronger than classes or type selectors.
  • Class, attribute, and pseudo-class selectors (.btn, [type="text"], :hover) carry medium weight.
  • Type selectors and pseudo-elements (div, p, ::before) have the lowest weight. Although, the * selector is even lower with a specificity of 0-0-0 compared to type selectors which have a specificity of 0-0-1.
/* Low specificity (0,0,1) */
p {
  color: gray;
}

/* Medium specificity (0,1,0) */
.button {
  color: blue;
}

/* High specificity (1,1,0) */
#header .button {
  color: red;
}
<!-- Inline style (1,0,0) -->
<p style="color: green;">Hello</p>

Inline styles being the heaviest also explains why they’re often frowned upon and not considered “clean” CSS since they bypass most of the normal structure we try to maintain.

!important changes this behavior. It skips normal specificity and source order, pushing that declaration to the top within its origin and cascade layer:

p {
  color: red !important;
}

#main p {
  color: blue;
}

Even though #main p is more specific, the paragraph will appear red because the !important declaration overrides it.

Why !important can be problematic

Here’s the typical lifecycle of !important in a project involving multiple developers:

“Why isn’t this working? Add !important. Okay, fixed.”

Then someone else comes along and tries to change that same component. Their rule doesn’t apply, and after some digging, they find the !important. Now they have a choice:

  • remove it and risk breaking something else,
  • or add another !important to override it.

And since no one is completely sure why the first one was added, the safer move often feels like adding another one. This can quickly spiral out of control in larger projects.

On a more technical note, the fundamental problem with !important is that it breaks the intended order of the cascade. CSS is designed to resolve conflicts predictably through specificity and source order. Later rules override earlier ones, and more specific selectors override less specific ones.

A common place where this becomes obvious is theme switching. Consider the example below:

.button {
  color: red !important;
}

.dark .button {
  color: white;
}

Even inside a dark theme, the button stays red. This results in the stylesheet becoming harder to reason about, because the cascade is no longer predictable.

In large teams, especially, this results in maintenance and debugging becoming harder. None of this means !important should never be used. There are legitimate cases for it, especially in utility classes, accessibility overrides, or user stylesheets. But if you’re using it as your go-to method to resolve a selector/styling conflict, it’s usually a sign that something else in the cascade needs attention.

Let’s look at alternatives.

Cascade layers

Cascade layers are a more advanced feature of CSS, and there’s a lot of theory on them. For the purposes of this discussion, we’ll focus on how they help you avoid !important. If you want to learn more, Miriam Suzanne wrote a complete guide on CSS Cascade Layers on it that goes into considerable detail.

In short, cascade layers let you define explicit priority groups in your CSS. Instead of relying on selector specificity, you decide up front which category of styles should take precedence. You can define your layer order up front:

@layer reset, defaults, components, utilities;

This establishes priority from lowest to highest. Now you can add styles into those layers:

@layer defaults {
  a:any-link {
    color: maroon;
  }
}

@layer utilities {
  [data-color='brand'] {
    color: green;
  }
}

Even though [data-color='brand'] has lower specificity than a:any-link, the utilities layer takes precedence because it was defined later in the layer stack.

It’s worth noting that specificity still works inside a layer. But between layers, layer order is given priority.

With cascade layers, you can prioritize entire categories of styles instead of individual rules. For example, your “overrides” layer always takes precedence over your “base” layer. This sort of architectural thinking, instead of reactive fixing saves a lot of headaches down the line.

One very common example is integrating third-party CSS. If a framework ships with highly specific selectors, you can do this:

@layer framework, components;

@import url('framework.css') layer(framework);

@layer components {
  .card {
    padding: 2rem;
  }
}

Now your component styles automatically override the framework styles, regardless of their selector specificity, as long as the framework isn’t using !important.

And while we’re talking about it, it’s good to note that using !important with cascade layers is actually counterintuitive. That’s because !important actually reverses the layer order. It is no longer a quick way to jump to the top of the priorities — but an integrated part of our cascade layering; a way for lower layers to insist that some of their styles are essential.

So, if we were to order a set of layers like this:

  1. utilities (most powerful)
  2. components
  3. defaults (least powerful)

Using !important flips things on their head:

  1. !important defaults (most powerful)
  2. !important components
  3. !important utilities
  4. normal utilities
  5. normal components
  6. normal defaults (least powerful)

Notice what happens there: it generates three new, reversed important layers that supersede the original three layers while reversing the entire order.

The :is() pseudo

The :is() pseudo-class is interesting because it takes the specificity of its most specific argument. Say you have a component that needs to match the weight of a more specific selector elsewhere in the codebase:

/* somewhere in your styles */
#sidebar a {
  color: gray;
}

/* your component */
.nav-link {
  color: blue;
}

Rather than using !important, you can bump .nav-link up by wrapping it in :is() with a more specific argument:

:is(#some_id, .nav-link) {
  color: blue;
}

Now this has id-level specificity while matching only .nav-link. It’s worth noting that the selector inside :is() doesn’t have to match an actual element. We’re using #some_id purely to increase specificity in this case.

Note: If #some_id actually exists in your markup, this selector would also match that element. So it would be best to use an id not being used to avoid side effects.

On the flip side, :where() does the opposite. It always resolves to a specificity of (0,0,0), no matter what’s inside it. This is handy for reset or base styles where you want anything downstream to override easily.

Doubling up a selector

A pretty straightforward way of increasing a selectors specificity is repeating the selector. This is usually done with classes. For example:

.button {
  color: blue;
}

.button.button {
  color: red;  /* higher specificity */
}

You would generally not want to do this too often as it can become a readability nightmare.

Reordering

CSS resolves ties in specificity by source order, so a rule that comes later is prioritized. This is easy to overlook, especially in larger stylesheets where styles are spread across multiple files.

If a more generic rule keeps overriding a more targeted one and the specificity is the same, check whether the generic rule is being loaded after yours. Flipping the order can fix the conflict without needing to increase specificity.

This is also why it’s worth thinking about stylesheet organization from the start. A common pattern is to go from generic to specific (resets and base styles first, then layout, then components, then utilities).

When using !important does make sense

After all that, it’s worth being clear: !important does have legitimate use cases. Chris discussed this a while back too, and the comments are worth a read too.

The most common case is utility classes. For example, the whole point of classes like .visually-hidden is that they do one thing, everywhere. In this cases, you don’t want a more specific selector quietly undoing it somewhere else. The same is true for state classes like .disabled or generic component styles like .button.

.visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden !important;
  clip-path: inset(50%) !important;
}

Third-party overrides are another common scenario. !important can be used here to either override inline styles being set in JavaScript or normal styles in a stylesheet that you can’t edit.

From an accessibility point of view, !important is irreplaceable for user stylesheets. Since these are applied on all webpages and there’s virtually no way to guarantee if the stylesheets’ selectors will always have the highest specificity, !important is basically the only reliable way to make sure your styles always get precedence.

Another good example is when it comes to respecting a user’s browser preferences, such as reducing motion:

@media screen and (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

Wrapping up

The difference between good and bad use of !important really comes down to intent. Are you using it because you understand the CSS Cascade and have made a call that this declaration should always apply? Or are you using it as a band-aid? The latter will inevitably cause issues down the line.

Further reading


Alternatives to the !important Keyword originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Monday, April 6, 2026

Mostly Cloudy/Wind today!



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

Current wind speeds: 20 from the Northeast

Pollen: 0

Sunrise: April 6, 2026 at 06:27PM

Sunset: April 7, 2026 at 07:20AM

UV index: 0

Humidity: 54%

via https://ift.tt/mRZuHxa

April 7, 2026 at 10:02AM

Looking at New CSS Multi-Column Layout Wrapping Features

Multi-column layouts have not been used to their full potential, mostly because once content exceeded a limit, multi-column would force a horizontal scroll. It’s unintuitive and a UX no-no, especially on the modern web where the default scroll is vertical.

Take the following case for example:

The CSS code for that might look something like this:

body {
  max-width: 700px;
}

.article {
  column-gap: 10px;
  column-count: 3;
  height: 350px;
}

When the content size exceeds the body container, multi-column creates additional columns and a horizontal scroll. However, we finally have the tools that have recently landed in Chrome that “fix” this without having to resort to trickier solutions.

Chrome 145 introduces the column-height and column-wrap properties, enabling us to wrap the additional content into a new row below, creating a vertical scroll instead of a horizontal scroll. 

So, now we can do something like this in Chrome 145+:

body {
  max-width: 700px;
}

.article {
  column-gap: 10px;
  column-count: 3;
  column-wrap: wrap;
  height: 350px;
}

And we get this nice multi-column layout that maintains the column-count:

Multi-column layout example showing three columns from left to right.

This effectively transforms Multi-Column layouts into 2D Flows, helping us create a more web-appropriate scroll.

⚠️ Browser Support: As of April 2026, column-wrap and column-height are available in Chrome 145+. Firefox, Safari, and Edge do not yet support these properties.

What this actually solves

The new properties can be genuinely useful in several cases:

Fixed-height content blocks

This is probably one of the most useful use cases for these properties. If you’re working with content that has predictable or capped heights, like card grids where each card has a max-height, then this works beautifully. 

Toggle between column-wrap: wrap and column-wrap: nowrap in the following demo (Chrome 145+ needed) to check the difference.

In case you’re checking this in an unsupported browser, this is the nowrap layout:

Multi-column layout example of four cards components in a row with horizontal scrolling.

And this is the wrap layout:

Multi-column layout example of five cards components in a row that wraps to a second row.

Wrapping creates a much more seamless flow. 

However, in case the content-per-card is unbalanced, then even with wrapping, it can lead to unbalanced layouts:

A broken multi-column layout of card components. Some cards are split into multiple cards because the content is unbalanced.

Newspaper-style and Magazine-style layouts

Another real life use case is when designing newspaper-style layouts or sections where you’re willing to set explicit container and column heights. As can be seen in the earlier example, the combination of column-height and column-wrap helps make the layout responsive for different screen sizes, while retaining a more intuitive flow of information. 

Block-direction carousels

This is my personal favorite use case of the column-wrap feature! By setting the column height to match the viewport (e.g., 100dvh), you can essentially treat the multi-column flow as a pagination system, where your content fills the height of the screen and then “wraps” vertically. When combined with scroll-snap-type: y mandatory, you get a fluid, vertical page-flipping experience that handles content fragmentation without any manual clipping or JavaScript calculation.

Play around with the following demo and check it out for yourself. Unless you’re on Chrome 145+ you’ll get a horizontal scroll instead of the intended vertical.

There is a bit of a drawback to this though: If the content on a slide is too long, column-wrap will make it flow vertically, but the flow feels interrupted by that imbalance. 

What they don’t solve

While these properties are genuinely helpful, they are not one-stop solutions for all multi-column designs. Here are a few situations where they might not be the “right” approach.

Truly dynamic content

If the content height is unknown or unpredictable in advance (e.g., user-generated content, CMS-driven pages), then these properties are of little use. The design can still be wrapped vertically with the column-wrap property, however, the layout would remain unpredictable without a fixed column height.

It can lead to over-estimating the column height, leaving awkward gaps in the layout. Similarly, it can lead you to under-estimate the height, resulting in unbalanced columns. The fix here is then to use JS to calculate heights, which defeats the idea of a CSS-native solution.

Media-query-free responsiveness

For a truly “responsive” layout, we still need to use media queries to adjust column-count and column-height for different viewport sizes. While the wrapping helps and creates incremental benefits for a CSS-native solution, it can only help adjust the overflow behavior. Hence, the dependency on media query persists when supporting varying screen sizes.

Complex alignment needs

If you need precise control over where items sit in relation to each other, CSS Grid is still a better option. While multi-column with wrapping gives you flow, it still lacks positioning control.

Comparing alternatives

Let’s see how the multi-column approach compares with existing alternatives like CSS Grid, CSS Flexbox, and the evolving CSS Masonry, that offer similar layouts.

One key difference is that while grid and flexbox manage distinct containers, multi-column is the only system that can fragment a single continuous stream of content across multiple columns and rows. This makes it the best fit for presenting long-form content, like we saw in the newspaper layout example.

CSS Grid lets us control placement via the grid structure, making it great for complex layouts requiring precise positioning or following asymmetric designs, like dashboards or responsive image galleries that need to auto-fit according to the screen size.

Flexbox with wrapping is great for creating standard UI components like navigation bars and tag clouds that should wrap around on smaller screen sizes.

Multi-column layout showing a navigation of eight items where a second row wraps starting at the fifth items.

Note: Chrome is also experimenting with a new flex-wrap: balance keyword that could provide more wrapping control as well.

CSS Grid and Flexbox with wrapping are both good fits for layouts where each item is independent. They work well with content of dynamic heights and provide better alignment control compared to a multi-column approach. However, multi-column with the updated properties has an edge when it comes to fragmentation-aware layouts as we’ve seen.

CSS Masonry, on the other hand, will be useful for interlocking items with varying heights. This makes it perfect for creating style boards (like Pinterest) that pack items with varying heights in an efficient and aesthetic manner. Another good use case is e-commerce websites that use a masonry grid for product displays because descriptions and images can lead to differing card heights.

Conclusion

The new column-wrap and column-height properties supported in Chrome 145 could significantly increase the usability of multi-column layouts. By enabling 2D flows, we have a way to fragment content without losing the vertical scrolling experience.

That said, these features will not be a replacement for the structural precision of CSS Grid or the item-based flexibility of Flexbox. But they will fill a unique niche. As browser support continues to expand, the best way to approach multi-column layout is with an understanding of both its advantages and limitations. They won’t solve dynamic height issues or eliminate the need for media queries, but will allow flowing continuous content in a 2D space.


Looking at New CSS Multi-Column Layout Wrapping Features originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Sunday, April 5, 2026

Mostly Clear today!



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

Current wind speeds: 10 from the Southeast

Pollen: 0

Sunrise: April 5, 2026 at 06:29PM

Sunset: April 6, 2026 at 07:19AM

UV index: 0

Humidity: 35%

via https://ift.tt/R3kSTl4

April 6, 2026 at 10:02AM

Saturday, April 4, 2026

Mostly Clear today!



With a high of F and a low of 28F. Currently, it's 42F and Clear outside.

Current wind speeds: 4 from the Northeast

Pollen: 0

Sunrise: April 4, 2026 at 06:30PM

Sunset: April 5, 2026 at 07:18AM

UV index: 0

Humidity: 38%

via https://ift.tt/3bSXI6A

April 5, 2026 at 10:02AM

Friday, April 3, 2026

Clear today!



With a high of F and a low of 26F. Currently, it's 37F and Clear outside.

Current wind speeds: 13 from the Northwest

Pollen: 0

Sunrise: April 3, 2026 at 06:32PM

Sunset: April 4, 2026 at 07:17AM

UV index: 0

Humidity: 58%

via https://ift.tt/Kx7GgJS

April 4, 2026 at 10:02AM

Thursday, April 2, 2026

Mostly Clear/Wind today!



With a high of F and a low of 33F. Currently, it's 57F and Clear outside.

Current wind speeds: 18 from the South

Pollen: 0

Sunrise: April 2, 2026 at 06:34PM

Sunset: April 3, 2026 at 07:16AM

UV index: 0

Humidity: 32%

via https://ift.tt/7sOAMup

April 3, 2026 at 10:02AM

Alternatives to the !important Keyword

Every now and then, I stumble onto an old project of mine, or worse, someone else’s, and I’m reminded just how chaotic CSS can get over time...