> All in One 586

Ads

Wednesday, March 11, 2026

Abusing Customizable Selects

Web browsers ship new features all the time, but what fun is it if we can’t build silly and fun things with them?

In this article, let’s go over a few demos that I’ve made by using the new customizable <select> feature, and walk through the main steps and techniques that I’ve used to implement them.

I hope they get you as excited as I am about custom selects, and give you just about enough knowledge to get started creating your own. Yours might be more, you know, useful than mine, and probably for good reasons, but I like going a little bit overboard on silly ideas because that gives me a better chance to learn.

Before we start, a word about browser support: the demos in this article only run on recent Chromium-based browsers because that’s where customizable selects are implemented right now. However, this feature is designed in a way that doesn’t break non-supporting browsers. After all, a customized <select> element is still a <select> element. So, if the browser you’re using doesn’t support customizable selects, you’ll just see normal selects and options in these demos, and that’s great. It’ll just be a lot less fun.

Curved stack of folders

Let’s get started with the first demo: a stack of folders to pick from, with a twist:

We’ll start with some HTML code first. We don’t need a lot of complicated markup here because each option is just the name of the folder. We can draw the folder icons later with CSS only.

<select>
  <option value="documents"><span>Documents</span></option>
  <option value="photos"><span>Photos</span></option>
  <option value="music"><span>Music</span></option>
  <option value="videos"><span>Videos</span></option>
  <option value="downloads"><span>Downloads</span></option>
  <option value="desktop"><span>Desktop</span></option>
  <option value="projects"><span>Projects</span></option>
  <option value="backups"><span>Backups</span></option>
  <option value="trash"><span>Trash</span></option>
</select>

You’ll notice that we’ve used <span> elements inside the <option> elements, to wrap each folder name. That’s going to be useful for styling the selected folder name later. Even though this is just a <span>, being able to do this is quite a big change from what was previously possible.

That’s because, up until very recently, <option>s could only contain text, because that’s the only thing that could appear inside options of a select. The HTML parser has now been relaxed to allow for a lot more HTML elements to be embedded in options. Browsers that don’t support customizable selects will just ignore these extra elements and display the text only.

So, here’s what our stack of folders looks like so far:

An unstyled select element with expanded options.

Next up, and this is the most important thing you’ll want to do to opt into the customizable select feature: let’s reset the default appearance of the select and its dropdown part, by using the ::picker() pseudo-element:

select,
::picker(select) {
  appearance: base-select;
}

This CSS rule does a lot for us: it unlocks full styling capabilities for the entire select, including its button, dropdown, and options. Without this opt-in, you get a standard select.

Now let’s style the select, starting with its button part. First, we’ll get rid of the picker icon by using the new ::picker-icon pseudo-element to hide it:

select::picker-icon {
  display: none;
}

Next, let’s add a bit more styles to create a nice-looking button:

select {
  background: linear-gradient(
    135deg,
    rgba(40, 40, 50, 0.4) 0%,
    rgba(60, 60, 70, 0.25) 50%,
    rgba(50, 50, 60, 0.35) 100%
  );
  backdrop-filter: blur(12px) saturate(180%);
  box-shadow:
    0 8px 32px rgba(0, 0, 0, 0.2),
    inset 0 1px 1px rgba(255, 255, 255, 0.15),
    inset 0 -1px 1px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: white;
  min-inline-size: 12rem;
}

And here is our new select button:

A custom select button with an opaque background, a folder icon, and a text label called Music.

Now let’s turn our attention to the dropdown part since this is where the magic happens.

In a select, the dropdown contains all the options and appears when you click on the button. A lot of browser default styles apply to it already to set its position, background-color, margin, and more. So, we’ll have to disable and override a bunch of stuff.

In our demo, we don’t want the dropdown to be visible at all. Instead, we want each individual option (each folder in this case) to appear as if floating above the page, without a container element.

To do this, let’s use the ::picker(select) pseudo-element to set our styles:

::picker(select) {
  background: transparent;
  border: none;
  box-shadow: none;
  overflow: visible;
}

And with this, the dropdown isn’t visible anymore and it no longer constrains the options or clips them if they overflow the dropdown area.

This gives us the following improvements:

A select element with expanded options formatted as text in a single vertical list. An option called music is selected and represents the top picker button which is styled with a folder icon to the left of the text label.

It’s now time to turn our attention to the option elements. First, let’s replace the checkmark icon with a little disc icon instead by using the ::checkmark pseudo-element:

option::checkmark {
  content: "●";
  color: #222;
}

This pseudo-element makes it easy to change the shape, the color, or even the size of the checkmark.

Let’s also add an additional pseudo-element to each option, by using option::before, to display a folder emoji next to each option. And, with a pinch more CSS fine tuning, we end up with this:

A vertical column of folder icons expanded as options from a select element. Each folder includes a label on the right.

We now have a list of folders which floats on top of the page when we click the select button. It works like any other select, too, either with the mouse, or with the keyboard, so we can just thank the browser for maintaining the accessibility of the input while we’re having fun with CSS.

Let’s now apply some CSS transformation to make the stack of folders a little curvy, so it looks cooler.

To achieve this, we’ll need one more piece of new CSS syntax which, unfortunately, isn’t yet widely available: the sibling-index() function. This function returns the index of the element within its siblings. The sibling-count() function also exists, and it returns the total number of siblings, but we won’t need it here.

Having access to the index of the current element within its siblings means that we can style each option depending on its position within the select dropdown. This is exactly what we need to make the options appear at a gradually larger angle.

Here is the code:

option {
  --rotation-offset: -4deg;
  rotate: calc(sibling-index() * var(--rotation-offset));
}

In this code snippet, we first create a custom property called --rotation-offset, which defines the angle by which each option should rotate, with respect to the previous option. We then use this with the rotate property, multiplying its value by sibling-index(). That way, the first option is rotated by -4 degrees, the second one by -8 degrees, the third by -12 degrees, and so on.

Now, that’s not enough on its own to create the illusion of a curved stack of folders because each folder rotates around its own point of origin, which is located in the top-left corner of each folder by default. Right now, we get this:

A single column of folder icons with labels on the right. Each folder is slightly rotated more as the list goes down.

Let’s use the transform-origin property to set a shared point of origin around which all options will rotate. Because transform-origin is relative to each individual element, we need to use the sibling-index() function again to move all origin points up and to the right so they’re all in the same spot:

option {
  --rotation-offset: -4deg;
  rotate: calc(sibling-index() * var(--rotation-offset));
  transform-origin: right calc(sibling-index() * -1.5rem);
}

And with this, we get the following result:

A vertical column of folders with labels on the right fanned out and curving towards the right.

The final step is to animate the options. It looks great as it is, but we want the stack of folders to get gradually curved until it reaches its final shape. That’ll make it a lore more lively and fun to interact with.

Let’s reset the option’s rotation by default, and apply a transition with a nice elastic easing function:

option {
  rotate: 0deg;
  transition: rotate 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

And now, let’s apply the right rotation angle only when the select is open:

select:open option {
  rotate: calc(sibling-index() * -1 *  var(--rotation-offset));
}

Unfortunately, the above is not enough. By default, CSS transitions are not triggered when an element appears, which is the case for our options. Thankfully, there’s a fix for this issue: the @starting-style at-rule. This at-rule lets us define the initial state of the options, making it possible for the transition to play right when the options appear:

@starting-style {
  select:open option {
    rotate: 0deg;
  }
}

One more thing to make it even nicer. Let’s delay each transition relative to the previous one to make it look like each folder comes in slightly after the one before it. To achieve this, let’s use the sibling-index() function once more, as a multiplier to a short transition delay:

option {
  transition-delay: calc((sibling-index() - 1) * 0.01s);
}

We now have an animated, curved, stack of folders implemented with a <select> element! Check out the demo and code in the next CodePen:

CSS gains a lot of new capabilities each year. I hope this demo walk through helped you get a better understanding of some of these new capabilities. Building it helped me understand a lot of new, to me, concepts. It also got me very excited about the customizable select feature. So much, that I created other demos too. So, let’s look at two more of them. This time though, we’ll go quicker and only highlight the most important parts.

Fanned deck of cards

For our second demo, we’ll create a card picker, which opens up in a fanned deck fashion:

The HTML markup for this demo is a little different than for the previous one. Each card has a bit of content to display, so let’s create a couple of <span> elements to each option:

<option class="red" value="QH">
  <span class="rank">Q</span>
  <span class="suit">♥</span>
</option>

The other interesting thing about the HTML code we’ll use here, is the addition of an empty <button> element right below the <select> opening tag:

<select>
  <button></button>
  <option>…</option>
  <!-- ... -->
</select>

This empty <button> serves a very specific purpose: it prevents the default <selectedcontent> behavior from happening.

In a customized select, the browser automatically displays the currently selected option’s content (in this case, the card face) in the button area of the select. And it does this by creating an element named <selectedcontent> which mirrors the selected option. But, in our demo, we want the button to always show the back of the deck of cards, not the selected card. To achieve this, we override the default behavior by introducing our own <button>. This tells the browser not to insert its own <selectedcontent> element and lets us style the <select> element:

select {
  background:
    /* Diamond pattern overlay */
    repeating-linear-gradient(45deg,
      transparent,
      transparent 1vmin,
      rgba(255, 255, 255, 0.05) 1vmin,
      rgba(255, 255, 255, 0.05) 2vmin),
    repeating-linear-gradient(-45deg,
      transparent,
      transparent 1vmin,
      rgba(255, 255, 255, 0.05) 1vmin,
      rgba(255, 255, 255, 0.05) 2vmin),
    /* Base gradient */
    linear-gradient(135deg, #8b0000 0%, #dc143c 50%, #8b0000 100%);
}
A single card with its back showing in red.

Now, for the dropdown part, just like in the previous demo, we don’t want the dropdown container element to be visible, so we’ll also override the default background, border, and overflow styles like we did before.

More importantly, the position of the deck of cards, when opened, is very important. We want it to fan out from the deck itself and remain centered above it.

In a customizable select, the dropdown part, i.e., the ::picker(select) pseudo-element, is positioned relative to the button part thanks to anchor positioning, which is great because we can override it!

In our case, let’s override the alignment relative to the anchor, which is the button, by using the position-area property:

::picker(select) {
  position-area: center center;
  inset: 0;
}

We’re also setting the inset property to 0 here. This sets all top, right, bottom, and left properties to 0 in a single declaration, which makes the dropdown part able to use the entire available space, rather than being constrained by the browser to appear on the side of the select button.

Finally, let’s make the cards appear side by side, rather than above each other:

select:open::picker(select) {
  display: flex;
}

When the select element is open and the options are visible, we now see this:

Nice cards lined up in a single row. Each card slightly overlaps.

The next step is to rotate each card so the options appear in a fanned out way, with the center card straight, the cards to the left gradually more rotated towards the left, and the cards to the right rotated towards the right.

To do this, you’ve guessed it, we’ll use the sibling-index() property again. We’ll also use the sibling-count() property this time:

option {
  --card-fan-rotation: 7deg;
  --card-fan-spread: -11vmin;
  --option-index: calc(sibling-index() - 1);
  --center: calc(sibling-count() / 2);
  --offset-from-center: calc(var(--option-index) - var(--center));

  rotate: calc(var(--offset-from-center) * var(--card-fan-rotation));
  translate: calc(var(--offset-from-center) * var(--card-fan-spread)) 0;
  transform-origin: center 75vmin;
}

In the above code snippet, we’re calculating the offset of each card relative to the center card, and we’re using this to rotate each card by increments of 7 degrees. For example, in a deck with 9 cards, the left-most card (i.e., the first card) will get a -4 offset, and will be rotated by -4 * 7 = -28 degrees, while the right-most card will be rotated by 28 degrees.

We also use the translate property to bring the cards close together into a fan, and the `transform-origin` property to make it all look perfect.

Nice cards fanned out in a subtle arc.

 Finally, let’s bring it all together by animating the opening of the deck. To do this, we can define a CSS transition on the custom --card-fan-rotation property. Animating it from 0 to 7 degrees is all we need to create the illusion we’re after. Animating a custom property takes a couple of steps.

First, let’s define the custom property’s type, so that the browser can animate it correctly:

@property --card-fan-rotation {
  syntax: '<angle>';
  inherits: false;
  initial-value: 7deg;
}

Second, let’s use a @starting-style at-rule, like in the previous demo, to allow the CSS transition to play when the options appear:

@starting-style {
  select:open option {
  --card-fan-rotation: 0deg;
  }
}

Then, set the starting rotation angle when the select element is closed, and define the CSS transition:

option {
  --card-fan-rotation: 0deg;
  transition: --card-fan-rotation 0.2s ease-out;
}

And, finally, let’s set the final angle when the select is opened:

select:open option {
  --card-fan-rotation: initial;
}

We can use the `initial` value above instead of hard-coding the 7deg value again, since it’s already defined as the initial value in the @property rule above.

That’s it, our deck of cards, with animated opening, is now ready! Check out the complete code and live demo in this CodePen:

It’s amazing to me how far customizable selects allow you to push things. You don’t only get to override the way the button and its options look, you get to change how everything is positioned, and even animated.

Let’s close with one final demo.

Radial emoji picker

Just like in the previous demo, here we want the emojis to be centered around the select button. To achieve this, let’s override the default anchor positioning of the dropdown part.

This time, we’ll use the anchor() function to set the top and left coordinates of the dropdown container:

::picker(select) {
  top: calc(anchor(top) - var(--radius));
  left: calc(anchor(left) - var(--radius));
  width: calc(var(--radius) * 2 + var(--option-size));
  height: calc(var(--radius) * 2 + var(--option-size));
}

In this code snippet, the --radius property is the radius of the circle of emojis. And, since customizable selects already use anchor positioning, we can use the anchor() function to position the dropdown relative to the button.

Now we need to position the options in a circle, inside the dropdown. As it turns out, CSS knows trigonometry now, too, so we’ll use the cos() and sin() functions together with the sibling-index() and sibling-count() functions:

option {
  position: absolute;
  --angle: calc((sibling-index() - 2) * (360deg / (sibling-count() - 1)) - 90deg);
  top: 50%;
  left: 50%;
  translate:
    calc(-50% + cos(var(--angle)) * var(--radius)) calc(-50% + sin(var(--angle)) * var(--radius));
}

And there we are:

Circular options with icons around another circular item in the center with a star icon.

The final demo also contains a bit of code for animating the opening of the options, but we won’t dig into the details in this article.

To learn more and play with the live demo, check out this CodePen:

Wrapping up

That’s it for now. I hope these demos have given you a bit more of an understanding for how customizable selects are customized, and some excitement for actually using the feature in a real project.

Keep in mind, even when customized, the element is still a <select> and will work just fine in non-supporting browsers. So, even if the feature is still in its early days, you can use it as a great progressive enhancement.


Abusing Customizable Selects originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Tuesday, March 10, 2026

Partly Cloudy/Wind today!



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

Current wind speeds: 22 from the Northeast

Pollen: 0

Sunrise: March 10, 2026 at 07:10PM

Sunset: March 11, 2026 at 06:53AM

UV index: 0

Humidity: 64%

via https://ift.tt/Z3COUi2

March 11, 2026 at 10:02AM

Monday, March 9, 2026

Clear today!



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

Current wind speeds: 11 from the Southwest

Pollen: 0

Sunrise: March 9, 2026 at 07:12PM

Sunset: March 10, 2026 at 06:52AM

UV index: 0

Humidity: 26%

via https://ift.tt/mSGt6L3

March 10, 2026 at 10:02AM

The Value of z-index

The z-index property is one of the most important tools any UI developer has at their disposal, as it allows you to control the stacking order of elements on a webpage. Modals, toasts, popups, dropdowns, tooltips, and many other common elements rely on it to ensure they appear above other content.

While most resources focus on the technical details or the common pitfalls of the Stacking Context (we’ll get to that in a moment…), I think they miss one of the most important and potentially chaotic aspects of z-index: the value.

Screenshot of a code editor with a large number of z-index values, many of which include the !important keyword.

In most projects, once you hit a certain size, the z-index values become a mess of “magic numbers”, a chaotic battlefield of values, where every team tries to outdo the others with higher and higher numbers.

How This Idea Started

I saw this line on a pull request a few years ago:

z-index: 10001;

I thought to myself, “Wow, that’s a big number! I wonder why they chose that specific value?” When I asked the author, they said: “Well, I just wanted to make sure it was above all the other elements on the page, so I chose a high number.”

This got me thinking about how we look at the stacking order of our projects, how we choose z-index values, and more importantly, the implications of those choices.

The Fear of Being Hidden

The core issue isn’t a technical one, but a lack of visibility. In a large project with multiple teams, you don’t always know what else is floating on the screen. There might be a toast notification from Team A, a cookie banner from Team B, or a modal from the marketing SDK.

The developer’s logic was simple in this case: “If I use a really high number, surely it will be on top.”

This is how we end up with magic numbers, these arbitrary values that aren’t connected to the rest of the application. They are guesses made in isolation, hoping to win the “arms race” of z-index values.

We’re Not Talking About Stacking Context… But…

As I mentioned at the beginning, there are many resources that cover z-index in the context of the Stacking Context. In this article, we won’t cover that topic. However, it’s impossible to talk about z-index values without at least mentioning it, as it’s a crucial concept to understand.

Essentially, elements with a higher z-index value will be displayed in front of those with a lower value as long as they are in the same Stacking Context.

If they aren’t, then even if you set a massive z-index value on an element in a “lower” stack, elements in a “higher” stack will stay on top of it, even if they have a very low z-index value. This means that sometimes, even if you give an element the maximum possible value, it can still end up being hidden behind something else.

Now let’s get back to the values.

💡 Did you know? The maximum value for z-index is 2147483647. Why this specific number? It’s the maximum value for a 32-bit signed integer. If you try to go any higher, most browsers will simply clamp it to this limit.

The Problem With “Magic Numbers”

Using arbitrary high values for z-index can lead to several issues:

  1. Lack of maintainability: When you see a z-index value like 10001, it doesn’t tell you anything about its relationship to other elements. It’s just a number that was chosen without any context.
  2. Potential for conflicts: If multiple teams or developers are using high z-index values, they might end up conflicting with each other, leading to unexpected behavior where some elements are hidden behind others.
  3. Difficult to debug: When something goes wrong with the stacking order, it can be challenging to figure out why, especially if there are many elements with high z-index values.A Better Approach

I’ve encountered this “arms race” in almost every large project I’ve been a part of. The moment you have multiple teams working in the same codebase without a standardized system, chaos eventually takes over.

The solution is actually quite simple: tokenization of z-index values.

Now, wait, stay with me! I know that the moment someone mentions “tokens”, some developers might roll their eyes or shake their heads, but this approach actually works. Most of the major (and better-designed) design systems include z-index tokens for a reason. Teams that adopt them swear by them and never look back.

By using tokens, you gain:

  • Simple and easy maintenance: You manage values in one place.
  • Conflict prevention: No more guessing if 100 is higher than whatever Team B is using.
  • Easier debugging:: You can see exactly which “layer” an element belongs to.
  • Better Stacking Context management: It forces you to think about layers systematically rather than as random numbers.

A Practical Example

Let’s look at how this works in practice. I’ve prepared a simple demo where we manage our layers through a central set of tokens in the :root:

:root {
  --z-base: 0;
  --z-toast: 100;
  --z-popup: 200;
  --z-overlay: 300;
}

This setup is incredibly convenient. If you need to add a new popup or a toast, you know exactly which z-index to use. If you want to change the order — for example, to place toasts above the overlay — you don’t need to hunt through dozens of files. You just change the values in the :root, and everything updates accordingly in one place.

Handling New Elements

The real power of this system shines when your requirements change. Suppose you need to add a new sidebar and place it specifically between the base content and the toasts.

In a traditional setup, you’d be checking every existing element to see what numbers they use. With tokens, we simply insert a new token and adjust the scale:

:root {
  --z-base: 0;
  --z-sidebar: 100;
  --z-toast: 200;
  --z-popup: 300;
  --z-overlay: 400;
}

You don’t have to touch a single existing component with this setup. You update the tokens and you’re good to go. The logic of your application remains consistent, and you’re no longer guessing which number is “high enough”.

The Power of Relative Layering

We sometimes want to “lock” specific layers relative to each other. A great example of this is a background element for a modal or an overlay. Instead of creating a separate token for the background, we can calculate its position relative to the main layer.

Using calc() allows us to maintain a strict relationship between elements that always belong together:

.overlay-background {
  z-index: calc(var(--z-overlay) - 1);
}

This ensures that the background will always stay exactly one step behind the overlay, no matter what value we assign to the --z-overlay token.

Managing Internal Layers

Up until now, we’ve focused on the main, global layers of the application. But what happens inside those layers?

The tokens we created for the main layers (like 100, 200, etc.) are not suitable for managing internal elements. This is because most of these main components create their own Stacking Context. Inside a popup that has z-index: 300, a value of 301 is functionally identical to 1. Using large global tokens for internal positioning is confusing and unnecessary.

Note: For these local tokens to work as expected, you must ensure the container creates a Stacking Context. If you’re working on a component that doesn’t already have one (e.g., it doesn’t has a z-index set), you can create one explicitly using isolation: isolate.

To solve this, we can introduce a pair of “local” tokens specifically for internal use:

:root {
  /* ... global tokens ... */

  --z-bottom: -10;
  --z-top: 10;
}

This allows us to handle internal positioning with precision. If you need a floating action button inside a popup to stay on top, or a decorative icon on a toast to sit behind the main content, you can use these local anchors:

.popup-close-button {
  z-index: var(--z-top);
}

.toast-decorative-icon {
  z-index: var(--z-bottom);
}

For even more complex internal layouts, you can still use calc() with these local tokens. If you have multiple elements stacking within a component, calc(var(--z-top) + 1) (or - 1) gives you that extra bit of precision without ever needing to look at global values.

This keeps our logic consistent: we think about layers and positions systematically, rather than throwing random numbers at the problem and hoping for the best.

Versatile Components: The Tooltip Case

One of the biggest headaches in CSS is managing components that can appear anywhere, like a tooltip.

Traditionally, developers give tooltips a massive z-index (like 9999) because they might appear over a modal. But if the tooltip is physically inside the modal’s DOM structure, its z-index is only relative to that modal anyway.

A tooltip simply needs to be above the content it’s attached to. By using our local tokens, we can stop the guessing game:

.tooltip {
  z-index: var(--z-top);
}

Whether the tooltip is on a button in the main content, an icon inside a toast, or a link within a popup, it will always appear correctly above its immediate surroundings. It doesn’t need to know about the global “arms race” because it’s already standing on the “stable floor” provided by its parent layer’s token.

Negative Values Can Be Good

Negative values often scare developers. We worry that an element with z-index: -1 will disappear behind the page background or some distant parent.

However, within our systematic approach, negative values are a powerful tool for internal decorations. When a component creates its own Stacking Context, the z-index is confined to that component. And z-index: var(--z-bottom) simply means “place this behind the default content of this specific container”.

This is perfect for:

  • Component backgrounds: Subtle patterns or gradients that shouldn’t interfere with text.
  • Shadow simulations: When you need more control than box-shadow provides.
  • Inner glows or borders: Elements that should sit “under” the main UI.

Conclusion: The z-index Manifesto

With just a few CSS variables, we’ve built a complete management system for z-index. It’s a simple yet powerful way to ensure that managing layers never feels like a guessing game again.

To maintain a clean and scalable codebase, here are the golden rules for working with z-index:

  1. No magic numbers: Never use arbitrary values like 999 or 10001. If a number isn’t tied to a system, it’s a bug waiting to happen.
  2. Tokens are mandatory: Every z-index in your CSS should come from a token, either a global layer token or a local positioning token.
  3. It’s rarely the value: If an element isn’t appearing on top despite a “high” value, the problem is almost certainly its Stacking Context, not the number itself.
  4. Think in layers: Stop asking “how high should this be?” and start asking “which layer does this belong to?”
  5. Calc for connection: Use calc() to bind related elements together (like an overlay and its background) rather than giving them separate, unrelated tokens.
  6. Local contexts for local problems: Use local tokens (--z-top, --z-bottom) and internal stacking contexts to manage complexity within components.

By following these rules, you turn z-index from a chaotic source of bugs into a predictable, manageable part of your design system. The value of z-index isn’t in how high the number is, but in the system that defines it.

Bonus: Enforcing a Clean System

A system is only as good as its enforcement. In a deadline-driven environment, it’s easy for a developer to slip in a quick z-index: 999 to “make it just work”. Without automation, your beautiful token system will eventually erode back into chaos.

To prevent this, I developed a library specifically designed to enforce this exact system: z-index-token-enforcer.

npm install z-index-token-enforcer --save-dev

It provides a unified set of tools to automatically flag any literal z-index values and require developers to use your predefined tokens:

  • Stylelint plugin: For standard CSS/SCSS enforcement
  • ESLint plugin: To catch literal values in CSS-in-JS and React inline styles
  • CLI scanner: A standalone script that can quickly scan files directly or be integrated into your CI/CD pipelines

By using these tools, you turn the “Golden Rules” from a recommendation into a hard requirement, ensuring that your codebase stays clean, scalable, and, most importantly, predictable.


The Value of z-index originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Sunday, March 8, 2026

Clear today!



With a high of F and a low of 35F. Currently, it's 44F and Clear outside.

Current wind speeds: 7 from the Southwest

Pollen: 0

Sunrise: March 8, 2026 at 07:13PM

Sunset: March 9, 2026 at 06:51AM

UV index: 0

Humidity: 38%

via https://ift.tt/vcAKGbN

March 9, 2026 at 10:02AM

Saturday, March 7, 2026

Clear today!



With a high of F and a low of 27F. Currently, it's 32F and Clear outside.

Current wind speeds: 8 from the Southwest

Pollen: 0

Sunrise: March 7, 2026 at 07:15PM

Sunset: March 8, 2026 at 06:50AM

UV index: 0

Humidity: 58%

via https://ift.tt/DpWMQnj

March 8, 2026 at 10:02AM

Friday, March 6, 2026

Snow Showers Early today!



With a high of F and a low of 21F. Currently, it's 29F and Mostly Cloudy/Wind outside.

Current wind speeds: 20 from the Northwest

Pollen: 0

Sunrise: March 6, 2026 at 07:16PM

Sunset: March 7, 2026 at 06:49AM

UV index: 0

Humidity: 91%

via https://ift.tt/Unkw81P

March 7, 2026 at 10:02AM

Abusing Customizable Selects

Web browsers ship new features all the time, but what fun is it if we can’t build silly and fun things with them? In this article, let’s go...