> All in One 586: April 2025

Ads

Wednesday, April 30, 2025

Mostly Cloudy today!



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

Current wind speeds: 16 from the Northwest

Pollen: 0

Sunrise: April 30, 2025 at 05:53PM

Sunset: May 1, 2025 at 07:44AM

UV index: 0

Humidity: 62%

via https://ift.tt/aHq2g5v

May 1, 2025 at 10:02AM

Revisiting Image Maps

I mentioned last time that I’ve been working on a new website for Emmy-award-winning game composer Mike Worth. He hired me to create a highly graphical design that showcases his work.

Mike loves ’90s animation, particularly Disney’s Duck Tales and other animated series. He challenged me to find a way to incorporate their retro ’90s style into his design without making it a pastiche. But that wasn’t my only challenge. I also needed to achieve that ’90s feel by using up-to-the-minute code to maintain accessibility, performance, responsiveness, and semantics.

Design by Andy Clarke, Stuff & Nonsense. Mike Worth’s website will launch in April 2025, but you can see examples from this article on CodePen.

Designing for Mike was like a trip back to when mainstream website design seemed more spontaneous and less governed by conventions and best practices. Some people describe these designs as “whimsical”:

adjective

  1. spontaneously fanciful or playful
  2. given to whims; capricious
  3. quaint, unusual, or fantastic

Collins English Dictionary

But I’m not so sure that’s entirely accurate. “Playful?” Definitely. “Fanciful?” Possibly. But “fantastic?” That depends. “Whimsy” sounds superfluous, so I call it “expressive” instead.

Studying design from way back, I remembered how websites often included graphics that combined branding, content, and navigation. Pretty much every reference to web design in the ’90s — when I designed my first website — talks about Warner Brothers’ Space Jam from 1996.

Space Jam website homepage. The movie logo is in the center of a series of planets that are navigation for other areas of the website against a dark starry background.
Warner Brothers’ Space Jam (1996)

So, I’m not going to do that.

Brands like Nintendo used their home pages to direct people to their content while making branded visual statements. Cheestrings combined graphics with navigation, making me wonder why we don’t see designs like this today. Goosebumps typified this approach, combining cartoon illustrations with brightly colored shapes into a functional and visually rich banner, proving that being useful doesn’t mean being boring.

Left to right: Nintendo, Cheestrings, Goosebumps.

In the ’90s, when I developed graphics for websites like these, I either sliced them up and put their parts in tables or used mostly forgotten image maps.

A brief overview of properties and values

Let’s run through a quick refresher. Image maps date all the way back to HTML 3.2, where, first, server-side maps and then client-side maps defined clickable regions over an image using map and area elements. They were popular for graphics, maps, and navigation, but their use declined with the rise of CSS, SVG, and JavaScript.

<map> adds clickable areas to a bitmap or vector image.

<map name="projects">
  ...
</map>

That <map> is linked to an image using the usemap attribute:

<img usemap="#projects" ...>

Those elements can have separate href and alt attributes and can be enhanced with ARIA to improve accessibility:

<map name="projects">
  <area href="" alt="" … />
  ...
</map>

The shape attribute specifies an area’s shape. It can be a primitive circle or rect or a polygon defined by a set of absolute x and y coordinates:

<area shape="circle" coords="..." ... />
<area shape="rect" coords="..." ... />
<area shape="poly" coords="..." ... />

Despite their age, image maps still offer plenty of benefits. They’re lightweight and need (almost) no JavaScript. More on that in just a minute. They’re accessible and semantic when used with alt, ARIA, and title attributes. Despite being from a different era, even modern mobile browsers support image maps.

A large illustrated map of a cartoon island.
Design by Andy Clarke, Stuff & Nonsense. Mike Worth’s website will launch in April 2025, but you can see examples from this article on CodePen.

My design for Mike Worth includes several graphic navigation elements, which made me wonder if image maps might still be an appropriate solution.

Image maps in action

Mike wants his website to showcase his past work and the projects he’d like to do. To make this aspect of his design discoverable and fun, I created a map for people to explore by pressing on areas of the map to open modals. This map contains numbered circles, and pressing one pops up its modal.

A large illustrated cartoon map of an island. 6 annotations are on the map and a tooltip is exposed showing detail of one of the annotations.

My first thought was to embed anchors into the external map SVG:

<img src="projects.svg" alt="Projects">

<svg ...>
  ...
  <a href="...">
    <circle cx="35" cy="35" r="35" fill="#941B2F"/>
    <path fill="#FFF" d="..."/>
  </a>
</svg>

This approach is problematic. Those anchors are only active when SVG is inline and don’t work with an <img> element. But image maps work perfectly, even though specifying their coordinates can be laborious. Fortunately, plenty of tools are available, which make defining coordinates less tedious. Upload an image, choose shape types, draw the shapes, and copy the markup:

<img src="projects.svg" usemap="#projects-map.svg">

<map name="projects-map.svg">
  <area href="" alt="" coords="..." shape="circle">
  <area href="" alt="" coords="..." shape="circle">
  ...
</map>

Image maps work well when images are fixed sizes, but flexible images present a problem because map coordinates are absolute, not relative to an image’s dimensions. Making image maps responsive needs a little JavaScript to recalculate those coordinates when the image changes size:

function resizeMap() {
  const image = document.getElementById("projects");
  const map = document.querySelector("map[name='projects-map']");
  
  if (!image || !map || !image.naturalWidth) return;
  
  const scale = image.clientWidth / image.naturalWidth;
  map.querySelectorAll("area").forEach(area => {
  
    if (!area.dataset.originalCoords) {
      area.dataset.originalCoords = area.getAttribute("coords");
    }

    const scaledCoords = area.dataset.originalCoords
    
    .split(",")
    .map(coord => Math.round(coord * scale))
    .join(",");
    area.setAttribute("coords", scaledCoords);
  });
}

["load", "resize"].forEach(event =>
  window.addEventListener(event, resizeMap)
);

I still wasn’t happy with this implementation as I wanted someone to be able to press on much larger map areas, not just the numbered circles.

Every <path> has coordinates which define how it’s drawn, and they’re relative to the SVG viewBox:

<svg width="1024" height="1024">
  <path fill="#BFBFBF" d="…"/>
</svg>

On the other hand, a map’s <area> coordinates are absolute to the top-left of an image, so <path> values need to be converted. Fortunately, Raphael Monnerat has written PathToPoints, a tool which does precisely that. Upload an SVG, choose the point frequency, copy the coordinates for each path, and add them to a map area’s coords:

<map>
  <area href="" shape="poly" coords="...">
  <area href="" shape="poly" coords="...">
  <area href="" shape="poly" coords="...">
  ...
</map>

More issues with image maps

Image maps are hard-coded and time-consuming to create without tools. Even with tools for generating image maps, converting paths to points, and then recalculating them using JavaScript, they could be challenging to maintain at scale.

<area> elements aren’t visible, and except for a change in the cursor, they provide no visual feedback when someone hovers over or presses a link. Plus, there’s no easy way to add animations or interaction effects.

But the deal-breaker for me was that an image map’s pixel-based values are unresponsive by default. So, what might be an alternative solution for implementing my map using CSS, HTML, and SVG?

A large illustrated map of a cartoon island cut out against a transparent background.

Anchors positioned absolutely over my map wouldn’t solve the pixel-based positioning problem or give me the irregular-shaped clickable areas I wanted. Anchors within an external SVG wouldn’t work either.

But the solution was staring me in the face. I realized I needed to:

  1. Create a new SVG path for each clickable area.
  2. Make those paths invisible.
  3. Wrap each path inside an anchor.
  4. Place the anchors below other elements at the end of my SVG source.
  5. Replace that external file with inline SVG.
The same illustrated map of an island but the six regions are represented by solid colors.

I created a set of six much larger paths which define the clickable areas, each with its own fill to match its numbered circle. I placed each anchor at the end of my SVG source:

<svg … viewBox="0 0 1024 1024">

  <!-- Visible content -->
  <g>...</g>

  <!-- Clickable areas -->`
  <g id="links">`
    <a href="..."><path fill="#B48F4C" d="..."/></a>`
    <a href="..."><path fill="#6FA676" d="..."/></a>`
    <a href="..."><path fill="#30201D" d="..."/></a>`
    ...
  </g>
</svg>

Then, I reduced those anchors’ opacity to 0 and added a short transition to their full-opacity hover state:

#links a {
  opacity: 0;
  transition: all .25s ease-in-out;
}

#links a:hover {
  opacity: 1;
}

While using an image map’s <area> sadly provides no visual feedback, embedded anchors and their content can respond to someone’s action, hint at what’s to come, and add detail and depth to a design.

The illustrated regions of the cartoon map in three states, from left to right: annotated, with visual markers, and with both visual markers and labels.

I might add gloss to those numbered circles to be consistent with the branding I’ve designed for Mike. Or, I could include images, titles, or other content to preview the pop-up modals:

<g id="links">
  <a href="…">
    <path fill="#B48F4C" d="..."/>
    <image href="..." ... />
  </a>
</g>

Try it for yourself:

Expressive design, modern techniques

Designing Mike Worth’s website gave me a chance to blend expressive design with modern development techniques, and revisiting image maps reminded me just how important a tool image maps were during the period Mike loves so much.

Ultimately, image maps weren’t the right tool for Mike’s website. But exploring them helped me understand what I really needed: a way to recapture the expressiveness and personality of ’90s website design using modern techniques that are accessible, lightweight, responsive, and semantic. That’s what design’s about: choosing the right tool for a job, even if that sometimes means looking back to move forward.


Biography: Andy Clarke

Often referred to as one of the pioneers of web design, Andy Clarke has been instrumental in pushing the boundaries of web design and is known for his creative and visually stunning designs. His work has inspired countless designers to explore the full potential of product and website design.

Andy’s written several industry-leading books, including Transcending CSS, Hardboiled Web Design, and Art Direction for the Web. He’s also worked with businesses of all sizes and industries to achieve their goals through design.

Visit Andy’s studio, Stuff & Nonsense, and check out his Contract Killer, the popular web design contract template trusted by thousands of web designers and developers.


Revisiting Image Maps originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Tuesday, April 29, 2025

Partly Cloudy today!



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

Current wind speeds: 9 from the South

Pollen: 0

Sunrise: April 29, 2025 at 05:55PM

Sunset: April 30, 2025 at 07:43AM

UV index: 0

Humidity: 59%

via https://ift.tt/0klVv36

April 30, 2025 at 10:02AM

Open Up With Brad Frost, Episode 2

Brad Frost is running this new little podcast called Open Up. Folks write in with questions about the “other” side of web design and front-end development — not so much about tools and best practices as it is about the things that surround the work we do, like what happens if you get laid off, or AI takes your job, or something along those lines. You know, the human side of what we do in web design and development.

Well, it just so happens that I’m co-hosting the show. In other words, I get to sprinkle in a little advice on top of the wonderful insights that Brad expertly doles out to audience questions.

Our second episode just published, and I thought I’d share it. We’re finding our sea legs with this whole thing and figuring things out as we go. We’ve opened things up (get it?!) to a live audience and even pulled in one of Brad’s friends at the end to talk about the changing nature of working on a team and what it looks like to collaborate in a remote-first world.

https://www.youtube.com/watch?v=bquVF5Cibaw

Open Up With Brad Frost, Episode 2 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Monday, April 28, 2025

Partly Cloudy/Wind today!



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

Current wind speeds: 17 from the North

Pollen: 0

Sunrise: April 28, 2025 at 05:56PM

Sunset: April 29, 2025 at 07:42AM

UV index: 0

Humidity: 65%

via https://ift.tt/L4GI7qO

April 29, 2025 at 10:02AM

Anchor Positioning Just Don’t Care About Source Order

Ten divs walk into a bar:

<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>

There’s not enough chairs for them to all sit at the bar, so you need the tenth div to sit on the lap of one of the other divs, say the second one. We can visually cover the second div with the tenth div but have to make sure they are sitting next to each other in the HTML as well. The order matters.

<div>1</div>
<div>2</div>
<div>10</div><!-- Sitting next to Div #2-->
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>

The tenth div needs to sit on the second div’s lap rather than next to it. So, perhaps we redefine the relationship between them and make this a parent-child sorta thing.

<div>1</div>
<div class="parent">
  2
  <div class="child">10</div><!-- Sitting in Div #2's lap-->
</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>

Now we can do a little tricky positioning dance to contain the tenth div inside the second div in the CSS:

.parent {
  position: relative; /* Contains Div #10 */
}

.child {
  position: absolute;
}

We can inset the child’s position so it is pinned to the parent’s top-left edge:

.child {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
}

And we can set the child’s width to 100% of the parent’s size so that it is fully covering the parent’s lap and completely obscuring it.

.child {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  width: 100%;
}

Cool, it works!

Anchor positioning simplifies this process a heckuva lot because it just doesn’t care where the tenth div is in the HTML. Instead, we can work with our initial markup containing 10 individuals exactly as they entered the bar. You’re going to want to follow along in the latest version of Chrome since anchor positioning is only supported there by default at the time I’m writing this.

<div>1</div>
<div class="parent">2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div class="child">10</div>

Instead, we define the second div as an anchor element using the anchor-name property. I’m going to continue using the .parent and .child classes to keep things clear.

.parent {
  anchor-name: --anchor; /* this can be any name formatted as a dashed ident */
}

Then we connect the child to the parent by way of the position-anchor property:

.child {
  position-anchor: --anchor; /* has to match the `anchor-name` */
}

The last thing we have to do is position the child so that it covers the parent’s lap. We have the position-area property that allows us to center the element over the parent:

.child {
  position-anchor: --anchor;
  position-area: center;
}

If we want to completely cover the parent’s lap, we can set the child’s size to match that of the parent using the anchor-size() function:

.child {
  position-anchor: --anchor;
  position-area: center;
  width: anchor-size(width);
}

No punchline — just one of the things that makes anchor positioning something I’m so excited about. The fact that it eschews HTML source order is so CSS-y because it’s another separation of concerns between content and presentation.


Anchor Positioning Just Don’t Care About Source Order originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Sunday, April 27, 2025

Partly Cloudy/Wind today!



With a high of F and a low of 41F. Currently, it's 65F and Partly Cloudy/Wind outside.

Current wind speeds: 21 from the South

Pollen: 0

Sunrise: April 27, 2025 at 05:57PM

Sunset: April 28, 2025 at 07:41AM

UV index: 0

Humidity: 34%

via https://ift.tt/FUwTJza

April 28, 2025 at 10:02AM

Saturday, April 26, 2025

Rain/Wind Early today!



With a high of F and a low of 47F. Currently, it's 55F and Cloudy/Wind outside.

Current wind speeds: 23 from the Southeast

Pollen: 0

Sunrise: April 26, 2025 at 05:58PM

Sunset: April 27, 2025 at 07:40AM

UV index: 0

Humidity: 91%

via https://ift.tt/dA1uZBY

April 27, 2025 at 10:02AM

Friday, April 25, 2025

Showers Late today!



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

Current wind speeds: 14 from the Southeast

Pollen: 0

Sunrise: April 25, 2025 at 06:00PM

Sunset: April 26, 2025 at 07:39AM

UV index: 0

Humidity: 98%

via https://ift.tt/BNQwsK6

April 26, 2025 at 10:02AM

Thursday, April 24, 2025

Thundershowers today!



With a high of F and a low of 39F. Currently, it's 50F and Cloudy outside.

Current wind speeds: 12 from the Northeast

Pollen: 0

Sunrise: April 24, 2025 at 06:01PM

Sunset: April 25, 2025 at 07:38AM

UV index: 0

Humidity: 84%

via https://ift.tt/8ITH6LA

April 25, 2025 at 10:02AM

The Lost CSS Tricks of Cohost.org

You would be forgiven if you’ve never heard of Cohost.org. The bespoke, Tumblr-like social media website came and went in a flash. Going public in June 2022 with invite-only registrations, Cohost’s peach and maroon landing page promised that it would be “posting, but better.” Just over two years later, in September 2024, the site announced its shutdown, its creators citing burnout and funding problems. Today, its servers are gone for good. Any link to cohost.org redirects to the Wayback Machine’s slow but comprehensive archive.

Screenshot of the Cohost.org homepage before it was shut down.

The landing page for Cohost.org, featuring our beloved eggbug.

Despite its short lifetime, I am confident in saying that Cohost delivered on its promise. This is in no small part due to its user base, consisting mostly of niche internet creatives and their friends — many of whom already considered “posting” to be an art form. These users were attracted to Cohost’s opinionated, anti-capitalist design that set it apart from the mainstream alternatives. The site was free of advertisements and follower counts, all feeds were purely chronological, and the posting interface even supported a subset of HTML.

It was this latter feature that conjured a community of its own. For security reasons, any post using HTML was passed through a sanitizer to remove any malicious or malformed elements. But unlike most websites, Cohost’s sanitizer was remarkably permissive. The vast majority of tags and attributes were allowed — most notably inline CSS styles on arbitrary elements.

Users didn’t take long to grasp the creative opportunities lurking within Cohost’s unassuming “new post” modal. Within 48 hours of going public, the fledgling community had figured out how to post poetry using the <details> tag, port the Apple homepage from 1999, and reimplement a quick-time WarioWare game. We called posts like these “CSS Crimes,” and the people who made them “CSS Criminals.” Without even intending to, the developers of Cohost had created an environment for a CSS community to thrive.

In this post, I’ll show you a few of the hacks we found while trying to push the limits of Cohost’s HTML support. Use these if you dare, lest you too get labelled a CSS criminal.

Width-hacking

Many of the CSS crimes of Cohost were powered by a technique that user @corncycle dubbed “width-hacking.” Using a combination of the <details> element and the CSS calc() function, we can get some pretty wild functionality: combination lockstile matching games, Zelda-style top-down movement, the list goes on.

If you’ve been around the CSS world for a while, there’s a good chance you’ve been exposed to the old checkbox hack. By combining a checkbox, a label, and creative use of CSS selectors, you can use the toggle functionality of the checkbox to implement all sorts of things. Tabbed areas, push toggles, dropdown menus, etc.

However, because this hack requires CSS selectors, that meant we couldn’t use it on Cohost — remember, we only had inline styles. Instead, we used the relatively new elements <details> and <summary>. These elements provide the same visibility-toggling logic, but now directly in HTML. No weird CSS needed.

These elements work like so: All children of the <details> element are hidden by default, except for the <summary> element. When the summary is clicked, it “opens” the parent details element, causing its children to become visible.

We can add all sorts of styles to these elements to make this example more interesting. Below, I have styled the constituent elements to create the effect of a button that lights up when you click on it.

This is achieved by giving the <summary> element a fixed position and size, a grey background color, and an outset border to make it look like a button. When it’s clicked, a sibling <div> is revealed that covers the <summary> with its own red background and border. Normally, this <div> would block further click events, but I’ve given it the declaration pointer-events: none. Now all clicks pass right on through to the <summary> element underneath, allowing you to turn the button back off.

This is all pretty nifty, but it’s ultimately the same logic as before: something is toggled either on or off. These are only two states. If we want to make games and other gizmos, we might want to represent hundreds to thousands of states.

Width-hacking gives us exactly that. Consider the following example:

In this example, three <details> elements live together in an inline-flex container. Because all the <summary> elements are absolutely-positioned, the width of their respective <details> elements are all zero when they’re closed.

Now, each of these three <details> has a small <div> inside. The first has a child with a width of 1px, the second a child with a width of 2px, and the third a width of 4px. When a <details> element is opened, it reveals its hidden <div>, causing its own width to increase. This increases the width of the inline-flex container. Because the width of the container is the sum of its children, this means its width directly corresponds to the specific <details> elements that are open.

For example, if just the first and third <details> are open, the inline-flex container will have the width 1px + 4px = 5px. Conversely, if the inline-flex container is 2px wide, we can infer that the only open <details> element is the second one. With this trick, we’ve managed to encode all eight states of the three <details> into the width of the container element.

This is pretty cool. Maybe we could use this as an element of some kind of puzzle game? We could show a secret message if the right combination of buttons is checked. But how do we do that? How do we only show the secret message for a specific width of that container div?

In the preceding CodePen, I’ve added a secret message as two nested divs. Currently, this message is always visible — complete with a TODO reminding us to implement the logic to hide it unless the correct combination is set.

You may wonder why we’re using two nested divs for such a simple message. This is because we’ll be hiding the message using a peculiar method: We will make the width of the parent div.secret be zero. Because the overflow: hidden property is used, the child div.message will be clipped, and thus invisible.

Now we’re ready to implement our secret message logic. Thanks to the fact that percentage sizes are relative to the parent, we can use 100% as a stand-in for the parent’s width. We can then construct a complicated CSS calc() formula that is 350px if the container div is our target size, and 0px otherwise. With that, our secret message will be visible only when the center button is active and the others are inactive. Give it a try!

This complicated calc() function that’s controlling the secret div’s width has the following graph:

Line chart showing the width of the secret div when the container div is at different widths.

You can see that it’s a piecewise linear curve, constructed from multiple pieces using min/max. These pieces are placed in just the right spots so that the function maxes out when the container div is 2px— which we’ve established is precisely when only the second button is active.

A surprising variety of games can be implemented using variations on this technique. Here is a tower of Hanoi game I had made that uses both width and height to track the game’s state.

SVG animation

So far, we’ve seen some basic functionality for implementing a game. But what if we want our games to look good? What if we want to add ✨animations?✨ Believe it or not, this is actually possible entirely within inline CSS using the power of SVG.

SVG (Scalable Vector Graphics) is an XML-based image format for storing vector images. It enjoys broad support on the web — you can use it in <img> elements or as the URL of a background-image property, among other things.

Like HTML, an SVG file is a collection of elements. For SVG, these elements are things like <rect><circle>, and <text>, to name a few. These elements can have all sorts of properties defined, such as fill color, stroke width, and font family.

A lesser-known feature of SVG is that it can contain <style> blocks for configuring the properties of these elements. In the example below, an SVG is used as the background for a div. Inside that SVG is a <style> block that sets the fillcolor of its <circle> to red.

An even lesser-known feature of SVG is that its styles can use media queries. The size used by those queries is the size of the div it is a background of.

In the following example, we have a resizable <div> with an SVG background. Inside this SVG is a media query which will change the fill color of its <circle> to blue when the width exceeds 100px. Grab the resize handle in its bottom right corner and drag until the circle turns blue.

Because resize handles don’t quite work on mobile, unfortunately, this and the next couple of CodePens are best experienced on desktop.

This is an extremely powerful technique. By mixing it with width-hacking, we could encode the state of a game or gizmo in the width of an SVG background image. This SVG can then show or hide specific elements depending on the corresponding game state via media queries.

But I promised you animations. So, how is that done? Turns out you can use CSS animations within SVGs. By using the CSS transition property, we can make the color of our circle smoothly transition from red to blue.

Amazing! But before you try this yourself, be sure to look at the source code carefully. You’ll notice that I’ve had to add a 1×1px, off-screen element with the ID #hack. This element has a very simple (and nearly unnoticeable) continuous animation applied. A “dummy animation” like this is necessary to get around some web browsers’ buggy detection of SVG animation. Without that hack, our transition property wouldn’t work consistently.

For the fun of it, let’s combine this tech with our previous secret message example. Instead of toggling the secret message’s width between the values of 0px and 350px, I’ve adjusted the calc formula so that the secret message div is normally 350px, and becomes 351px if the right combination is set.

Instead of HTML/CSS, the secret message is now just an SVG background with a <text> element that says “secret message.” Using media queries, we change the transform scale of this <text> to be zero unless the div is 351px. With the transition property applied, we get a smooth transition between these two states.

Click the center button to activate the secret message:

The first cohost user to discover the use of media queries within SVG backgrounds was @ticky for this post. I don’t recall who figured out they could animate, but I used the tech quite extensively for this quiz that tells you what kind of soil you’d like if you were a worm.

Wrapping up

And that’s will be all for now. There are a number of techniques I haven’t touched on — namely the fun antics one can get up to with the resize property. If you’d like to explore the world of CSS crimes further, I’d recommend this great linkdump by YellowAfterlife, or this video retrospective by rebane2001.


It will always hurt to describe Cohost in the past tense. It truly was a magical place, and I don’t think I’ll be able to properly convey what it was like to be there at its peak. The best I can do is share the hacks we came up with: the lost CSS tricks we invented while “posting, but better.”


The Lost CSS Tricks of Cohost.org originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Wednesday, April 23, 2025

Thunderstorms Early today!



With a high of F and a low of 46F. Currently, it's 54F and Light Rain with Thunder outside.

Current wind speeds: 13 from the East

Pollen: 0

Sunrise: April 23, 2025 at 06:02PM

Sunset: April 24, 2025 at 07:37AM

UV index: 0

Humidity: 74%

via https://ift.tt/IsFAeXC

April 24, 2025 at 10:02AM

Tuesday, April 22, 2025

Showers Early today!



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

Current wind speeds: 10 from the East

Pollen: 0

Sunrise: April 22, 2025 at 06:04PM

Sunset: April 23, 2025 at 07:36AM

UV index: 0

Humidity: 40%

via https://ift.tt/MSXT9H7

April 23, 2025 at 10:02AM

Monday, April 21, 2025

Showers Early today!



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

Current wind speeds: 9 from the Northeast

Pollen: 0

Sunrise: April 21, 2025 at 06:05PM

Sunset: April 22, 2025 at 07:35AM

UV index: 0

Humidity: 30%

via https://ift.tt/nrW6pLK

April 22, 2025 at 10:02AM

Sunday, April 20, 2025

Mostly Clear today!



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

Current wind speeds: 9 from the Northwest

Pollen: 0

Sunrise: April 20, 2025 at 06:06PM

Sunset: April 21, 2025 at 07:34AM

UV index: 0

Humidity: 44%

via https://ift.tt/Fr4K2Zd

April 21, 2025 at 10:02AM

Saturday, April 19, 2025

Partly Cloudy today!



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

Current wind speeds: 8 from the Southwest

Pollen: 0

Sunrise: April 19, 2025 at 06:08PM

Sunset: April 20, 2025 at 07:33AM

UV index: 0

Humidity: 55%

via https://ift.tt/wiU4mfH

April 20, 2025 at 10:02AM

Friday, April 18, 2025

Wintry Mix today!



With a high of F and a low of 26F. Currently, it's 30F and Cloudy outside.

Current wind speeds: 9 from the Northeast

Pollen: 0

Sunrise: April 18, 2025 at 06:09PM

Sunset: April 19, 2025 at 07:32AM

UV index: 0

Humidity: 86%

via https://ift.tt/iP6VayJ

April 19, 2025 at 10:02AM

“Pretty” is in the eye of the beholder

Hey, did you see the post Jen Simmons published about WebKit’s text-wrap: pretty implementation? It was added to Safari Technology Preview and can be tested now, as in, like, today. Slap this in a stylesheet and your paragraphs get a nice little makeover that improves the ragging, reduces hyphenation, eliminates typographic orphans at the end of the last line, and generally avoids large typographic rivers as a result. The first visual in the post tells the full story, showing how each of these is handled.

A screenshot of paragraph text that demonstrates a short last line, bad rag, bad hyphenation, and a typographic river.
Credit: WebKit Blog

That’s a lot of heavy lifting for a single value! And according to Jen, this is vastly different from Chromium’s implementation of the exact same feature.

According to an article by the Chrome team, Chromium only makes adjustments to the last four lines of a paragraph. It’s focused on preventing short last lines. It also adjusts hyphenation if consecutive hyphenated lines appear at the end of a paragraph.

Jen suggests that performance concerns are the reason for the difference. It does sound like the pretty value does a lot of work, and you might imagine that would have a cumulative effect when we’re talking about long-form content where we’re handling hundreds, if not thousands, of lines of text. If it sounds like Safari cares less about performance, that’s not the case, as their approach is capable of handling the load.

One thing to know as a developer, the performance of text-wrap is not affected by how many elements on the page it’s applied to. Perf concerns emerge as the pretty algorithm takes more and more lines into consideration as it calculates what to do. In WebKit-based browsers or apps, your text element would need to be many hundreds or thousands of lines long to see a performance hit — and that kind of content is unusual on the web. If your content is broken up into typical-length paragraphs, then you have no reason to worry. Use text-wrap: pretty as much as you want, and rely on our browser engineers to ensure your users will not experience any downsides.

Great, carry on! But now you know that two major browsers have competing implementations of the same feature. I’ve been unclear on the terminology of pretty since it was specced, and now it truly seems that what is considered “pretty” really is in the eye of the beholder. And if you’re hoping to choose a side, don’t, because the specification is intentionally unopinionated in this situation, as it says (emphasis added):

The user agent may among other things attempt to avoid excessively short last lines… but it should also improve the layout in additional ways. The precise set of improvements is user agent dependent, and may include things such as: reducing the variation in length between lines; avoiding typographic rivers; prioritizing different classes of soft wrap opportunities, hyphenation opportunities, or justification opportunities; avoiding hyphenation on too many consecutive lines.

So, there you have it. One new feature. Two different approaches. Enjoy your new typographic powers. 💪


“Pretty” is in the eye of the beholder originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Thursday, April 17, 2025

Partly Cloudy/Wind today!



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

Current wind speeds: 26 from the North

Pollen: 0

Sunrise: April 17, 2025 at 06:11PM

Sunset: April 18, 2025 at 07:31AM

UV index: 0

Humidity: 45%

via https://ift.tt/sferoId

April 18, 2025 at 10:02AM

So, You Want to Give Up CSS Pre- and Post-Processors…

There was once upon a time when native CSS lacked many essential features, leaving developers to come up with all sorts of ways to make CSS easier to write over the years.

These ways can mostly be categorized into two groups:

  1. Pre-processors
  2. Post-processors

Pre-processors include tools like Sass, Less, and Stylus. Like what the category’s name suggests, these tools let you write CSS in their syntax before compiling your code into valid CSS.

Post-processors work the other way — you write non-valid CSS syntax into a CSS file, then post-processors will change those values into valid CSS.

There are two major post-processors today:

  • PostCSS
  • LightningCSS

PostCSS is the largest kid on the block while Lightning CSS is a new and noteworthy one. We’ll talk about them both in a bit.

I think post-processors have won the compiling game

Post-processors have always been on the verge of winning since PostCSS has always been a necessary tool in the toolchain.

The most obvious (and most useful) PostCSS plugin for a long time is Autoprefixer — it creates vendor prefixes for you so you don’t have to deal with them.

/* Input */
.selector {
  transform: /* ... */; 
}

.selector {
  -webkit-transform: /* ... */;
  transform: /* ... */;
}

Arguably, we don’t need Autoprefixer much today because browsers are more interopable, but nobody wants to go without Autoprefixer because it eliminates our worries about vendor prefixing.

What has really tilted the balance towards post-processors includes:

  1. Native CSS gaining essential features
  2. Tailwind removing support for pre-processors
  3. Lightning CSS

Let me expand on each of these.

Native CSS gaining essential features

CSS pre-processors existed in the first place because native CSS lacked features that were critical for most developers, including:

  • CSS variables
  • Nesting capabilities
  • Allowing users to break CSS into multiple files without additional fetch requests
  • Conditionals like if and for
  • Mixins and functions

Native CSS has progressed a lot over the years. It has gained great browser support for the first two features:

  • CSS Variables
  • Nesting

With just these two features, I suspect a majority of CSS users won’t even need to fire up pre-processors or post-processors. What’s more, The if() function is coming to CSS in the future too.

But, for the rest of us who needs to make maintenance and loading performance a priority, we still need the third feature — the ability to break CSS into multiple files. This can be done with Sass’s use feature or PostCSS’s import feature (provided by the postcss-import plugin).

PostCSS also contains plugins that can help you create conditionals, mixins, and functions should you need them.

Although, from my experience, mixins can be better replaced with Tailwind’s @apply feature.

This brings us to Tailwind.

Tailwind removing support for pre-processors

Tailwind 4 has officially removed support for pre-processors. From Tailwind’s documentation:

Tailwind CSS v4.0 is a full-featured CSS build tool designed for a specific workflow, and is not designed to be used with CSS pre-processors like Sass, Less, or Stylus. Think of Tailwind CSS itself as your pre-processor — you shouldn’t use Tailwind with Sass for the same reason you wouldn’t use Sass with Stylus. Since Tailwind is designed for modern browsers, you actually don’t need a pre-processor for things like nesting or variables, and Tailwind itself will do things like bundle your imports and add vendor prefixes.

If you included Tailwind 4 via its most direct installation method, you won’t be able to use pre-processors with Tailwind.

@import `tailwindcss`

That’s because this one import statement makes Tailwind incompatible with Sass, Less, and Stylus.

But, (fortunately), Sass lets you import CSS files if the imported file contains the .css extension. So, if you wish to use Tailwind with Sass, you can. But it’s just going to be a little bit wordier.

@layer theme, base, components, utilities;

@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/preflight.css" layer(base);
@import "tailwindcss/utilities.css" layer(utilities);

Personally, I dislike Tailwind’s preflight styles so I exclude them from my files.

@layer theme, base, components, utilities;
@import 'tailwindcss/theme.css' layer(theme);
@import 'tailwindcss/utilities.css' layer(utilities);

Either way, many people won’t know you can continue to use pre-processors with Tailwind. Because of this, I suspect pre-processors will get less popular as Tailwind gains more momentum.

Now, beneath Tailwind is a CSS post-processor called Lightning CSS, so this brings us to talking about that.

Lightning CSS

Lightning CSS is a post-processor can do many things that a modern developer needs — so it replaces most of the PostCSS tool chain including:

Besides having a decent set of built-in features, it wins over PostCSS because it’s incredibly fast.

Lightning CSS is over 100 times faster than comparable JavaScript-based tools. It can minify over 2.7 million lines of code per second on a single thread.

Comparing build times for CSS Nano (544 milliseconds), ES Build (17 milliseconds), and Lightning CSS (4 milliseconds).

Speed helps Lightning CSS win since many developers are speed junkies who don’t mind switching tools to achieve reduced compile times. But, Lightning CSS also wins because it has great distribution.

It can be used directly as a Vite plugin (that many frameworks support). Ryan Trimble has a step-by-step article on setting it up with Vite if you need help.

// vite.config.mjs
export default {
  css: {
    transformer: 'lightningcss'
  },
  build: {
    cssMinify: 'lightningcss'
  }
};

If you need other PostCSS plugins, you can also include that as part of the PostCSS tool chain.

// postcss.config.js
// Import other plugins...
import lightning from 'postcss-lightningcss'

export default {
  plugins: [lightning, /* Other plugins */],
}

Many well-known developers have switched to Lightning CSS and didn’t look back. Chris Coyier says he’ll use a “super basic CSS processing setup” so you can be assured that you are probably not stepping in any toes if you wish to switch to Lightning, too.

If you wanna ditch pre-processors today

You’ll need to check the features you need. Native CSS is enough for you if you need:

  • CSS Variables
  • Nesting capabilities

Lightning CSS is enough for you if you need:

  • CSS Variables
  • Nesting capabilities
  • import statements to break CSS into multiple files

Tailwind (with @apply) is enough for you if you need:

  • all of the above
  • Mixins

If you still need conditionals like if, for and other functions, it’s still best to stick with Sass for now. (I’ve tried and encountered interoperability issues between postcss-for and Lightning CSS that I shall not go into details here).

That’s all I want to share with you today. I hope it helps you if you have been thinking about your CSS toolchain.


So, You Want to Give Up CSS Pre- and Post-Processors… originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Wednesday, April 16, 2025

Light Rain Early today!



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

Current wind speeds: 9 from the Northwest

Pollen: 0

Sunrise: April 16, 2025 at 06:12PM

Sunset: April 17, 2025 at 07:30AM

UV index: 0

Humidity: 37%

via https://ift.tt/2vo9lwS

April 17, 2025 at 10:02AM

Using CSS backdrop-filter for UI Effects

This article covers tips and tricks on effectively utilizing the CSS backdrop-filter property to style contemporary user interfaces. You’ll learn how to layer backdrop filters among multiple elements, and integrate them with other CSS graphical effects to create elaborate designs.

Below is a hodgepodge sample of what you can build based on everything we’ll cover in this article. More examples are coming up.

The blurry, frosted glass effect is popular with developers and designers these days — maybe because Josh Comeau wrote a deep-dive about it somewhat recently — so that is what I will base my examples on. However, you can apply everything you learn here to any relevant filter. I’ll also be touching upon a few of them in my examples.

What’s essential in a backdrop filter?

If you’re familiar with CSS filter functions like blur() and brightness(), then you’re also familiar with backdrop filter functions. They’re the same. You can find a complete list of supported filter functions here at CSS-Tricks as well as over at MDN.

The difference between the CSS filter and backdrop-filter properties is the affected part of an element. Backdrop filter affects the backdrop of an element, and it requires a transparent or translucent background in the element for its effect to be visible. It’s important to remember these fundamentals when using a backdrop filter, for these reasons:

  1. to decide on the aesthetics,
  2. to be able to layer the filters among multiple elements, and
  3. to combine filters with other CSS effects.

The backdrop

Design is subjective, but a little guidance can be helpful. If you’ve applied a blur filter to a plain background and felt the result was unsatisfactory, it could be that it needed a few embellishments, like shadows, or more often than not, it’s because the backdrop is too plain.

Plain backdrops can be enhanced with filters like brightness(), contrast(), and invert(). Such filters play with the luminosity and hue of an element’s backdrop, creating interesting designs. Textured backdrops complement distorting filters like blur() and opacity().

<main>
<div>
  <section>
    <h1>Weather today</h1>
    Cloudy with a chance of meatballs. Ramenstorms at 3PM that will last for ten minutes.
  </section>
</div>
</main>
main {
  background: center/cover url("image.jpg");
  box-shadow: 0 0 10px rgba(154 201 255 / 0.6);
  /* etc. */
  
  div {
    backdrop-filter: blur(10px);
    color: white;
    /* etc. */
  }
}

Layering elements with backdrop filters

As we just discussed, backdrop filters require an element with a transparent or translucent background so that everything behind it, with the filters applied, is visible.

If you’re applying backdrop filters on multiple elements that are layered above one another, set a translucent (not transparent) background to all elements except the bottommost one, which can be transparent or translucent, provided it has a backdrop. Otherwise, you won’t see the desired filter buildup.

<main>
<div>
  <section>
    <h1>Weather today</h1>
    Cloudy with a chance of meatballs. Ramenstorms at 3PM that will last for ten minutes.
  </section>
  <p>view details</p>
</div>
</main>
main {
  background: center/cover url("image.jpg");
  box-shadow: 0 0 10px rgba(154 201 255 / 0.6);
  /* etc. */

  div {
    background: rgb(255 255 255 / .1);
    backdrop-filter: blur(10px);
    /* etc. */

    p {
      backdrop-filter: brightness(0) contrast(10);
      /* etc. */
    }
  }
}

Combining backdrop filters with other CSS effects

When an element meets a certain criterion, it gets a backdrop root (not yet a standardized name). One criterion is when an element has a filter effect (from filter and background-filter). I believe backdrop filters can work well with other CSS effects that also use a backdrop root because they all affect the same backdrop.

Of those effects, I find two interesting: mask and mix-blend-mode. Combining backdrop-filter with mask resulted in the most reliable outcome across the major browsers in my testing. When it’s done with mix-blend-mode, the blur backdrop filter gets lost, so I won’t use it in my examples. However, I do recommend exploring mix-blend-mode with backdrop-filter.

Backdrop filter with mask

Unlike backdrop-filter, CSS mask affects the background and foreground (made of descendants) of an element. We can use that to our advantage and work around it when it’s not desired.

<main>
  <div>
    <div class="bg"></div>
    <section>
     <h1>Weather today</h1>
      Cloudy with a chance of meatballs. Ramenstorms at 3PM that will last for ten minutes. 
    </section>
  </div>
</main>
main {
  background: center/cover url("image.jpg");
  box-shadow: 0 0 10px rgba(154 201 255 / 0.6);
  /* etc. */
  
  > div {
      .bg {
        backdrop-filter: blur(10px);
        mask-image: repeating-linear-gradient(90deg, transparent, transparent 2px, white 2px, white 10px);
        /* etc. */
      }
    /* etc. */
  }
}

Backdrop filter for the foreground

We have the filter property to apply graphical effects to an element, including its foreground, so we don’t need backdrop filters for such instances. However, if you want to apply a filter to a foreground element and introduce elements within it that shouldn’t be affected by the filter, use a backdrop filter instead.

<main>
  <div class="photo">
    <div class="filter"></div>
  </div>
  <!-- etc. -->
</main>
.photo {
  background: center/cover url("photo.jpg");

  .filter {
    backdrop-filter: blur(10px) brightness(110%);
    mask-image: radial-gradient(white 5px, transparent 6px);
    mask-size: 10px 10px;
    transition: backdrop-filter .3s linear;
    /* etc.*/
  }

  &:hover .filter {
    backdrop-filter: none;
    mask-image: none;
  }
}

In the example below, hover over the blurred photo.

There are plenty of ways to play with the effects of the CSS backdrop-filter. If you want to layer the filters across stacked elements then ensure the elements on top are translucent. You can also combine the filters with other CSS standards that affect an element’s backdrop. Once again, here’s the set of UI designs I showed at the beginning of the article, that might give you some ideas on crafting your own.

References


Using CSS backdrop-filter for UI Effects originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Tuesday, April 15, 2025

Partly Cloudy today!



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

Current wind speeds: 9 from the South

Pollen: 0

Sunrise: April 15, 2025 at 06:13PM

Sunset: April 16, 2025 at 07:29AM

UV index: 0

Humidity: 40%

via https://ift.tt/sLMjx6H

April 16, 2025 at 10:02AM

Monday, April 14, 2025

Clear today!



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

Current wind speeds: 3 from the East

Pollen: 0

Sunrise: April 14, 2025 at 06:15PM

Sunset: April 15, 2025 at 07:28AM

UV index: 0

Humidity: 46%

via https://ift.tt/jbYq7Mu

April 15, 2025 at 10:02AM

Next Level CSS Styling for Cursors

The cursor is a staple of the desktop interface but is scarcely touched by websites. This is for good reason. People expect their cursors to stay fairly consistent, and meddling with them can unnecessarily confuse users. Custom cursors also aren’t visible for people using touch interfaces — which excludes the majority of people.

Geoff has already covered styling cursors with CSS pretty comprehensively in “Changing the Cursor with CSS for Better User Experience (or Fun)” so this post is going to focus on complex and interesting styling.

Custom cursors with JavaScript

Custom cursors with CSS are great, but we can take things to the next level with JavaScript. Using JavaScript, we can use an element as our cursor, which lets us style it however we would anything else. This lets us transition between cursor states, place dynamic text within the cursor, apply complex animations, and apply filters.

In its most basic form, we just need a div that continuously positions itself to the cursor location. We can do this with the mousemove event listener. While we’re at it, we may as well add a cool little effect when clicking via the mousedown event listener.

That’s wonderful. Now we’ve got a bit of a custom cursor going that scales on click. You can see that it is positioned based on the mouse coordinates relative to the page with JavaScript. We do still have our default cursor showing though, and it is important for our new cursor to indicate intent, such as changing when hovering over something clickable.

We can disable the default cursor display completely by adding the CSS rule cursor: none to *. Be aware that some browsers will show the cursor regardless if the document height isn’t 100% filled.

We’ll also need to add pointer-events: none to our cursor element to prevent it from blocking our interactions, and we’ll show a custom effect when hovering certain elements by adding the pressable class.

Very nice. That’s a lovely little circular cursor we’ve got here.

Fallbacks, accessibility, and touchscreens

People don’t need a cursor when interacting with touchscreens, so we can disable ours. And if we’re doing really funky things, we might also wish to disable our cursor for users who have the prefers-reduced-motion preference set.

We can do this without too much hassle:

What we’re doing here is checking if the user is accessing the site with a touchscreen or if they prefer reduced motion and then only enabling the custom cursor if they aren’t. Because this is handled with JavaScript, it also means that the custom cursor will only show if the JavaScript is active, otherwise falling back to the default cursor functionality as defined by the browser.

const isTouchDevice = "ontouchstart"in window || navigator.maxTouchPoints > 0;
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

if (!isTouchDevice && !prefersReducedMotion && cursor) {
  // Cursor implementation is here
}

Currently, the website falls back to the default cursors if JavaScript isn’t enabled, but we could set a fallback cursor more similar to our styled one with a bit of CSS. Progressive enhancement is where it’s at!

Here we’re just using a very basic 32px by 32px base64-encoded circle. The 16 values position the cursor hotspot to the center.

html {
  cursor:
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0Jve
D0iMCAwIDMyIDMyIj4KICA8Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSIxNiIgZmlsbD0iYmxhY2siIC8+Cjwvc3ZnPg==")
    16 16,
    auto;
}

Taking this further

Obviously this is just the start. You can go ballistic and completely overhaul the cursor experience. You can make it invert what is behind it with a filter, you can animate it, you could offset it from its actual location, or anything else your heart desires.

As a little bit of inspiration, some really cool uses of custom cursors include:

  • Studio Mesmer switches out the default cursor for a custom eye graphic when hovering cards, which is tasteful and fits their brand.
  • Iara Grinspun’s portfolio has a cursor implemented with JavaScript that is circular and slightly delayed from the actual position which makes it feel floaty.
  • Marlène Bruhat’s portfolio has a sleek cursor that is paired with a gradient that appears behind page elements.
  • Aleksandr Yaremenko’s portfolio features a cursor that isn’t super complex but certainly stands out as a statement piece.
  • Terra features a giant glowing orb containing text describing what you’re hovering over.

Please do take care when replacing browser or native operating system features in this manner. The web is accessible by default, and we should take care to not undermine this. Use your power as a developer with taste and restraint.


Next Level CSS Styling for Cursors originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.



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

Clear today!

With a high of F and a low of 51F. Currently, it's 67F and Clear outside. Current wind speeds: 6 from the South Pollen: 0 Sunris...