> All in One 586: November 2025

Ads

Sunday, November 30, 2025

Snow Showers Early today!



With a high of F and a low of 10F. Currently, it's 16F and Cloudy outside.

Current wind speeds: 14 from the Southeast

Pollen: 0

Sunrise: November 30, 2025 at 07:51PM

Sunset: December 1, 2025 at 05:29AM

UV index: 0

Humidity: 76%

via https://ift.tt/NtxvYls

December 1, 2025 at 10:02AM

Saturday, November 29, 2025

Partly Cloudy today!



With a high of F and a low of 10F. Currently, it's 14F and Fair outside.

Current wind speeds: 5 from the North

Pollen: 0

Sunrise: November 29, 2025 at 07:50PM

Sunset: November 30, 2025 at 05:29AM

UV index: 0

Humidity: 73%

via https://ift.tt/fFqobUl

November 30, 2025 at 10:02AM

Friday, November 28, 2025

Light Rain/Freezing Rain/Wind today!



With a high of F and a low of 19F. Currently, it's 33F and Mostly Cloudy outside.

Current wind speeds: 7 from the North

Pollen: 0

Sunrise: November 28, 2025 at 07:49PM

Sunset: November 29, 2025 at 05:29AM

UV index: 0

Humidity: 89%

via https://ift.tt/9rjPsqB

November 29, 2025 at 10:02AM

Thursday, November 27, 2025

Mostly Cloudy today!



With a high of F and a low of 24F. Currently, it's 31F and Clear outside.

Current wind speeds: 9 from the Southeast

Pollen: 0

Sunrise: November 27, 2025 at 07:48PM

Sunset: November 28, 2025 at 05:30AM

UV index: 0

Humidity: 81%

via https://ift.tt/Pz3BqiC

November 28, 2025 at 10:02AM

Wednesday, November 26, 2025

Partly Cloudy today!



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

Current wind speeds: 6 from the Southwest

Pollen: 0

Sunrise: November 26, 2025 at 07:47PM

Sunset: November 27, 2025 at 05:30AM

UV index: 0

Humidity: 81%

via https://ift.tt/c2kBKyv

November 27, 2025 at 10:02AM

Tuesday, November 25, 2025

Partly Cloudy today!



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

Current wind speeds: 5 from the Northwest

Pollen: 0

Sunrise: November 25, 2025 at 07:46PM

Sunset: November 26, 2025 at 05:30AM

UV index: 0

Humidity: 61%

via https://ift.tt/zqZOIy2

November 26, 2025 at 10:02AM

Monday, November 24, 2025

Mostly Clear today!



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

Current wind speeds: 9 from the West

Pollen: 0

Sunrise: November 24, 2025 at 07:45PM

Sunset: November 25, 2025 at 05:31AM

UV index: 0

Humidity: 73%

via https://ift.tt/rVxSuYE

November 25, 2025 at 10:02AM

On Inheriting and Sharing Property Values

Sometimes I want to set the value of a CSS property to that of a different property, even if I don’t know what that value is, and even if it changes later. Unfortunately though, that’s not possible (at least, there isn’t a CSS function that specifically does that).

In my opinion, it’d be super useful to have something like this (for interpolation, maybe you’d throw calc-size() in there as well):

/* Totally hypothetical */
button {
  border-radius: compute(height, self);
  border-radius: compute(height, inherit);
  border-radius: compute(height, #this);
}

In 2021, Lea Verou explained why, despite being proposed numerous times, implementing such a general-purpose CSS function like this isn’t feasible. Having said that, I do remain hopeful, because things are always evolving and the CSSWG process isn’t always linear.

In the meantime, even though there isn’t a CSS function that enables us to get the value of a different property, you might be able to achieve your outcome using a different method, and those methods are what we’re going to look at today.

The fool-proof CSS custom properties method

We can easily get the value of a different CSS property using custom properties, but we’d need to know what the value is in order to declare the custom property to begin with. This isn’t ideal, but it does enable us to achieve some outcomes.

Let’s jump back to the example from the intro where we try to set the border-radius based on the height, only this time we know what the height is and we store it as a CSS custom property for reusability, and so we’re able to achieve our outcome:

button {
  --button-height: 3rem;
  height: var(--button-height);
  border-radius: calc(var(--button-height) * 0.3);
}

We can even place that --button-height custom property higher up in the CSS cascade to make it available to more containment contexts.

:root {
  /* Declare here to use anywhere */
  --button-height: 3rem;

  header {
    --header-padding: 1rem;
    padding: var(--header-padding);
  
    /* Height is unknown (but we can calculate it) */
    --header-height: calc(var(--button-height) + (var(--header-padding) * 2));
  
    /* Which means we can calculate this, too */
    border-radius: calc(var(--header-height) * 0.3);
  
    button {
      /* As well as these, of course */
      height: var(--button-height);
      border-radius: calc(var(--button-height) * 0.3);

      /* Oh, what the heck */
      padding-inline: calc(var(--button-height) * 0.5);
    }
  }
}

I guess when my math teacher said that I’d need algebra one day. She wasn’t lying!

The unsupported inherit() CSS function method

The inherit() CSS function, which isn’t currently supported by any web browser, will enable us to get the value of a parent’s property. Think: the inherit keyword, except that we can get the value of any parent property and even modify it using value functions such as calc(). The latest draft of the CSS Values and Units Module Level 5 spec defines how this’d work for custom properties, which wouldn’t really enable us to do anything that we can’t already do (as demonstrated in the previous example), but the hope is that it’d work for all CSS properties further down the line so that we wouldn’t need to use custom properties (which is just a tad longer):

header {
  height: 3rem;

  button {
    height: 100%;

    /* Get height of parent but use it here */
    border-radius: calc(inherit(height) * 0.3);
    padding-inline: calc(inherit(height) * 0.5);
  }
}

There is one difference between this and the custom properties approach, though. This method depends on the fixed height of the parent, whereas with the custom properties method either the parent or the child can have the fixed height.

This means that inherit() wouldn’t interpolate values. For example, an auto value that computes to 3rem would still be inherited as auto, which might compute to something else when inherit()-ed., Sometimes that’d be fine, but other times it’d be an issue. Personally, I’m hoping that interpolation becomes a possibility at some point, making it far more useful than the custom properties method.

Until then, there are some other (mostly property-specific) options.

The aspect-ratio CSS property

Using the aspect-ratio CSS property, we can set the height relative to the width, and vice-versa. For example:

div {
  width: 30rem;

  /* height will be half of the width */
  aspect-ratio: 2 / 1;

  /* Same thing */
  aspect-ratio: 3 / 1.5;

  /* Same thing */
  aspect-ratio: 10 / 5;

  /* width and height will be the same */
  aspect-ratio: 1 / 1;
}

Technically we don’t “get” the width or the height, but we do get to set one based on the other, which is the important thing (and since it’s a ratio, you don’t need to know the actual value — or unit — of either).

The currentColor CSS keyword

The currentColor CSS keyword resolves to the computed value of the color property. Its data type is <color>, so we can use it in place of any <color> on any property on the same element. For example, if we set the color to red (or something that resolves to red), or if the color is computed as red via inheritance, we could then declare border-color: currentColor to make the border red too:

body {
  /* We can set color here (and let it be inherited) */
  color: red;

  button {
    /* Or set it here */
    color: red;

    /* And then use currentColor here */
    border-color: currentColor;
    border: 0.0625rem solid currentColor;
    background: hsl(from currentColor h s 90);
  }
}

This enables us to reuse the color without having to set up custom properties, and of course if the value of color changes, currentColor will automatically update to match it.

While this isn’t the same thing as being able to get the color of literally anything, it’s still pretty useful. Actually, if something akin to compute(background-color) just isn’t possible, I’d be happy with more CSS keywords like currentColor.

In fact, currentBackgroundColor/currentBackground has already been proposed. Using currentBackgroundColor for example, we could set the border color to be slightly darker than the background color (border-color: hsl(from currentBackgroundColor h s calc(l - 30))), or mix the background color with another color and then use that as the border color (border-color: color-mix(currentBackgroundColor, black, 30)).

But why stop there? Why not currentWidth, currentHeight, and so on?

The from-font CSS keyword

The from-font CSS keyword is exclusive to the text-decoration-thickness property, which can be used to set the thickness of underlines. If you’ve ever hated the fact that underlines are always 1px regardless of the font-size and font-weight, then text-decoration-thickness can fix that.

The from-font keyword doesn’t generate a value though — it’s optionally provided by the font maker and embedded into the font file, so you might not like the value that they provide, if they provide one at all. If they don’t, auto will be used as a fallback, which web browsers resolve to 1px. This is fine if you aren’t picky, but it’s nonetheless unreliable (and obviously quite niche).

We can, however, specify a percentage value instead, which will ensure that the thickness is relative to the font-size. So, if text-decoration-thickness: from-font just isn’t cutting it, then we have that as a backup (something between 8% and 12% should do it).

Don’t underestimate CSS units

You probably already know about vw and vh units (viewport width and viewport height units). These represent a percentage of the viewport’s width and height respectively, so 1vw for example would be 1% of the viewport’s width. These units can be useful by themselves or within a calc() function, and used within any property that accepts a <length> unit.

However, there are plenty of other, lesser-known units that can be useful in a similar way:

  • 1ex: equal to the computed x-height
  • 1cap: equal to the computed cap height
  • 1ch: equal to the computed width of the 0 glyph
  • 1lh: equal to the computed line-height (as long as you’re not trimming or adding to its content box, for example using text-box or padding, respectively, lh units could be used to determine the height of a box that has a fixed number of lines)
Source: W3

And again, you can use them, their logical variants (e.g., vi and vb), and their root variants (e.g., rex and rcap) within any property that accepts a <length> unit.

In addition, if you’re using container size queries, you’re also free to use the following container query units within the containment contexts:

  • 1cqw: equal to 1% of the container’s computed width
  • 1cqh: equal to 1% of the container’s computed height
  • 1cqi: equal to 1% of the container’s computed inline size
  • 1cqb: equal to 1% of the container’s computed block size
  • 1cqmin: equal to 1cqi or 1cqb, whichever is smallest
  • 1cqmax: equal to 1cqi or 1cqb, whichever is largest

That inherit() example from earlier, you know, the one that isn’t currently supported by any web browser? Here’s the same thing but with container size queries:

header {
  height: 3rem;
  container: header / size;

  @container header (width) {
    button {
      height: 100%;
      border-radius: calc(100cqh * 0.3);
      padding-inline: calc(100cqh * 0.5);
    }
  }
}

Or, since we’re talking about a container and its direct child, we can use the following shorter version that doesn’t create and query a named container (we don’t need to query the container anyway, since all we’re doing is stealing its units!):

header {
  height: 3rem;
  container-type: size;

  button {
    height: 100%;
    border-radius: calc(100cqh * 0.3);
    padding-inline: calc(100cqh * 0.5);
  }
}

However, keep in mind that inherit() would enable us to inherit anything, whereas container size queries only enable us to inherit sizes. Also, container size queries don’t work with inline containers (that’s why this version of the container is horizontally stretched), so they can’t solve every problem anyway.

In a nutshell

I’m just going to throw compute() out there again, because I think it’d be a really great way to get the values of other CSS properties:

button {
  /* self could be the default */
  border-radius: compute(height, self);
  /* inherit could work like inherit() */
  border-radius: compute(height, inherit);
  /* Nice to have, but not as important */
  border-radius: compute(height, #this);
}

But if it’s just not possible, I really like the idea of introducing more currentColor-like keywords. With the exception of keywords like from-font where the font maker provides the value (or not, sigh), keywords such as currentWidth and currentHeight would be incredibly useful. They’d make CSS easier to read, and we wouldn’t have to create as many custom properties.

In the meantime though, custom properties, aspect-ratio, and certain CSS units can help us in the right circumstances, not to mention that we’ll be getting inherit() in the future. These are heavily geared towards getting widths and heights, which is fine because that’s undoubtedly the biggest problem here, but hopefully there are more CSS features on the horizon that allow values to be used in more places.


On Inheriting and Sharing Property Values originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Sunday, November 23, 2025

Rain today!



With a high of F and a low of 36F. Currently, it's 42F and Cloudy outside.

Current wind speeds: 6 from the East

Pollen: 0

Sunrise: November 23, 2025 at 07:44PM

Sunset: November 24, 2025 at 05:32AM

UV index: 0

Humidity: 92%

via https://ift.tt/JMBtjEZ

November 24, 2025 at 10:02AM

Saturday, November 22, 2025

Mostly Clear today!



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

Current wind speeds: 4 from the Southwest

Pollen: 0

Sunrise: November 22, 2025 at 07:43PM

Sunset: November 23, 2025 at 05:32AM

UV index: 0

Humidity: 79%

via https://ift.tt/qmTfh9R

November 23, 2025 at 10:02AM

Friday, November 21, 2025

Mostly Clear today!



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

Current wind speeds: 6 from the Southwest

Pollen: 0

Sunrise: November 21, 2025 at 07:42PM

Sunset: November 22, 2025 at 05:32AM

UV index: 0

Humidity: 94%

via https://ift.tt/PAEX8MY

November 22, 2025 at 10:02AM

Sketch: A guided tour of Copenhagen

Sketch is getting a massive UI overhaul, codenamed Copenhagen:

Our latest update — Copenhagen — features a major redesign of Sketch’s UI. Redesigns like this don’t happen often. In fact, our last one was in 2020, when Apple launched macOS Big Sur.

Makes a lot of sense for an app that’s so tightly integrated to Mac to design around the macOS UI. Big Sur was a big update. Apple called it the biggest one since Mac OS X. So big, indeed, that they renamed Mac OS to macOS in the process. Now we have macOS Tahoe and while it isn’t billed the “biggest update since Big Sur” it does lean into an entirely new Liquid Glass aesthetic that many are calling the biggest design update to the Apple ecosystem since iOS 7.

Sketch probably didn’t “have” to redesign its UI to line up with macOS Tahoe, but a big part of its appeal is the fact that it feels like it totally belongs to the Mac. It’s the same for Panic apps.

The blog post I linked to sheds a good amount of light on the Sketch team’s approach to the updates. I came to the blog post to read about the attention they put into new features (individual page and frame link for the win!) and tightening up existing ones (that layer list looks nice), but what I really stayed for was their approach to Liquid Glass. Turns out they decided to respect it, but split lanes a bit:

Early on in the process, we prototyped various approaches to the sidebar and Inspector, including floating options (the new default in Tahoe) and glass materials. Ultimately, we went custom here, with fixed sidebars that felt less distracting in the context of a canvas-based design tool.

Spend a few seconds with an early prototype that leaned more heavily into Liquid Glass and it’s uber clear why a custom route was the best lane choice:

Showing two translucent columns on the right and left of an app window containing a full-width grid of color tiles. The tiles show through the columns, distorting the UI.
Still taken from one of the blog post’s embedded videos

Choosing a design editor can feel personal, can’t it? I know lots of folks are in the Figma Or Bust camp. Illustrator is still the favorite child for many, after all these… decades! There’s a lot of buzz around Affinity now that it’s totally free. I adopted Sketch a long time ago. How long? I dug up this dusty old blog post I wrote about Sketch 3 back in 2014, so at least 11 years.

But I’m more of a transient in the design editor space. Being a contractor and all, I have to be open to any app my clients might use internally, regardless of my personal preference. I’d brush up on Sketch’s UI updates even if it wasn’t my go-to.


Sketch: A guided tour of Copenhagen originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Thursday, November 20, 2025

Rain today!



With a high of F and a low of 34F. Currently, it's 40F and Rain Shower outside.

Current wind speeds: 12 from the Northeast

Pollen: 0

Sunrise: November 20, 2025 at 07:41PM

Sunset: November 21, 2025 at 05:33AM

UV index: 0

Humidity: 99%

via https://ift.tt/e2BMCwZ

November 21, 2025 at 10:02AM

Should We Even Have :closed?

For the past few months, I’ve been writing a lot of entries on pseudo-selectors in CSS, like ::picker() or ::checkmark. And, in the process, I noticed I tend to use the :open pseudo-selector a lot in my examples — and in my work in general.

Borrowing words from the fine author of the :open entry in the Almanac:

The CSS :open pseudo-selector targets elements that support open and closed states — such as the <details> and <select> elements — and selects them in their open state.

So, given this:

details:open {
  background: lightblue;
  color: darkred;
}

We expect that the <details> element gets a light blue background and dark red text when it is in an open state (everywhere but Safari at the time I’m writing this):

But what if we want to select the “closed” state instead? That’s what we have the:closed pseudo-class for, right? It’s supposed to match an element’s closed state. I say, supposed because it’s not specced yet.

But does it need to be specced at all? I only ask because we can still target an element’s closed state without it using :not():

/* When details is _not_ open, but closed */
details:not(:open) {
  /* ... */
}

So, again: do we really need a :closed pseudo-class? The answer may surprise you! (Just kidding, this isn’t that sort of article…)

Some background

Talks surrounding :open started in May 2022 when Mason Freed raised the issue of adding :open (which was also considered being named :top-layer at the time) to target elements in the top layer (like popups):

Today, the OpenUI WC similarly resolved to add a :top-layer pseudo class that should apply to (at least) elements using the Popup API which are currently in the top layer. The intention for the naming and behavior, though, was that this pseudo class should also be general purpose. It should match any type of element in the top layer, including modal <dialog>, fullscreen elements, and ::backdrop pseudo elements.

This sparked discourse on whether the name of the pseudo-element targeting the top layer of any type of element (e.g., popups, pickers, etc.) should either be :open or :top-layer. I, for one, was thrilled when the CSSWG eventually decided on :open in August 2022. The name makes a lot more sense to me because “open” assumes something in the top layer.

To :close or :not(:open)?

Hold on, though! In September that same year, Mason asked whether or not we should have something like a :closed pseudo-class to accompany :open. That way, we can match elements in their “closed” states just as we can their “open” states. That makes a lot of sense, t least on the surface. Tab Atkins chimed in:

I love this definition, as I think it captures a concept of “openness” that lines up with what most developers think “open” means. I also think it makes it relatively straightforward for HTML to connect it to specific elements.

What do folks think?

Should we also talk about adding the corresponding :closed pseudo class? That would avoid the problem that :not(:open) can match anything, including things that don’t open or close.

And guess what? Everyone seemed to agree. Why? Because it made sense at the time. I mean, since we have a pseudo-class that targets elements in their :open state, surely it makes sense to have :closed to target elements in their closed states, right? Right??

No. There’s actually an issue with that line of reasoning. Joey Arhar made a comment about it in October that same year:

I opened a new issue about :closed because this doesn’t have consensus yet (#11039).

Wait, what happened to consensus? It’s the same question I raised at the top of this post. According to Luke Warlow:

Making :closed match things that can never be open feels odd. And would essentially make it :not(:open) in which case do we even need :closed? Like we don’t have a :popover-closed because it’s the inverse of :popover-open.

There is no :closed… for now

Fast forward one more month to November 2024. A consensus was made to start out with just :open and remove :closed for the time being.

Dang. Nevertheless, according to WHATWG and CSSWG, that decision could change in the future. In fact, Bramus dropped a useful note in there just a month before WHATWG made the decision:

Just dropping this as an FYI: :read-only is defined as :not(:read-write), and that shipped.

Which do you find easier to understand?

Personally, I’m okay with :closed — or even using :not(:open) — so far as it works. In fact, I went ahead swapped :closed for :not(:open) in my  ::checkmark and ::picker() examples. That’s why they are they way they are today.

But! If you were to ask me which one comes easier to me on a typical day, I think I would say :closed. It’s easier for to think in literal terms than negated statements.

What do you think, though? Would you prefer having :closed or just leaving it as :not(:open)?

If you’re like me and you love following discussions like this, you can always head over to CSSWG drafts on GitHub to watch or participate in the fun.


Should We Even Have :closed? originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Wednesday, November 19, 2025

Partly Cloudy today!



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

Current wind speeds: 5 from the Southeast

Pollen: 0

Sunrise: November 19, 2025 at 07:40PM

Sunset: November 20, 2025 at 05:34AM

UV index: 0

Humidity: 63%

via https://ift.tt/EMcZbX7

November 20, 2025 at 10:02AM

Tuesday, November 18, 2025

Partly Cloudy today!



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

Current wind speeds: 8 from the Southeast

Pollen: 0

Sunrise: November 18, 2025 at 07:39PM

Sunset: November 19, 2025 at 05:34AM

UV index: 0

Humidity: 59%

via https://ift.tt/oyKIdVq

November 19, 2025 at 10:02AM

Monday, November 17, 2025

Clear today!



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

Current wind speeds: 8 from the Northwest

Pollen: 0

Sunrise: November 17, 2025 at 07:37PM

Sunset: November 18, 2025 at 05:35AM

UV index: 0

Humidity: 53%

via https://ift.tt/dhWxCfo

November 18, 2025 at 10:02AM

The “Most Hated” CSS Feature: asin(), acos(), atan() and atan2()

This is a series! It all started a couple of articles ago, when we found out that, according to the State of CSS 2025 survey, trigonometric functions were the “Most Hated” CSS feature.

Most Hated Feature: trigonometric functions

I’ve been trying to change that perspective, so I showcased several uses for trigonometric functions in CSS: one for sin() and cos() and another on tan(). However, that’s only half of what trigonometric functions can do. So today, we’ll poke at the inverse world of trigonometric functions: asin()acos()atan() and atan2().

CSS Trigonometric Functions: The “Most Hated” CSS Feature

  1. sin() and cos()
  2. tan()
  3. asin()acos()atan() and atan2() (You are here!)

Inverse functions?

Recapping things a bit, given an angle, the sin()cos() and tan() functions return a ratio presenting the sine, cosine, and tangent of that angle, respectively. And if you read the last two parts of the series, then you already know what each of those quantities represents.

What if we wanted to go the other way around? If we have a ratio that represents the sine, cosine or tangent of an angle, how can we get the original angle? This is where inverse trigonometric functions come in! Each inverse function asks what the necessary angle is to get a given value for a specific trigonometric function; in other words, it undoes the original trigonometric function. So…

  • acos() is the inverse of cos(),
  • asin() is the inverse of sin(), and
  • atan() and atan2() are the inverse of tan().

They are also called “arcus” functions and written as arcos()arcsin() and arctan() in most places. This is because, in a circle, each angle corresponds to an arc in the circumference.

The length of this arc is the angle times the circle’s radius. Since trigonometric functions live in a unit circle, where the radius is equal to 1, the arc length is also the angle, expressed in radians.

Their mathy definitions are a little boring, to say the least, but they are straightforward:

  • y = acos(x) such that x = cos(y)
  • y = asin(x) such that x = sin(y)
  • y = atan(x) such that x = tan(y)

acos() and asin()

Using acos() and asin(), we can undo cos(θ) and sin(θ) to get the starting angle, θ. However, if we try to graph them, we’ll notice something odd:

acos() and asin() graphed. The inverse sine curve crosses the x-axis at -1 and 1. The inverse cosine curve also crosses at -1 and 1.

The functions are only defined from -1 to 1!

Remember, cos() and sin() can take any angle, but they will always return a number between -1 and 1. For example, both cos(90°) and cos(270°) (not to mention others) return 0, so which value should acos(0) return? To answer this, both acos() and asin() have their domain (their input) and range (their output) restricted:

  • acos() can only take numbers between -1 and 1 and return angles between  and 180°.
  • asin() can only take numbers between -1 and 1 and return angles between -90° and 90°.

This limits a lot of the situations where we can use acos() and asin(), since something like asin(1.2) doesn’t work in CSS* — according to the spec, going outside acos() and asin() domain returns NaN — which leads us to our next inverse function…

atan() and atan2()

Similarly, using atan(), we can undo tan(θ) to get θ. But, unlike asin() and acos(), if we graph it, we’ll notice a big difference:

atan() graphed. The curve's midpoint is positioned at 0 and 0, and the curve extends infinitely in the X direction.

This time it is defined on the whole number line! This makes sense since tan() can return any number between -Infinity and Infinity, so atan() is defined in that domain.

atan() can take any number between -Infinity and Infinity and returns angles -90° and 90°.

This makes atan() incredibly useful to find angles in all kinds of situations, and a lot more versatile than acos() and asin(). That’s why we’ll be using it, along atan2(), going forward. Although don’t worry about atan2() for now, we’ll get to it later.

Finding the perfect angle

In the last article, we worked a lot with triangles. Specifically, we used the tan() function to find one of the sides of a right-angled triangle from the following relationships:

The tangent of theta is equal to the opposite side divided by the adjacent side.

To make it work, we needed to know one of its sides and the angle, and by solving the equation, we would get the other side. However, in most cases, we do know the lengths of the triangle’s sides and what we are actually looking for is the angle. In that case, the last equation becomes:

Theta is equal to the atan of opposite side divided by the adjacent side.

Triangles and Conic Gradients

Finding the angle comes in handy in lots of cases, like in gradients, for instance. In a linear gradient, for example, if we want it to go from corner to corner, we’ll have to match the gradient’s angle depending on the element’s dimensions. Otherwise, with a fixed angle, the gradient won’t change if the element gets resized:

.gradient {
  background: repeating-linear-gradient(ghostwhite 0px 25px, darkslategray 25px 50px);
}

This may be the desired look, but I think that most often than not, you want it to match the element’s dimensions.

Using linear-gradient(), we can easily solve this using to top right or to bottom left values for the angle, which automatically sets the angle so the gradient goes from corner to corner.

.gradient {
  background: repeating-linear-gradient(to top right, ghostwhite 0px 25px, darkslategray 25px 50px);
}

However, we don’t have that type of syntax for other gradients, like a conic-gradient(). For example, the next conic gradient has a fixed angle and won’t change upon resizing the element.

.gradient {
  background: conic-gradient(from 45deg, #84a59d 180deg, #f28482 180deg);
}

Luckily, we can fix this using atan()! We can look at the gradient as a right-angled triangle, where the width is the adjacent side and the height the opposite side:

A square bisected diagonally from the bottom-left corner to the top-right corner, creating two right triangles. The theta angle is labeled in the bottom-left corner and the width is labeled along the bottom edge.

Then, we can get the angle using this formula:

.gradient {
  --angle: atan(var(--height-gradient) / var(--width-gradient));
}

Since conic-gradient() starts from the top edge — conic-gradient(from 0deg) — we’ll have to shift it by 90deg to make it work.

.gradient {
  --rotation: calc(90deg - var(--angle));
  background: conic-gradient(from var(--rotation), #84a59d 180deg, #f28482 180deg);
}

You may be wondering: can’t we do that with a linear gradient? And the answer is, yes! But this was just an example to showcase atan(). Let’s move on to more interesting stuff that’s unique to conic gradients.

I got the next example from Ana Tudor’s post on “Variable Aspect Ratio Card With Conic Gradients”:

Pretty cool, right?. Sadly, Ana’s post is from 2021, a time when trigonometric functions were specced out but not implemented. As she mentions in her article, it wasn’t possible to create these gradients using atan(). Luckily, we live in the future! Let’s see how simple they become with trigonometry and CSS.

We’ll use two conic gradients, each of them covering half of the card’s background.

A square bisected in the middle with a diagonal line going from the top-right corner to the bottom-left, creating two right triangles, each with a different conic gradient applied to it.

To save time, I’ll gloss over exactly how to make the original gradient, so here is a quick little step-by-step guide on how to make one of those gradients in a square-shaped element:

Since we’re working with a perfect square, we can fix the --angle and --rotation to be 45deg, but for a general use case, each of the conic-gradients would look like this in CSS:

.gradient {
  background: 
    /* one below */
    conic-gradient(
      from var(--rotation) at bottom left,
      #b9eee1 calc(var(--angle) * 1 / 3),
      #79d3be calc(var(--angle) * 1 / 3) calc(var(--angle) * 2 / 3),
      #39b89a calc(var(--angle) * 2 / 3) calc(var(--angle) * 3 / 3),
      transparent var(--angle)
    ),
    /* one above */
    conic-gradient(
      from calc(var(--rotation) + 180deg) at top right,
      #fec9d7 calc(var(--angle) * 1 / 3),
      #ff91ad calc(var(--angle) * 1 / 3) calc(var(--angle) * 2 / 3),
      #ff5883 calc(var(--angle) * 2 / 3) calc(var(--angle) * 3 / 3),
      transparent var(--angle)
    );
}

And we can get those --angle and --rotation variables the same way we did earlier — using atan(), of course!

.gradient {
  --angle: atan(var(--height-gradient) / var(--width-gradient));
  --rotation: calc(90deg - var(--angle));
}

What about atan2()?

The last example was all abou atan(), but I told you we would also look at the atan2() function. With atan(), we get the angle when we divide the opposite side by the adjacent side and pass that value as the argument. On the flip side, atan2() takes them as separate arguments:

  • atan(opposite/adjacent)
  • atan2(opposite, adjacent)

What’s the difference? To explain, let’s backtrack a bit.

We used atan() in the context of triangles, meaning that the adjacent and opposite sides were always positive. This may seem like an obvious thing since lengths are always positive, but we won’t always work with lengths.

Imagine we are in a x-y plane and pick a random point on the graph. Just by looking at its position, we can know its x and y coordinates, which can have both negative and positive coordinates. What if we wanted its angle instead? Measuring it, of course, from the positive x-axis.

Showing a coordinate located at 3, 2 on an x-y graph. A line is drawn between it and the center point located at 0, 0, and the angle of the line is labeled as theta.

Well, remember from the last article in this series that we can also define tan() as the quotient between sin() and cos():

The tangent of an angle is equal to the sine of the angle divided by the cosine of the angle.

Also recall that when we measure the angle from the positive x-axis, then sin() returns the y-coordinate and cos() returns the x-coordinate. So, the last formula becomes:

The tangent of an angle equals the y coordinate divided by the x coordinate.

And applying atan(), we can directly get the angle!

And angle is equal to the a-tangent times the value of the y-coordinate divided by the x-coordinate.

This formula has one problem, though. It should work for any point in the x-y plane, and since both x and y can be negative, we can confuse some points. Since we are dividing the y-coordinate by the x-coordinate, in the eyes of atan(), the negative y-coordinate looks the same as the negative x-coordinate. And if both coordinates are negative, it would look the same as if both were positive.

The negative y-coordinate divided by the negative x-coordinate is equal to the y-coordinate divided by the x-coordinate. Also, the negative y-coordinate divided by the x-coordxinate is equal to the y-coordinate divided by the negative x-coordinate.

To compensate for this, we have atan2(), and since it takes the y-coordinate and x-coordinate as separate arguments, it’s smart enough to return the angle everywhere in the plane!

Let’s see how we can put it to practical use.

Following the mouse

Using atan2(), we can make elements react to the mouse’s position. Why would we want to do that? Meet my friend Helpy, Clippy’s uglier brother from Microsoft.

Helpy wants to always be looking at the user’s mouse, and luckily, we can help him using atan2(). I won’t go into too much detail about how Helpy is made, just know that his eyes are two pseudo-elements:

.helpy::before,
.helpy::after {
  /* eye styling */
}

To help Helpy, we first need to let CSS know the mouse’s current x-y coordinates. And while I may not like using JavaScript here, it’s needed in order to pass the mouse coordinates to CSS as two custom properties that we’ll call --m-x and --m-y.

const body = document.querySelector("body");

// listen for the mouse pointer
body.addEventListener("pointermove", (event) => {
  // set variables for the pointer's current coordinates
  let x = event.clientX;
  let y = event.clientY;

  // assign those coordinates to CSS custom properties in pixel units
  body.style.setProperty("--m-x", `${Math.round(x)}px`);
  body.style.setProperty("--m-y", `${Math.round(y)}px`);
});

Helpy is currently looking away from the content, so we’ll first move his eyes so they align with the positive x-axis, i.e., to the right.

.helpy::before,
.helpy::after {
  rotate: 135deg;
}

Once there, we can use atan2() to find the exact angle Helpy has to turn so he sees the user’s mouse. Since Helpy is positioned at the top-left corner of the page, and the x and y coordinates are measured from there, it’s time to plug those coordinates into our function: atan2(var(--m-y), var(--m-x)).

.helpy::before,
.helpy::after {
  /* rotate the eyes by it's starting position, plus the atan2 of the coordinates */
  rotate: calc(135deg + atan2(var(--m-y), var(--m-x)));
}

We can make one last improvement. You’ll notice that if the mouse goes on the little gap behind Helpy, he is unable to look at the pointer. This happens because we are measuring the coordinates exactly from the top-left corner, and Helpy is positioned a little bit away from that.

To fix this, we can translate the origin of the coordinate system directly on Helpy by subtracting the padding and half its size:

Showing the range of Helpy's eyesight, going from left-to-right to top-to-bottom. A diagonal line bisects that range revealing an angle that is labeled theta.

Which looks like this in CSS:

.helpy::before,
.helpy::after  {
  rotate: calc(
    135deg +
      atan2(
        var(--m-y) - var(--spacing) - var(--helpy-size) / 2,
        var(--m-x) - var(--spacing) - var(--helpy-size) / 2
      )
  );
}

This is a somewhat minor improvement, but moving the coordinate origin will be vital if we want to place Helpy in any other place on the screen.

Extra: Getting the viewport (and anything) in numbers

I can’t finish this series without mentioning a trick to typecast different units into simple numbers using atan2() and tan(). It isn’t directly related to trigonometry but it’s still super useful. It was first described amazingly by Jane Ori in 2023, and goes as follows.

If we want to get the viewport as an integer, then we can…

@property --100vw {
  syntax: "<length>;";
  initial-value: 0px;
  inherits: false;
}

:root {
  --100vw: 100vw;
  --int-width: calc(10000 * tan(atan2(var(--100vw), 10000px)));
}

And now: the --int-width variable holds the viewport width as an integer. This looks like magic, so I really recommend reading Jane Ori’s post to understand it. I also have an article using it to create animations as the viewport is resized!

What about reciprocals?

I noticed that we are still lacking the reciprocals for each trigonometric function. The reciprocals are merely 1 divided by the function, so there’s a total of three of them:

  • The secant, or sec(x), is the reciprocal of cos(x), so it’s 1 / cos(x).
  • The cosecant, or csc(x), is the reciprocal of sin(x), so it’s 1 / sin(x).
  • The cotangent, or cot(x) is the reciprocal of tan(x), so it’s 1 / tan(x).

The beauty of sin()cos() and tan() and their reciprocals is that they all live in the unit circle we’ve looked at in other articles in this series. I decided to put everything together in the following demo that shows all of the trigonometric functions covered on the same unit circle:

That’s it!

Welp, that’s it! I hope you learned and had fun with this series just as much as I enjoyed writing it. And thanks so much for those of you who have shared your own demos. I’ll be rounding them up in my Bluesky page.

CSS Trigonometric Functions: The “Most Hated” CSS Feature

  1. sin() and cos()
  2. tan()
  3. asin()acos()atan() and atan2() (You are here!)

The “Most Hated” CSS Feature: asin(), acos(), atan() and atan2() originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Sunday, November 16, 2025

Partly Cloudy today!



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

Current wind speeds: 16 from the Southeast

Pollen: 0

Sunrise: November 16, 2025 at 07:36PM

Sunset: November 17, 2025 at 05:36AM

UV index: 0

Humidity: 59%

via https://ift.tt/IuX7eK5

November 17, 2025 at 10:02AM

Saturday, November 15, 2025

Clear today!



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

Current wind speeds: 7 from the South

Pollen: 0

Sunrise: November 15, 2025 at 07:35PM

Sunset: November 16, 2025 at 05:36AM

UV index: 0

Humidity: 58%

via https://ift.tt/YGxlqsj

November 16, 2025 at 10:02AM

Friday, November 14, 2025

Partly Cloudy today!



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

Current wind speeds: 8 from the Southwest

Pollen: 0

Sunrise: November 14, 2025 at 07:34PM

Sunset: November 15, 2025 at 05:37AM

UV index: 0

Humidity: 31%

via https://ift.tt/w7bXRJZ

November 15, 2025 at 10:02AM

Quiet UI Came and Went, Quiet as a Mouse

A few weeks ago, Quiet UI made the rounds when it was released as an open source user interface library, built with JavaScript web components. I had the opportunity to check out the documentation and it seemed like a solid library. I’m always super excited to see more options for web components out in the wild.

Unfortunately, before we even had a chance to cover it here at CSS-Tricks, Quiet UI has disappeared. When visiting the Quiet UI website, there is a simple statement:

Unavailable

Quiet UI is no longer available to the general public. I will continue to maintain it as my personal creative outlet, but I am unable to release it to the world at this time.
Thanks for understanding. I’m really sorry for the inconvenience.

The repository for Quiet UI is no longer available on Quiet UI’s GitHub, and its social accounts seem to have been removed as well.

The creator, Cory LaViska, is a veteran of UI libraries and most known for work on Shoelace. Shoelace joined Font Awesome in 2022 and was rebranded as Web Awesome. The latest version of Web Awesome was released around the same time Quiet UI was originally announced.

According to the Quiet UI site, Cory will be continuing to work on it as a personal creative outlet, but hopefully we’ll be able to see what he’s cooking up again, someday. In the meantime, you can get a really good taste of what the project is/was all about in Dave Rupert’s fantastic write-up.


Quiet UI Came and Went, Quiet as a Mouse originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Thursday, November 13, 2025

Clear today!



With a high of F and a low of 41F. Currently, it's 45F and Clear outside.

Current wind speeds: 7 from the Southwest

Pollen: 0

Sunrise: November 13, 2025 at 07:33PM

Sunset: November 14, 2025 at 05:38AM

UV index: 0

Humidity: 38%

via https://ift.tt/6r92mBp

November 14, 2025 at 10:02AM

The Range Syntax Has Come to Container Style Queries and if()

The range syntax isn’t a new thing. We‘re already able to use it with media queries to query viewport dimensions and resolutions, as well as container size queries to query container dimensions. Being able to use it with container style queries — which we can do starting with Chrome 142 — means that we can compare literal numeric values as well as numeric values tokenized by custom properties or the attr() function.

In addition, this feature comes to the if() function as well.

Here’s a quick demo that shows the range syntax being used in both contexts to compare a custom property (--lightness) to a literal value (50%):

#container {
  /* Choose any value 0-100% */
  --lightness: 10%;

  /* Applies it to the background */
  background: hsl(270 100% var(--lightness));

  color: if(
    /* If --lightness is less than 50%, white text */
    style(--lightness < 50%): white;
    /* If --lightness is more than or equal to 50%, black text */
    style(--lightness >= 50%): black
  );

  /* Selects the children */
  * {
    /* Specifically queries parents */
    @container style(--lightness < 50%) {
      color: white;
    }

    @container style(--lightness >= 50%) {
      color: black;
    }
  }
}

Again, you’ll want Chrome 142 or higher to see this work:

Both methods do the same thing but in slightly different ways.

Let’s take a closer look.

Range syntax with custom properties

In the next demo coming up, I’ve cut out the if() stuff, leaving only the container style queries. What’s happening here is that we’ve created a custom property called --lightness on the #container. Querying the value of an ordinary property isn’t possible, so instead we save it (or a part of it) as a custom property, and then use it to form the HSL-formatted value of the background.

#container {
  /* Choose any value 0-100% */
  --lightness: 10%;

  /* Applies it to the background */
  background: hsl(270 100% var(--lightness));
}

After that we select the container’s children and conditionally declare their color using container style queries. Specifically, if the --lightness property of #container (and, by extension, the background) is less than 50%, we set the color to white. Or, if it’s more than or equal to 50%, we set the color to black.

#container {
  /* etc. */

  /* Selects the children */
  * {
    /* Specifically queries parents */
    @container style(--lightness < 50%) {
      color: white;
    }

    @container style(--lightness >= 50%) {
      color: black;
    }
  }
}

/explanation Note that we wouldn’t be able to move the @container at-rules to the #container block, because then we’d be querying --lightness on the container of #container (where it doesn’t exist) and then beyond (where it also doesn’t exist).

Prior to the range syntax coming to container style queries, we could only query specific values, so the range syntax makes container style queries much more useful.

By contrast, the if()-based declaration would work in either block:

#container {
  --lightness: 10%;
  background: hsl(270 100% var(--lightness));

  /* --lightness works here */
  color: if(
    style(--lightness < 50%): white;
    style(--lightness >= 50%): black
  );

  * {
    /* And here! */
    color: if(
      style(--lightness < 50%): white;
      style(--lightness >= 50%): black
    );
  }
}

So, given that container style queries only look up the cascade (whereas if() also looks for custom properties declared within the same CSS rule) why use container style queries at all? Well, personal preference aside, container queries allow us to define a specific containment context using the container-name CSS property:

#container {
  --lightness: 10%;
  background: hsl(270 100% var(--lightness));

  /* Define a named containment context */
  container-name: myContainer;

  * {
    /* Specify the name here */
    @container myContainer style(--lightness < 50%) {
      color: white;
    }

    @container myContainer style(--lightness >= 50%) {
      color: black;
    }
  }
}

With this version, if the @container at-rule can’t find --lightness on myContainer, the block doesn’t run. If we wanted @container to look further up the cascade, we’d only need to declare container-name: myContainer further up the cascade. The if() function doesn’t allow for this, but container queries allow us to control the scope.

Range syntax with the attr() CSS function

We can also pull values from HTML attributes using the attr() CSS function.

In the HTML below, I’ve created an element with a data attribute called data-notifs whose value represents the number of unread notifications that a user has:

<div data-notifs="8"></div>

We want to select [data-notifs]::after so that we can place the number inside [data-notifs] using the content CSS property. In turn, this is where we’ll put the @container at-rules, with [data-notifs] serving as the container. I’ve also included a height and matching border-radius for styling:

[data-notifs]::after {
  height: 1.25rem;
  border-radius: 1.25rem;

  /* Container style queries here */
}

Now for the container style query logic. In the first one, it’s fairly obvious that if the notification count is 1-2 digits (or, as it’s expressed in the query, less than or equal to 99), then content: attr(data-notifs) inserts the number from the data-notifs attribute while aspect-ratio: 1 / 1 ensures that the width matches the height, forming a circular notification badge.

In the second query, which matches if the number is more than 99, we switch to content: "99+" because I don’t think that a notification badge could handle four digits. We also include some inline padding instead of a width, since not even three characters can fit into the circle.

To summarize, we’re basically using this container style query logic to determine both content and style, which is really cool:

[data-notifs]::after {
  height: 1.25rem;
  border-radius: 1.25rem;

  /* If notification count is 1-2 digits */
  @container style(attr(data-notifs type(<number>)) <= 99) {

    /* Display count */
    content: attr(data-notifs);

    /* Make width equal the height */
    aspect-ratio: 1 / 1;
  }

  /* If notification count is 3 or more digits */
  @container style(attr(data-notifs type(<number>)) > 99) {
    /* After 99, simply say "99+" */
    content: "99+";

    /* Instead of width, a little padding */
    padding-inline: 0.1875rem;
  }
}

But you’re likely wondering why, when we read the value in the container style queries, it’s written as attr(data-notifs type(<number>) instead of attr(data-notifs). Well, the reason is that when we don’t specify a data type (or unit, you can read all about the recent changes to attr() here), the value is parsed as a string. This is fine when we’re outputting the value with content: attr(data-notifs), but when we’re comparing it to 99, we must parse it as a number (although type(<integer>) would also work).

In fact, all range syntax comparatives must be of the same data type (although they don’t have to use the same units). Supported data types include <length>, <number>, <percentage>, <angle>, <time>, <frequency>, and <resolution>. In the earlier example, we could actually express the lightness without units since the modern hsl() syntax supports that, but we’d have to be consistent with it and ensure that all comparatives are unit-less too:

#container {
  /* 10, not 10% */
  --lightness: 10;

  background: hsl(270 100 var(--lightness));

  color: if(
    /* 50, not 50% */
    style(--lightness < 50): white;
    style(--lightness >= 50): black
  );

  * {
    /* 50, not 50% */
    @container style(--lightness < 50) {
      color: white;
    }

    @container style(--lightness >= 50) {
      color: black;
    }
  }
}

Note: This notification count example doesn’t lend itself well to if(), as you’d need to include the logic for every relevant CSS property, but it is possible and would use the same logic.

Range syntax with literal values

We can also compare literal values, for example, 1em to 32px. Yes, they’re different units, but remember, they only have to be the same data type and these are both valid CSS <length>s.

In the next example, we set the font-size of the <h1> element to 31px. The <span> inherits this font-size, and since 1em is equal to the font-size of the parent, 1em in the scope of <span> is also 31px. With me so far?

According to the if() logic, if 1em is equal to less than 32px, the font-weight is smaller (to be exaggerative, let’s say 100), whereas if 1em is equal to or greater than 32px, we set the font-weight to a chunky 900. If we remove the font-size declaration, then 1em computes to the user agent default of 32px, and neither condition matches, leaving the font-weight to also compute to the user agent default, which for all headings is 700.

Basically, the idea is that if we mess with the default font-size of the <h1>, then we declare an optimized font-weight to maintain readability, preventing small-fat and large-thin text.

<h1>
  <span>Heading 1</span>
</h1>
h1 {
  /*
    The default value is 32px,
    but we overwrite it to 31px,
    causing the first if() condition to match
  */
  font-size: 31px;

  span {
    /* Here, 1em is equal to 31px */

    font-weight: if(
      style(1em < 32px): 100;
      style(1em > 32px): 900
    );
  }
}

CSS queries have come a long way, haven’t they?

In my opinion, the range syntax coming to container style queries and the if() function represents CSS’s biggest leap in terms of conditional logic, especially considering that it can be combined with media queries, feature queries, and other types of container queries (remember to declare container-type if combining with container size queries). In fact, now would be a great time to freshen up on queries, so as a little parting gift, here are some links for further reading:


The Range Syntax Has Come to Container Style Queries and if() originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Responsive List of Avatars Using Modern CSS (Part 2)

Ready for the second part? If you recall, last time we worked on a responsive list of overlapping avatar images featuring a cut-out between...