Developer News

CSSWG Minutes Telecon (2024-09-18)

Css Tricks - Fri, 09/20/2024 - 5:15am

For the past two months, all my livelihood has gone towards reading, researching, understanding, writing, and editing about Anchor Positioning, and with many Almanac entries published and a full Guide guide on the way, I thought I was ready to tie a bow on it all and call it done. I know that Anchor Positioning is still new and settling in. The speed at which it’s moved, though, is amazing. And there’s more and more coming from the CSSWG!

That all said, I was perusing the last CSSWG minutes telecon and knew I was in for more Anchor Positioning when I came to the following resolution:

Whenever you are comparing names, and at least one is tree scoped, then both are tree scoped, and the scoping has to be exact (not subtree) (Issue #10526: When does anchor-scope “match” a name?)

Resolutions aren’t part of the specification or anything, but the strongest of indications about where they’re headed. So, I thought this was a good opportunity not only to take a peek at what we might get in anchor-scope and touch on other interesting bits from the telecon.

Remember that you can subscribe and read the full minutes on W3C.org. :)

Full Transcription What’s anchor-scope?

To register an anchor, we can give it a distinctive anchor-name and then absolutely positioned elements with a matching position-anchor are attached to it. Even though it may look like it, anchor-name doesn’t have to be unique — we may reuse an anchor element inside a component with the same anchor-name.

<ul> <li> <div class="anchor">Anchor 1</div> <div class="target">Target 1</div> </li> <li> <div class="anchor">Anchor 2</div> <div class="target">Target 2</div> </li> <li> <div class="anchor">Anchor 3</div> <div class="target">Target 3</div> </li> </ul>

However, if we try to connect them with CSS,

.anchor { anchor-name: --my-anchor; } .target { position: absolute; position-anchor: --my-anchor; position-area: top right; }

We get an unpleasant surprise where instead of each .anchor having their .target positioned at its top-right edge, they all pile up on the last .anchor instance. We can see it better by rotating each target a little. You’ll want to check out the next demo in Chrome 125+ to see the behavior:

CodePen Embed Fallback

The anchor-scope property should make an anchor element only discoverable by targets in their individual subtree. So, the prior example would be fixed in the future like this:

.anchor { anchor-name: --my-anchor; anchor-scope: --my-anchor; }

This is fairly straightforward — anchor-scope makes the anchor element available only in that specific subtree. But then we have to ask another question: What should the anchor-scope own scope be? We can’t have an anchor-scope-scope property and then an anchor-scope-scope-scope and so on… so which behavior should it be?

This is what started the conversation, initially from a GitHub issue:

When an anchor-scope is specified with a <dashed-ident>, it scopes the name to that subtree when the anchor name is “matching”. The problem is that this matching can be interpreted in at least three ways: (Assuming that anchor-scope is a tree-scoped reference, which is also not clear in the spec):

  1. It matches by the ident part of the name only, ignoring any tree-scope that would be associated with the name, or
  2. It matches by exact match of the ident part and the associated tree-scope, or
  3. It matches by some mechanism similar to dereferencing of tree-scoped references, where it’s a match when the tree-scope of the anchor-scope-name is an inclusive ancestor of the tree-scope of the anchor query.

And then onto the CSSWG Minutes:

TabAtkins: In anchor positioning, anchor names and references are tree scoped. The anchor-scope property that scopes, does not say whether the names are tree scoped or not. Question to decide: should they be?

TabAtkins: I think the answer should be yes. If you have an anchor in a shadow tree with a part involved, then problems result if anchor scopes are not tree scoped. This is bad, so I think it should be tree scoped

<khush> sounds pretty reasonable

<fantasai> makes sense to me as far as I can understand it :)

This solution of the scope of scoping properties expanded towards View Transitions, which also rely on tree scoping to work:

khush: Thinking about this in the context of view transitions: in that API you give names and the tree scope has to be the same for them to match. There is another view transitions feature where I’m not sure if the spec says it’s tree scoped

khush: Want to make sure that feature is covered by the more general resolution

TabAtkins: Proposed more general resolution: whenever you are comparing names, and at least one is tree scoped, then both are tree scoped, and the scoping has to be exact (not subtree)

So the scope of anchor-scope is tree-scoped. Say that five times fast!

RESOLVED: whenever you are comparing names, and at least one is tree scoped, then both are tree scoped, and the scoping has to be exact (not subtree)

The next resolution was pretty straightforward. Besides allowing a <dashed-ident> that says that specific anchor is three-scoped, the anchor-scope property can take an all keyword, which means that all anchors are tree-scoped. So, the question was if all is also a tree-scoped value.

TabAtkins: anchor-scope, in addition to idents, can take the keyword ‘all‘, which scopes all names. Should this be a tree-scoped ‘all‘? (i.e. only applies to the current tree scope)

TabAtkins: Proposed resolution: the ‘all‘ keyword is also tree-scoped in the same way sgtm +1, again same pattern with view-transition-group

RESOLVED: the ‘all‘ keyword is tree-scoped

The conversation switched gears toward new properties coming in the CSS Scroll Snap Module Level 2 draft, which is all about changing the user’s initial scroll with CSS. Taking an example directly from the spec, say we have an image carousel:

<div class="carousel"> <img src="img1.jpg"> <img src="img2.jpg"> <img src="img3.jpg" class="origin"> <img src="img4.jpg"> <img src="img5.jpg"> </div>

We could set the initial scroll to show another image by setting it’s scroll-start-target to auto:

.carousel { overflow-inline: auto; } .carousel .origin { scroll-start-target: auto; }

As of right now, the only way to achieve this is using JavaScript to scroll an element into view:

document.querySelector(".origin").scrollIntoView({ behavior: "auto", block: "center", inline: "center" });

The last example is probably a carousel that is only scrollable in the inline direction. Still, there are doubts as far when the container is scrollable in both the inline and block directions. As seen in the initial GitHub issue:

The scroll snap 2 spec says that when there are multiple elements that could be scroll-start-targets for a scroll container “user-agents should select the one which comes first in tree order“.

Selecting the first element in tree-order seems like a natural way to resolve competition between multiple targets which would be scrolled to in one particular axis but is perhaps not as flexible as might be needed for the 2d case where an author wants to scroll to one item in one axis and another item in the other axis.

And back to the CSSWG minutes:

DavidA: We have a property we’re adding called scroll-start-target that indicates if an element within a scroll container, then the scroll should start with that element onscreen. Question is what happens if there are multiple targets?
DavidA: Propose to do it in reverse-DOM order, this would result in the first one applied last and then be on screen. Also, should only change the scroll position if you have to.

After discussing why we have to define scroll-start-target when we have scroll-snap-align, the discussion went on the reverse-DOM order:

fantasai: There was a bunch of discussion about regular vs reverse-DOM order. Where did we end up and why?
flackr: Currently, we expect that it scrolls to the first item in DOM order. We probably want that to still happen. That is why the proposal is to scroll to each item in sequence in reverse-DOM order.

So we are coming in reverse to scroll the element, but only as required so the following elements are showing as much as possible:

flackr: There is also the issue of nearest…
fantasai: Can you explain nearest?
flackr: Same as scroll into view
fantasai: ?
flackr: This is needed with you scroll multiple things into view and want to find a good position (?)
fantasai: You scroll in reverse-DOM order…when you add the spec can you make it really clear that this is the end result of the algorithm?
flackr: Yes absolutely
fantasai: Otherwise it seems to make sense

And so it was resolved:

Proposed resolution 2: When scroll-start-target targets multiple elements, scroll to each in reverse DOM order with text to specify priority is the first item

Lastly, there was the debate about the text-underline-position, that when set to auto says, “The user agent may use any algorithm to determine the underline’s position; however it must be placed at or under the alphabetic baseline.” The discussion was about whether the auto value should automatically adjust the underlined position to match specific language rules, for example, at the right of the text for vertical writing modes, like Japanese and Mongolian.

fantasai: The initial value of text-underline-position is auto, which is defined as “find a good place to put the underline”.
Three options there: (1) under alphabetical baseline, (2) fully below text (good for lots-of-descenders cases), (3) for vertical text on the RHS
fantasai: auto value is defined in the spec about ‘how far down below the text’, but doesn’t say things about flipping. The current spec says “at or below”. In order to handle language-specific aspects, there is a default UA style sheet that for Chinese and Japanese and Korean there are differences for those languages. A couple of implementations do this
fantasai: Should we change the spec to mention these things?
fantasai: Or should we stick with the UA stylesheet approach?

The thing is that Chrome and Firefox already place the underline on the right in vertical Japanese when text-underline-position is auto.

CodePen Embed Fallback

The group was left with three options:

<fantasai> A) Keep spec as-is, update Gecko + Blink to match (using UA stylesheet for language switch)
<fantasai> B) Introduce auto to text-emphasis-position and use it in both text-emphasis-position and text-underline-position to effect language switches
<fantasai> C) Adopt inconsistent behavior: text-underline-position uses ‘auto‘ and text-emphasis-position uses UA stylesheet

Many CSSWG members like Emilio Cobos, TabAtkins, Miriam Suzanne, Rachel Andrew and fantasai casted their votes, resulting in the following resolution:

RESOLVED: add auto value for text-emphasis-position, and change the meaning of text-underline-position: auto to care about left vs right in vertical text

I definitely encourage you to read at the full minutes! Or if you don’t have the time, you can there’s a list just of resolutions.

CSSWG Minutes Telecon (2024-09-18) originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Quick Hit #20

Css Tricks - Thu, 09/19/2024 - 7:13am

Having fun with Bramus’ new Caniuse CLI tool. This’ll save lots of trips to the Caniuse site!

Quick Hit #20 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Quick Hit #19

Css Tricks - Thu, 09/19/2024 - 4:31am

Two possible syntaxes for CSS masonry, one draft specification, and you get to share your opinions.

Quick Hit #19 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Ask LukeW: Streaming Citations

LukeW - Tue, 09/17/2024 - 2:00pm

The Ask Luke feature on this site uses the thousands of articles, hundreds of PDFs, dozens of videos, and more I've created over the years to answer people's questions about digital product design. Since it launched a year ago, we've been iterating on the core of the Ask Luke system: retrieving relevant content to improve answers.

The most important job of any product interface is making its value clear and accessible to people. Most apps resort to some form of onboarding to accomplish this, but it's exponentially more impactful to experience value than to be told it exists. Likewise it's much more effective to learn through using an interface than through a tutorial explaining it.

These two factors make the seemingly simple job of "getting people to product value" quite difficult. Compounding the issue is that fact that interface solutions that accomplish this often feel simple and obvious -but only after they're uncovered. So iterating to an interface that intuitively conveys value and purpose is usually an iterative process.

That's a long-winded introduction, but it's important context for the changes we made to Ask Luke. The purpose and value of this feature is to pull the most relevant bits of my writings, videos, audio, and files together to answer people's questions about digital product design. So we made a bunch of changes to make that even more front and center -to make how Ask Luke works more obvious.

Now as answers to people's questions stream in, we add citations to the relevant articles, videos, PDF, etc. being used to answer a question in real-time. We also add these citations to the list of sources on the right dynamically instead of all at once before a question is answered.

Before people were able to select any given source and view it in the Ask Luke conversational UI. With these updates, they are also taken to the relevant part of a source: to the relevant point in a video; to the relevant page in a PDF. Since this is easier to see than read about, here's a quick video demonstrating these changes and hopefully making the value and purpose of Ask Luke a bit more obvious.

Further Reading
Acknowledgments

Big thanks to Sidharth Lakshmanan and Sam Breed for the engineering lift on these changes.

Clever Polypane Debugging Features I’m Loving

Css Tricks - Tue, 09/17/2024 - 3:49am

I’m working on a refresh of my personal website, what I’m calling the HD remaster. Well, I wouldn’t call it a “full” redesign. I’m just cleaning things up, and Polypane is coming in clutch. I wrote about how much I enjoy developing with Polypane on my personal blog back in March 2023. In there, I say that I discover new things every time I open the browser up and I’m here to say that is still happening as of August 2024.

Polypane, in case you’re unfamiliar with it, is a web browser specifically created to help developers in all sorts of different ways. The most obvious feature is the multiple panes displaying your project in various viewport sizes:

I’m not about to try to list every feature available in Polypane; I’ll leave that to friend and creator, Kilian Valkhof. Instead, I want to talk about a neat feature that I discovered recently.

Outline tab

Inside Polypane’s sidebar, you will find various tabs that provide different bits of information about your site. For example, if you are wondering how your social media previews will look for your latest blog post, Polypane has you covered in the Meta tab.

The tab I want to focus on though, is the Outline tab. On the surface, it seems rather straightforward, Polypane scans the page and provides you outlines for headings, landmarks, links, images, focus order, and even the full page accessibility tree.

Seeing your page this way helps you spot some pretty obvious mistakes, but Polypane doesn’t stop there. Checking the Show issues option will point out some of the not-so-obvious problems.

In the Landmarks view, there is an option to Show potentials as well, which displays elements that could potentially be page landmarks.

In these outline views, you also can show an overlay on the page and highlight where things are located.

Now, the reason I even stumbled upon these features within the Outline tab is due to a bug I was tracking down, one specifically related to focus order. So, I swapped over to the “Focus order” outline to inspect things further.

That’s when I noticed the option to see an overlay for the focus order.

This provides a literal map of the focus order of your page. I found this to be incredibly useful while troubleshooting the bug, as well as a great way to visualize how someone might navigate your website using a keyboard.

These types of seemingly small, but useful features are abundant throughout Polypane.

Amazing tool

When I reached out to Kilian, mentioning my discovery, his response was “Everything’s there when you need it!”

I can vouch for that.

Clever Polypane Debugging Features I’m Loving originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Multiple Anchors

Css Tricks - Mon, 09/16/2024 - 6:38am

Only Chris, right? You’ll want to view this in a Chromium browser:

CodePen Embed Fallback

This is exactly the sort of thing I love, not for its practicality (cuz it ain’t), but for how it illustrates a concept. Generally, tutorials and demos try to follow the “rules” — whatever those may be — yet breaking them helps you understand how a certain thing works. This is one of those.

The concept is pretty straightforward: one target element can be attached to multiple anchors on the page.

<div class="anchor-1"></div> <div class="anchor-2"></div> <div class="target"></div>

We’ve gotta register the anchors and attach the .target to them:

.anchor-1 { anchor-name: --anchor-1; } .anchor-2 { anchor-name: --anchor-2; } .target { }

Wait, wait! I didn’t attach the .target to the anchors. That’s because we have two ways to do it. One is using the position-anchor property.

.target { position-anchor: --anchor-1; }

That establishes a target-anchor relationship between the two elements. But it only accepts a single anchor value. Hmm. We need more than that. That’s what the anchor() function can do. Well, it doesn’t take multiple values, but we can declare it multiple times on different inset properties, each referencing a different anchor.

.target { top: anchor(--anchor-1, bottom); }

The second piece of anchor()‘s function is the anchor edge we’re positioned to and it’s gotta be some sort of physical or logical inset — top, bottom, start, end, inside, outside, etc. — or percentage. We’re bascially saying, “Take that .target and slap it’s top edge against --anchor-1‘s bottom edge.

That also works for other inset properties:

.target { top: anchor(--anchor-1 bottom); left: anchor(--anchor-1 right); bottom: anchor(--anchor-2 top); right: anchor(--anchor-2 left); }

Notice how both anchors are declared on different properties by way of anchor(). That’s rad. But we aren’t actually anchored yet because the .target is just like any other element that participates in the normal document flow. We have to yank it out with absolute positioning for the inset properties to take hold.

.target { position: absolute; top: anchor(--anchor-1 bottom); left: anchor(--anchor-1 right); bottom: anchor(--anchor-2 top); right: anchor(--anchor-2 left); }

In his demo, Chris cleverly attaches the .target to two <textarea> elements. What makes it clever is that <textarea> allows you to click and drag it to change its dimensions. The two of them are absolutely positioned, one pinned to the viewport’s top-left edge and one pinned to the bottom-right.

If we attach the .target's top and left edges to --anchor-1‘s bottom and right edges, then attach the target's bottom and right edges to --anchor-2‘s top and left edges, we’re effectively anchored to the two <textarea> elements. This is what allows the .target element to stretch with the <textarea> elements when they are resized.

But there’s a small catch: a <textarea> is resized from its bottom-right corner. The second <textarea> is positioned in a way where the resizer isn’t directly attached to the .target. If we rotate(180deg), though, it’s all good.

CodePen Embed Fallback

Again, you’ll want to view that in a Chromium browser at the time I’m writing this. Here’s a clip instead if you prefer.

That’s just a background-color on the .target element. We can put a little character in there instead as a background-image like Chris did to polish this off.

CodePen Embed Fallback

Fun, right?! It still blows my mind this is all happening in CSS. It wasn’t many days ago that something like this would’ve been a job for JavaScript.

Multiple Anchors originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Smashing Hour With Lynn Fisher

Css Tricks - Mon, 09/16/2024 - 6:35am

I’m a big Lynn Fisher fan. You probably are, too, if you’re reading this. Or maybe you’re reading her name for the first time, in which case you’re in for a treat.

That’s because I had a chance to sit down with Lynn for a whopping hour to do nothing more than gab, gab, and gab some more. I love these little Smashing Hours because they’re informal like that and I feel like I really get to know the person I’m talking with. And this was my very first time talking with Lynn, we had a ton to talk about — her CSS art, her annual site refreshes, where she finds inspiration for her work, when the web started to “click” for her… and so much more.

Don’t miss the bit where Lynn discusses her current site design (~24 min.) because it’s a masterclass in animation and creativity.

Smashing Hour With Lynn Fisher originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Two CSS Properties for Trimming Text Box Whitespace

Css Tricks - Fri, 09/13/2024 - 4:11am

The text-box-trim and text-box-edge properties in CSS enable developers to trim specifiable amounts of the whitespace that appear above the first formatted line of text and below the last formatted line of text in a text box, making the text box vertically larger than the content within.

This whitespace is called leading, and it appears above and below (so it’s two half-leadings, actually) all lines of text to make the text more readable. However, we only want it to appear in between lines of text, right? We don’t want it to appear along the over or under edges of our text boxes, because then it interferes with our margins, paddings, gaps, and other spacings.

As an example, if we implement a 50px margin but then the leading adds another 37px, we’d end up with a grand total of 87px of space. Then we’d need to adjust the margin to 13px in order to make the space 50px in practice.

As a design systems person, I try to maintain as much consistency as possible and use very little markup whenever possible, which enables me to use the adjacent-sibling combinator (+) to create blanket rules like this:

/* Whenever <element> is followed by <h1> */ <element> + h1 { margin-bottom: 13px; /* instead of margin-bottom: 50px; */ }

This approach is still a headache since you still have to do the math (albeit less of it). But with the text-box-trim and text-box-edge properties, 50px as defined by CSS will mean 50px visually:

Disclaimer: text-box-trim and text-box-edge are only accessible via a feature flag in Chrome 128+ and Safari 16.4+, as well as Safari Technology Preview without a feature flag. See Caniuse for the latest browser support.

Start with text-box-trim

text-box-trim is the CSS property that basically activates text box trimming. It doesn’t really have a use beyond that, but it does provide us with the option to trim from just the start, just the end, both the start and end, or none:

text-box-trim: trim-start; text-box-trim: trim-end; text-box-trim: trim-both; text-box-trim: none;

Note: In older web browsers, you might need to use the older start/end/both values in place of the newer trim-start/trim-end/trim-both values, respectively. In even older web browsers, you might need to use top/bottom/both. There’s no reference for this, unfortunately, so you’ll just have to see what works.

Now, where do you want to trim from?

You’re probably wondering what I mean by that. Well, consider that a typographic letter has multiple peaks.

There’s the x-height, which marks the top of the letter “x” and other lowercase characters (not including ascenders or overshoots), the cap height, which marks the top of uppercase characters (again, not including ascenders or overshoots), and the alphabetic baseline, which marks the bottom of most letters (not including descenders or overshoots). Then of course there’s the ascender height and descender height too.

You can trim the whitespace between the x-height, cap height, or ascender height and the “over” edge of the text box (this is where overlines begin), and also the white space between the alphabetic baseline or descender height and the “under” edge (where underlines begin if text-underline-position is set to under).

Don’t trim anything

text-box-edge: leading means to include all of the leading; simply don’t trim anything. This has the same effect as text-box-trim: none or forgoing text-box-trim and text-box-edge entirely. You could also restrict under-edge trimming with text-box-trim: trim-start or over edge trimming with text-box-trim: trim-end. Yep, there are quite a few ways to not even do this thing at all!

Newer web browsers have deviated from the CSSWG specification working drafts by removing the leading value and replacing it with auto, despite the “Do not ship (yet)” warning (*shrug*).

Naturally, text-box-edge accepts two values (an instruction regarding the over edge, then an instruction regarding the under edge). However, auto must be used solo.

text-box-edge: auto; /* Works */ text-box-edge: ex auto; /* Doesn't work */ text-box-edge: auto alphabetic; /* Doesn't work */

I could explain all the scenarios in which auto would work, but none of them are useful. I think all we want from auto is to be able to set the over or under edge to auto and the other edge to something else, but this is the only thing that it doesn’t do. This is a problem, but we’ll dive into that shortly. 

Trim above the ascenders and/or below the descenders

The text value will trim above the ascenders if used as the first value and below the descenders if used as the second value and is also the default value if you fail to declare the second value. (I think you’d want it to be auto, but it won’t be.)

text-box-edge: ex text; /* Valid */ text-box-edge: ex; /* Computed as `text-box-edge: ex text;` */ text-box-edge: text alphabetic; /* Valid */ text-box-edge: text text; /* Valid */ text-box-edge: text; /* Computed as `text-box-edge: text text;` */

It’s worth noting that ascender and descender height metrics come from the fonts themselves (or not!), so text can be quite finicky. For example, with the Arial font, the ascender height includes diacritics and the descender height includes descenders, whereas with the Fraunces font, the descender height includes diacritics and I don’t know what the ascender height includes. For this reason, there’s talk about renaming text to from-font.

Trim above the cap height only

To trim above the cap height:

text-box-edge: cap; /* Computed as text-box-edge: cap text; */

Remember, undeclared values default to text, not auto (as demonstrated above). Therefore, to opt out of trimming the under edge, you’d need to use trim-start instead of trim-both:

text-box-trim: trim-start; /* Not text-box-trim: trim-both; */ text-box-edge: cap; /* Not computed as text-box-edge: cap text; */ Trim above the cap height and below the alphabetic baseline

To trim above the cap height and below the alphabetic baseline:

text-box-trim: trim-both; text-box-edge: cap alphabetic;

By the way, the “Cap height to baseline” option of Figma’s “Vertical trim” setting does exactly this. However, its Dev Mode produces CSS code with outdated property names (leading-trim and text-edge) and outdated values (top and bottom).

Trim above the x-height only

To trim above the x-height only:

text-box-trim: trim-start; text-box-edge: ex; Trim above the x-height and below the alphabetic baseline

To trim above the x-height and below the alphabetic baseline:

text-box-trim: trim-both; text-box-edge: ex alphabetic; Trim below the alphabetic baseline only

To trim below the alphabetic baseline only, the following won’t work (things were going so well for a moment, weren’t they?):

text-box-trim: trim-end; text-box-edge: alphabetic;

This is because the first value is always the mandatory over-edge value whereas the second value is an optional under-edge value. This means that alphabetic isn’t a valid over-edge value, even though the inclusion of trim-end suggests that we won’t be providing one. Complaints about verbosity aside, the correct syntax would have you declare any over-edge value even though you’d effectively cancel it out with trim-end:

text-box-trim: trim-end; text-box-edge: [any over edge value] alphabetic; What about ideographic glyphs?

It’s difficult to know how web browsers will trim ideographic glyphs until they do, but you can read all about it in the spec. In theory, you’d want to use the ideographic-ink value for trimming and the ideographic value for no trimming, both of which aren’t unsupported yet:

text-box-edge: ideographic; /* No trim */ text-box-edge: ideographic-ink; /* Trim */ text-box-edge: ideographic-ink ideographic; /* Top trim */ text-box-edge: ideographic ideographic-ink; /* Bottom trim */ text-box, the shorthand property

If you’re not keen on the verbosity of text box trimming, there’s a shorthand text-box property that makes it somewhat inconsequential. All the same rules apply.

/* Syntax */ text-box: [text-box-trim] [text-box-edge (over)] [text-box-edge (under)]? /* Example */ text-box: trim-both cap alphabetic; Final thoughts

At first glance, text-box-trim and text-box-edge might not seem all that interesting, but they do make spacing elements a heck of a lot simpler.

Is the current proposal the best way to handle text box trimming though? Personally, I don’t think so. I think text-box-trim-start and text-box-trim-end would make a lot more sense, with text-box-trim being used as the shorthand property and text-box-edge not being used at all, but I’d settle for some simplification and/or consistent practices. What do you think?

There are some other concerns too. For example, should there be an option to include underlines, overlines, hanging punctuation marks, or diacritics? I’m going to say yes, especially if you’re using text-underline-position: under or a particularly thick text-decoration-thickness, as they can make the spacing between elements appear smaller.

Two CSS Properties for Trimming Text Box Whitespace originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

What’s Old is New

Css Tricks - Thu, 09/12/2024 - 4:05am

I collect a bunch of links in a bookmarks folder. These are things I fully intend to read, and I do — eventually. It’s a good thing bookmarks are digital, otherwise, I’d need a bigger coffee table to separate them from the ever-growing pile of magazines.

The benefit of accumulating links is that the virtual pile starts revealing recurring themes. Two seemingly unrelated posts published a couple months apart may congeal and become more of a dialogue around a common topic.

I spent time pouring through a pile of links I’d accumulated over the past few weeks and noticed a couple of trending topics. No, that’s not me you’re smelling — there’s an aroma of nostalgia in the air., namely a newfound focus on learning web fundamentals and some love for manual deployments.

Web Developers, AI, and Development Fundamentals

Alvaro Montero:

Ultimately, it is not about AI replacing developers, but about developers adapting and evolving with the tools. The ability to learn, understand, and apply the fundamentals is essential because tools will only take you so far without the proper foundation.

ShopTalk 629: The Great Divide, Global Design + Web Components, and Job Titles

Chris and Dave sound off on The Great Divide in this episode and the rising value of shifting back towards fundamentals:

Dave: But I think what is maybe missing from that is there was a very big feeling of disenfranchisement from people who are good and awesome at CSS and JavaScript and HTML. But then were being… The market was shifting hard to these all-in JavaScript frameworks. And a lot of people were like, “I don’t… This is not what I signed up for.”

[…]

Dave: Yeah. I’m sure you can be like, “Eat shit. That’s how it is, kid.” But that’s also devaluing somebody’s skillset. And I think what the market is proving now is if you know JavaScript or know HTML, CSS, and regular JavaScript (non-framework JavaScript), you are once again more valuable because you understand how a line of CSS can replace 10,000 lines of JavaScript – or whatever it is.

Chris: Yeah. Maybe it’s coming back just a smidge–

Dave: A smidge.

Chris: –that kind of respecting the fundamental stuff because there’s been churn since then, since five years ago. Now it’s like these exclusively React developers we hired, how useful are they anymore? Were they a little too limited and fundamental people are knowing more? I don’t know. It’s hard to say that the job industry is back when it doesn’t quite feel that way to me.

Dave: Yeah, yeah. Yeah, who knows. I just think the value in knowing CSS and HTML, good HTML, are up more than they maybe were five years ago.

Just a Spec: HTML Finally Gets the Respect It Deserves

Jared and Ayush riffin’ on the first ever State of HTML survey, why we need it, and whether “State of…” surveys are representative of people who work with HTML.

[…] once you’ve learned about divs and H’s 1 through 6, what else is there to know? Quite a lot, as it turns out. Once again, we drafted Lea Verou to put her in-depth knowledge of the web platform to work and help us craft a survey that ended up reaching far beyond pure HTML to cover accessibility, web components, and much more.

[…]

You know, it’s perfectly fine to be an expert at HTML and CSS and know very little JavaScript. So, yeah, I think it’s important to note that as we talk about the survey, because the survey is a snapshot of just the people who know about the survey and answer the questions, right? It’s not necessarily representative of the broad swath of people around the world who have used HTML at all.

[…]

So yeah, a lot of interest in HTML. I’m talking about HTML. And yeah, in the conclusion, Lea Verou talks about we really do have this big need for more extensibility of HTML.

In a more recent episode:

I’m not surprised. I mean, when someone who’s only ever used React can see what HTML does, I think it’s usually a huge revelation to them.

[…]

It just blows their minds. And it’s kind of like you just don’t know what you’re missing out on up to a point. And there is a better world out there that a lot of folks just don’t know about.

[…]

I remember a while back seeing a post come through on social media somewhere, somebody’s saying, oh, I just tried working with HTML forms, just standard HTML forms the first time and getting it to submit stuff. And wait, it’s that easy?

Yeah, last year when I was mentoring a junior developer with the Railsworld conference website, she had come through Bootcamp and only ever done React, and I was showing her what a web component does, and she’s like, oh, man, this is so cool. Yeah, it’s the web platform.

Reckoning: Part 4 — The Way Out

Alex Russell in the last installment of an epic four-part series well worth your time to fully grasp the timeline, impact, and costs of modern JavsaScript frameworks to today’s development practices:

Never, ever hire for JavaScript framework skills. Instead, interview and hire only for fundamentals like web standards, accessibility, modern CSS, semantic HTML, and Web Components. This is doubly important if your system uses a framework.

Semi-Annual Reminder to Learn and Hire for Web Standards

Adrian Roselli:

This is a common cycle. Web developers tire of a particular technology — often considered the HTML killer when released — and come out of it calling for a focus on the native web platform. Then they decide to reinvent it yet again, but poorly.

There are many reasons companies won’t make deep HTML / CSS / ARIA / SVG knowledge core requirements. The simplest is the commoditization of the skills, partly because framework and library developers have looked down on the basics.

The anchor element

Heydon Pickering in a series dedicated to HTML elements, starting alphabetically with the good ol’ anchor <a>:

Sometimes, the <a> is referred to as a hyperlink, or simply a link. But it is not one of these and people who say it is one are technically wrong (the worst kind of wrong).

[…]

Web developers and content editors, the world over, make the mistake of not making text that describes a link actually go inside that link. This is collosally unfortunate, given it’s the main thing to get right when writing hypertext.

AI Myth: It lets me write code I can’t on my own

Chris Ferndandi:

At the risk of being old and out-of-touch: if you don’t know how to write some code, you probably shouldn’t use code that Chat GPT et al write for you.

[…]

It’s not bulletproof, but StackOverflow provides opportunities to learn and understand the code in a way that AI-generated code does not.

What Skills Should You Focus on as Junior Web Developer in 2024?

Frontend Masters:

Let’s not be old-man-shakes-fist-at-kids.gif about this, but learning the fundamentals of tech is demonstrateably useful. It’s true in basketball, it’s true for the piano, and it’s true in making websites. If you’re aiming at a long career in websites, the fundamentals are what powers it.

[…]

The point of the fundamentals is how long-lasting and transferrable the knowledge is. It will serve you well no matter what other technologies a job might have you using, or when the abstractions over them change, as they are want to do.

As long as we’re talking about learning the fundamentals…

The Basics

Oh yeah, and of course there’s this little online course I released this summer for learning HTML and CSS fundamentals that I describe like this:

The Basics is more for your clients who do not know how to update the website they paid you to make. Or the friend who’s learning but still keeps bugging you with questions about the things they’re reading. Or your mom, who still has no idea what it is you do for a living. It’s for those whom the entry points are vanishing. It’s for those who could simply sign up for a Squarespace account but want to understand the code it spits out so they have more control to make a site that uniquely reflects them.

Not all this nostalgia is reserved only for HTML and CSS, but for deploying code, too. A few recent posts riff on what it might look like to ship code with “buildless” or near “buildless” workflows.

Raw-Dogging Websites

Brad Frost:

It is extraordinarily liberating. Yes, there are some ergonomic inefficiencies, but at the end of the day it comes out in the wash. You might have to copy-and-paste some HTML, but in my experience I’d spend that much time or more debugging a broken build or dependency hell.

Going Buildless

Max Böck in a follow-up to Brad:

So, can we all ditch our build tools soon?

Probably not. I’d say for production-grade development, we’re not quite there yet. Performance tradeoffs are a big part of it, but there are lots of other small problems that you’d likely run into pretty soon once you hit a certain level of complexity.

For smaller sites or side projects though, I can imagine going the buildless route – just to see how far I can take it.

Manual ’till it hurts

Jeremy Keith in a follow-up to Max:

If you’re thinking that your next project couldn’t possibly be made without a build step, let me tell you about a phrase I first heard in the indie web community: “Manual ‘till it hurts”. It’s basically a two-step process:

  1. Start doing what you need to do by hand.
  2. When that becomes unworkable, introduce some kind of automation.

It’s remarkable how often you never reach step two.

I’m not saying premature optimisation is the root of all evil. I’m just saying it’s premature.

That’s it for this pile of links and good gosh my laptop feels lighter for it. Have you read other recent posts that tread similar ground? Share ’em in the comments.

What’s Old is New originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Quick Hit #18

Css Tricks - Tue, 09/10/2024 - 8:40am

PSA: Today’s the day that Google’s performance tools officially stops supporting the First Input Delay (FID) metric that was replaced by Interaction to Next Paint (INP).

Quick Hit #18 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Sanding UI

Css Tricks - Tue, 09/10/2024 - 3:00am

Jim hit a snag while working on a form. Placing labels next to inputs is trivial with flexbox, sure, but what happened in Jim’s case was a bit of dead-clicking between the labels and radio buttons.

The issue? Not the markup, that’s all semantic and cool. Turns out the gap he placed between the elements is non-interactive. Makes sense when you think about it, but frustrating nonetheless because it looks like a bug and feels like a bug even though there’s nothing wrong with the styles.

The solution’s easy enough: padding along the inside edge of the input extends its box dimensions, allowing the added space to remain interactive with visual spacing. Margin wouldn’t work since it’s akin to gap in that it pushes the element’s box instead of expanding it.

I’m linking up Jim’s article because it’s a perfect demonstration that CSS is capable of accomplishing the same thing in many ways. It’s easy to fall into the trap of “single-solution” thinking, but CSS doesn’t want anything to do with that. It’ll instead challenge you to adapt toward open-minded strategies, perhaps even defensive ones.

Sanding UI originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Time Travelling CSS With :target

Css Tricks - Mon, 09/09/2024 - 5:16am

Checkbox and radio button hacks are the (in)famous trick for creating games using just CSS. But it turns out that other elements based on user input can be hacked and gamified. There are very cool examples of developers getting creative with CSS games based on the :hover pseudo-class, and even other games based on the :valid pseudo-class.

What I’ve found, though, is that the :target pseudo-class seems relatively unexplored territory in this area of CSS hacking. It’s an underrated powerful CSS feature when you think about it: :target allows us to style anything based on the selected jump link, so we have a primitive version of client-side routing built into the browser! Let’s go mad scientist with it and see where that takes us.

Unbeatable AI in CSS

Did I type those words together? Are we going to hack CSS so hard that we hit the singularity? Try to beat the stylesheet below at Tic Tac Toe and decide for yourself.

CodePen Embed Fallback

The stylesheet will sometimes allow the game to end in a draw, so you at least have a smidge of hope.

No need to worry! CSS hasn’t gone Skynet on us yet. Like any CSS hack, the rule of thumb to determine whether a game is possible to implement with CSS is the number of possible game states. I learned that when I was able to create a 4×Sudoku solver but found a 9×9 version pretty darn near impossible. That’s because CSS hacks come down to hiding and showing game states based on selectors that respond to user input.

Tic Tac Toe has 5,478 legal states reachable if X moves first and there’s a famous algorithm that can calculate the optimal move for any legal state. It stands to reason, then, that we can hack together the Tic Tac Toe game completely in CSS.

OK, but how?

In a way, we are not hacking CSS at all, but rather using CSS as the Lord Almighty intended: to hide, show, and animate stuff. The “intelligence” is how the HTML is generated. It’s like a “choose your own adventure” book of every possible state in the Tic Tac Toe multiverse with the empty squares linked to the optimal next move for the computer.

We generate this using a mutant version of the minimax algorithm implemented in Ruby. And did you know that since CodePen supports HAML (which supports Ruby blocks), we can use it secretly as a Ruby playground? Now you do.

Each state our HAML generates looks like this in HTML:

<div class="b" id="--OOX----"> <svg class="o s"> <circle></circle> </svg> <a class="s" href="#OXOOX----"> <div></div> </a> <svg class="o s"> <circle class="c"></circle> </svg> <svg class="o s"> <circle class="c"></circle> </svg> <div class="x"></div> <a class="s" href="#O-OOXX---"> <div></div> </a> <a class="s" href="#O-OOX-X--"> <div></div> </a> <a class="s" href="#O-OOX--X-"> <div></div> </a> <a class="s" href="#O-OOX---X"> <div></div> </a> </div>

With a sprinkling of surprisingly straightforward CSS, we will display only the currently selected game state using :target selectors. We’ll also add a .c class to historical computer moves — that way, we only trigger the handwriting animation for the computer’s latest move. This gives the illusion that we are only playing on a single gameboard when we are, in reality, jumping between different sections of the document.

/* Game's parent container */ .b, body:has(:target) #--------- { /* Game states */ .s { display: none; } } /* Game pieces with :target, elements with href */ :target, #--------- { width: 300px; height: 300px; / left: calc(50vw - 150px); top: calc(50vh - 150px); background-image: url(/path/to/animated/grid.gif); background-repeat: no-repeat; background-size: 100% auto; /* Display that game state and bring it to the forefront */ .s { z-index: 1; display: inline-block; } /* The player's move */ .x { z-index: 1; display: inline-block; background-image: url("data:image/svg+xml [...]"); /** shortened for brevity **/ height: 100px; width: 100px; } /* The browser's move */ circle { animation-fill-mode: forwards; animation-name: draw; animation-duration: 1s; /* Only animate the browser's latest turn */ &.c { animation-play-state: paused; animation-delay: -1s; } } }

When a jump link is selected by clicking an empty square, the :target pseudo-class displays the updated game state(.s), styled so that the computer’s precalculated response makes an animated entrance (.c).

Note the special case when we start the game: We need to display the initial empty grid before the user selects any jump link. There is nothing to style with :target at the start, so we hide the initial state — with the:body:has(:target) #--------- selector — once a jump link is selected. Similarly, if you create your experiments using :target you’ll want to present an initial view before the user begins interacting with your page. 

Wrapping up

I won’t go into “why” we’d want to implement this in CSS instead of what might be an “easier” path with JavaScript. It’s simply fun and educational to push the boundaries of CSS. We could, for example, pull this off with the classic checkbox hack — someone did, in fact.

Is there anything interesting about using :target instead? I think so because:

  • We can save games in CSS! Bookmark the URL and come back to it anytime in the state you left it.
  • There’s a potential to use the browser’s Back and Forward buttons as game controls. It’s possible to undo a move by going Back in time or replay a move by navigating Forward. Imagine combining :target with the checkbox hack to create games with a time-travel mechanic in the tradition of Braid.
  • Share your game states. There’s the potential of Wordle-like bragging rights. If you manage to pull off a win or a draw against the unbeatable CSS Tic Tac Toe algorithm, you could show your achievement off to the world by sharing the URL.
  • It’s completely semantic HTML. The checkbox hack requires you to hide checkboxes or radio buttons, so it will always be a bit of a hack and painful horse-trading when it comes to accessibility. This approach arguably isn’t a hack since all we are doing is using jump links and divs and their styling. This may even make it — dare I say —“easier” to provide a more accessible experience. That’s not to say this is accessible right out of the box, though.

Time Travelling CSS With :target originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Sticky Headers And Full-Height Elements: A Tricky Combination

Css Tricks - Mon, 09/09/2024 - 4:09am

Quite a fun article I worked on with Philip Braunen. Do you know that little bit of elasticity you get when scrolling beyond the viewport when browsing the web on a mobile device? iPhone calls it a “rubber-banding” effect. And you know it’s cool because Apple has previously fought to hold a copyright on it.

Anyway, Philip wrote into Smashing Magazine with a clever approach to mimic rubber-banding in CSS — not only for non-mobile UI but also applied to any sort of container you like.

But what about sticky headers and footers? If those have to be pinned to the container’s block edges, then how in heck do we include them in the rubber banding? Phillip’s trick is an extra div before the header, though we can get more concise markup using pseudos instead.

Sticky Headers And Full-Height Elements: A Tricky Combination originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Quick Hit #17

Css Tricks - Mon, 09/09/2024 - 3:53am

“Wrapping the <label> around the <input> is fine, and is sufficient for conformance on its own, however adding explicit association with for and id is still necessary in practice.” —James Edwards

Quick Hit #17 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Quick Hit #16

Css Tricks - Thu, 09/05/2024 - 6:04am

“Never, ever hire for JavaScript framework skills. Instead, interview and hire only for fundamentals like web standards, accessibility, modern CSS, semantic HTML, and Web Components.” — Alex Russell

Quick Hit #16 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Quick Hit #15

Css Tricks - Thu, 09/05/2024 - 6:02am

Almost missed that the WP Twenty Twenty-Five theme was approved a couple weeks ago.

Quick Hit #15 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Quick Hit #14

Css Tricks - Tue, 09/03/2024 - 9:08am

Inclusive Design 24 is in 8 short days — and it’s FREE, no sign-up required!

Quick Hit #14 originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Paragraphs

Css Tricks - Fri, 08/30/2024 - 4:23am

I sure do love little reminders about HTML semantics, particularly semantics that are tougher to commit to memory. Scott has a great one, beginning with this markup:

<p>I am a paragraph.</p> <span>I am also a paragraph.</span> <div>You might hate it, but I'm a paragraph too.</div> <ul> <li>Even I am a paragraph.</li> <li>Though I'm a list item as well.</li> </ul> <p>I might trick you</p> <address>Guess who? A paragraph!</address>

You may look at that markup and say “Hey! You can’t fool me, only the <p> elements are “real” paragraphs!

You might even call out such elements as divs or spans being used as “paragraphs” a WCAG failure.

But, if you’re thinking those sorts of things, then maybe you’re not aware that those are actually all “paragraphs”.

It’s easy to forget this since many of those non-paragraph elements are not allowed in between paragraph tags and it usually gets all sorted out anyway when HTML is parsed.

The accessibility bits are what I always come to Scott’s writing for:

Those examples I provided at the start of this post? macOS VoiceOver, NVDA and JAWS treat them all as paragraphs ([asterisks] for NVDA, read on…). […] The point being that screen readers are in step with HTML, and understand that “paragraphs” are more than just the p element.

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

Shipping Tumblr and WordPress

Css Tricks - Thu, 08/29/2024 - 5:05am

Didya see that Tumblr is getting a WordPress makeover? And it’s not a trivial move:

This won’t be easy. Tumblr hosts over half a billion blogs. We’re talking about one of the largest technical migrations in internet history. Some people think it’s impossible. But we say, “challenge accepted.”

Half a billion blogs. Considering that WordPress already powers somewhere around 40% of all websites (which is much, much higher than 500m) this’ll certainly push that figure even further.

I’m sure there’s at least one suspicious nose out there catching whiffs of marketing smoke though I’m amicable to the possibility that this is a genuine move to enhance a beloved platform that’s largely seen as a past relic of the Flickr era. I loved Tumblr back then. It really embraced the whole idea that a blog can help facilitate better writing with a variety of post formats. (Post formats, fwiw, are something I always wished would be a WordPress first-class citizen but they never made it out of being an opt-in theme feature). Tumblr was the first time I was able to see blogging as more than a linear chain of content organized in reverse chronological order. Blog posts are more about what you write and how you write it than they are when they’re written.

Anyway, I know jobs are a scarce commodity in tech these days and Auttomatic is looking for folks to help with the migration.

I was about to say this “could” be a neat opportunity, but nay, it’s a super interesting and exciting opportunity, one where your work is touching two of the most influential blogging platforms on the planet. I remember interviewing Alex Hollender and Jon Robson after they shipped a design update to Wikipedia and thinking how much fun and learning would come out of a project like that. This has that same vibe to me. Buuuut, make no illusions about it: it’ll be tough.

Shipping Tumblr and WordPress originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Introducing <skelly-wc>

Css Tricks - Wed, 08/28/2024 - 4:05am

I created a little library at work to make those “skeleton screens” that I’m not sure anyone likes. […] We named it skellyCSS because… skeletons and CSS, I guess. We still aren’t even really using it very much, but it was fun to do and it was the first node package I made myself (for the most part).

Regardless of whether or not anyone “likes” skeleton screens, they do come up and have their use cases. And they’re probably not something you want to rebuild time and again. Great use for a web component, I’d say! Maybe Ryan can get Uncle Dave to add it to his Awesome Standalones list. &#x1f609;

The other reason I’m sharing this link is that Ryan draws attention to the Web Components De-Mystified course that Scott Jehl recently published, something worth checking out of course, but that I needed a reminder for myself.

Introducing <skelly-wc> originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

Syndicate content
©2003 - Present Akamai Design & Development.